javascriptangularjsangular-ui-routerangularjs-bootstrap

ui-router multiple named nested views


I have a nested view like this

<div ui-view="master" id="ng-view">
  <div class="container-fluid height-full">
      <div ui-view="globalNavigationPanel" class="row"></div> 
     <div ui-view="detail" id="detailContent" class="row"></div>
  </div>
</div>

this is my resolver

function resolveShell()
{
   return {
            'views': {
                'master': {
                    templateUrl: 'core/views/shell.html',
                    controller: 'core/controllers/shellcontroller.js',
                    controllerAs: 'vm',
                },
                'globalNavigationPanel': {
                    templateUrl: 'core/views/globalNavigationPanel',
                    controller: 'core/controllers/globalNavigationPanelController.js',
                    controllerAs: 'gpvm',
                }
            },
            'resolve': {
                load: [
                    '$q', '$rootScope', ($q, $rootScope) => {
                        var dependencies = [
                            'core/controllers/shellcontroller.js',
                            'core/controllers/globalNavigationPanelController.js'
                        ];
                        return resolveDependencies($q, $rootScope, dependencies);
                    }
                ]
            }
        };
  }

when I set the state i could see all the files downloaded and shellcontroller.js getting called, but not the globalNavigationPanelController.

Also I cannot see the globalNavigationPanel view updating.

Can I basically set state and resolve multiple named nested views?


Solution

  • This is because we use multi views, which are nested in one state. That means, that we have to use absolute naming.

    This way, we can instruct UI-Router, that the second view, should be placed into current state other view. It is not obvious what is the name of your state, but let's imagine that it would be 'shell'

    'views': {
        'master': {
            ...
        },
        'globalNavigationPanel@shell': {
            ....
        }
    },
    

    Now, the template of our 'shell' state should be (I mean the templateUrl: 'core/views/shell.html',)

    <div class="container-fluid height-full">
       <div ui-view="globalNavigationPanel" class="row"></div> 
       <div ui-view="detail" id="detailContent" class="row"></div>
    </div>
    

    And the index.html should contain just:

    <div ui-view="master" id="ng-view">
    </div>
    

    Because the master will contain a placeholder for the 'globalNavigationPanel'

    Also check the doc

    View Names - Relative vs. Absolute Names

    Behind the scenes, every view gets assigned an absolute name that follows a scheme of viewname@statename, where viewname is the name used in the view directive and state name is the state's absolute name, e.g. contact.item. You can also choose to write your view names in the absolute syntax.

    For example, the previous example could also be written as:

    .state('report',{
        views: {
          'filters@': { },
          'tabledata@': { },
          'graph@': { }
        }
    })
    

    Notice that the view names are now specified as absolute names, as opposed to the relative name. It is targeting the 'filters', 'tabledata', and 'graph' views located in the root unnamed template. Since it's unnamed, there is nothing following the '@'. The root unnamed template is your index.html.

    EXTEND - There is a working example

    This is the state definition:

      .state('shell', {
        url: '/shell',
        views: {
          'master' : {
            templateUrl: 'core/views/shell.html',
                controller: 'shellcontroller',
                controllerAs: 'vm',
          },
          'globalNavigationPanel@shell': {
            templateUrl: 'core/views/globalNavigationPanel.html',
                controller: 'globalNavigationPanelController',
                controllerAs: 'gpvm',
          }
        }
      })
    

    These are the views

    The templateUrl: 'core/views/shell.html',

    <h2>shell</h2>
    
    <p>{{text}}</p>
    
    <hr />
    
    <div class="container-fluid height-full">
       <div ui-view="globalNavigationPanel" class="row"></div> 
       <div ui-view="detail" id="detailContent" class="row"></div>
    </div>
    

    The templateUrl: 'core/views/globalNavigationPanel.html',

    <h3>globalNavigationPanel</h3>
    
    <p>{{text}}</p>
    

    while index contains just:

    <div ui-view="master" id="ng-view"></div>
    

    Check it in action here