Search code examples
javascriptangularjsarchitecturesingle-page-applicationng-view

How to bootstrap component based angular 1 application?


Using angular 1.6, here are the components I need to have:

+-------------------+
|side|              | 
|bar |              |
|... |     view     |
|... |              |
|... |              |
+-------------------+
  • side bar: placed on left. using ng-repeat and updates dynamically.
  • view: rest of the app. template is static but contents changes when click on side bar.

when the user clicks on each list <li> of side bar, it updates the view. only view content/model will change. not the html template.

Important: I just don't want to write a code in <body>. Would like to have sidebar in one html file and view in another associated with their controllers and render the whole app through ng-view in <body>.

The side bar updates dynamically so that I cannot specify state in config() for each.

any other standard architecture is appreciated.


Solution

  • As mentioned in the comments, there are multiple architecture and framework choices that can be made to implement the type of templating you're looking for. I'll provide a basic example based on something I've used in the past with angular, using ui-router and child/nested views.

    Lets say you have an index.html like:

    <body>
        <div ui-view="header" class="header"></div>
        <div ui-view="main" class="main"></div>
        <div ui-view="footer" class="footer"></div>
    </body>
    

    The index page just has the layout for the most high level view, namely header, content and footer. If you have no need for header and footer, you can just ignore/remove it. Now the layout your are looking for, with a side bar on the left and the content on the right, will be placed within the main view. To do this lets declare another page which will define this structure, call it landing.html (use bootstrap for simplicity):

    <div class="container-fluid">
      <div class="row landingContainer">
        <div class="col-md-2 col-sm-4 col-xs-3 sidebarSection">
          <div class="row item" ng-click="landing.changePage('content1')">
            <span>Show Content 1</span>
          </div>
          <div class="row item" ng-click="landing.changePage('content2')">
            <span>Show Content 2</span>
          </div>
          <div class="row item" ng-click="landing.changePage('content3')">
            <span>Show Content 3</span>
          </div>
        </div> 
        <div class="col-md-10 col-sm-8 col-xs-9 contentSection">
          <div ui-view="content"></div>
        </div> 
      </div>
    </div>
    

    You can think of this page as the root of your layout. The page is split into a left and right section using bootstrap columns. The left side contains the listing of all your content views. You can use li, i just prefer divs. The right side will be where the dynamic part of the page is, where the content will change based on the item selected in the side bar. Each component view is a child of the landing page, it inherits all the features of the parent and then adds its own content into the ui-view, similar to how landing.html added its content into the main ui-view. Now lets take a look at the ui-router config that makes all this work.

    function routerConfig($stateProvider, $urlRouterProvider) {
        $stateProvider
          .state('landing', {
            url: '/landing',
            views: {
             'header': {
                templateUrl: 'app/components/header/headerPrivate.html',
                controller: 'HeaderController',
                controllerAs: 'header'
              },
              'main': {
                templateUrl: 'app/landing/landing.html',
                controller: 'LandingController',
                controllerAs: 'dashboard'
              },
              'footer': {
                templateUrl: 'app/components/footer/footer.html',
                controller: 'FooterController',
                controllerAs: 'footer'
              }
            }
          })
          .state('landing.content1', {
            url: '/content1',
            views: {
             'content': {
                templateUrl: 'app/content1/content1.html',
                controller: 'Content1Controller',
                controllerAs: 'content1'
              }
            }
          })
          .state('landing.content2', {
            url: '/content2',
            views: {
             'content': {
                templateUrl: 'app/content2/content2.html',
                controller: 'Content2Controller',
                controllerAs: 'content2'
              }
            }
          })
          .state('landing.content3', {
            url: '/content3',
            views: {
             'content': {
                templateUrl: 'app/content3/content3.html',
                controller: 'Content3Controller',
                controllerAs: 'content3'
              }
            }
          })
        $urlRouterProvider.otherwise('/');
    }
    

    Here you'll notice that the landing page route defines the configuration for the 3 main views, header, main and footer. The url path will be /landing. Then content1, content2 and content3 are defined as children by nesting them within landing using the dot notation: landing.content1. The url paths for each child will then resolve to /landing/content1, /landing/content2, landing/content3. So now anytime you navigate to those locations only the content for that specific child will be nested within the landing pages "content" ui-view and the remaining layout of the page stays the same.

    For the sake of completion, this is how the landing controller might look:

    function LandingController($state) {
        var vm = this;
    
        vm.changePage = function(page){
            $state.transitionTo('landing.'+page, null, null);
        }    
    }