21

I have the following layout:

enter image description here

Sidebar and Headerbar will always be present though their content is context-specific.

I think there are two options here: nested states (sidenav > Headerbar > Content) or with views (if I understand that correctly). I'm still struggling to get my head wrapped around ui-router regardless of how many videos and articles I've read.

Clicking on Sidenav would load a state (or view) into Content and Headerbar would adjust its content based on whatever is loaded into Content.

My sense is that nested states seem like the simplest direct approach, particularly when thinking about inheritance.

Looking at it from another point of view, these seem like they could be siblings (although inheritance issues probably make me wrong). My inkling is that views would allow me more flexibility in the future with sub-items and such.

And of course ng-include and directives could play into this.

Being new to ui-router could someone slap me in the right direction? Where I'm stuck is loading the home view. I want my users to see their dashboard in the Content section once they log in. And then, how do I load new elements into Content as the user navigates from the Sidebar?

Lee
  • 1,389
  • 3
  • 18
  • 28

2 Answers2

35

One way how to design scenario with 1) side bar, 2) action section and 3) main area could be like in this working example

Firstly the root state. Here is root state named 'index'. It is abstract and could do some resolve for us. It does not effect child state naming and does not extend the url (because is undefined)

$stateProvider
    .state('index', {
        abstract: true,
        //url: '/',
        views: {
          '@' : {
            templateUrl: 'layout.html',
            controller: 'IndexCtrl'
          },
          'top@index' : { templateUrl: 'tpl.top.html',},
          'left@index' : { templateUrl: 'tpl.left.html',},
          'main@index' : { templateUrl: 'tpl.main.html',},
        },
      })

The first real state is list, and it inherits from parent but with an attribute parent: 'index', so the parent name is not effecting the state name.

Advantage is, that it could inherit lot of resolved stuff. Also, the root state could be loaded once, for all other parent states

    .state('list', {
        parent: 'index',
        url: '/list',
        templateUrl: 'list.html',
        controller: 'ListCtrl'
      })

This is the real power of UI-Router, because now we can see that child is injecting stuff into two places - 1) action section and 2) main area

    .state('list.detail', {
        url: '/:id',
        views: {
          'detail@index' : {
            templateUrl: 'detail.html',
            controller: 'DetailCtrl'
          },
          'actions@index' : {
            templateUrl: 'actions.html',
            controller: 'ActionCtrl'
          },
        },
      })

This way, we can use named views and multi views in real world scenario. Please, never forget how the scope definition goes:

Scope Inheritance by View Hierarchy Only

Keep in mind that scope properties only inherit down the state chain if the views of your states are nested. Inheritance of scope properties has nothing to do with the nesting of your states and everything to do with the nesting of your views (templates).

It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states.

Check that all in action here

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • This has helped me very much thank you. A few final comments: 1) The Plunker is no longer working but I got it working on my local. Any ideas why it's not working now? 2) I assume the ',' after the template names (line 17-19 in app.js) is a typo correct? 3) I can't figure out how list.html is being loaded into tpl.left.html. Can you clarify please? – Lee Mar 05 '15 at 22:25
  • 1
    Actually I understand #3 now. Thanks again. – Lee Mar 06 '15 at 04:15
  • Radim, can you please post the URLs that should be visited for each state? It's not clear to me from this example. – Saqib Ali Nov 18 '16 at 08:42
  • @SaqibAli Check the example in that answer. IN that plunker.. click on the right upper corner icon... "launch the preview in a separate window" .. you will see any url once state is changed – Radim Köhler Nov 18 '16 at 09:13
4

I just would like to share my experience. There is

The snippet of the state def:

$stateProvider
    .state('index', {
        url: '/',
        views: {
          '@' : {
            templateUrl: 'layout.html',
            controller: 'IndexCtrl'
          },
          'top@index' : { templateUrl: 'tpl.top.html',},
          'left@index' : { templateUrl: 'tpl.left.html',},
          'main@index' : { templateUrl: 'tpl.main.html',},
        },
      })
    .state('index.list', {
        url: '/list',
        templateUrl: 'list.html',
        controller: 'ListCtrl'
      })
    .state('index.list.detail', {
        url: '/:id',
        views: {
          'detail@index' : {
            templateUrl: 'detail.html',
            controller: 'DetailCtrl'
          },
        }

In a nutshell, I do use the nesting approach.

It is similar to the "core example" available here http://angular-ui.github.io/ui-router/sample/#/. It is hierarchical (entity list / detail)

And what's more, I use the hidden supper root state:

which is handling security related stuff - once, and shared among all child states:

$stateProvider
  .state('root', {
    abstract: true,
    template: '<div ui-view></div>',
    resolve: {objectX : function() { return {x : 'x', y : 'y'};}},
    controller: 'rootController',
  })
  .state('home', {
    parent: "root",
    url: '/home',
    templateUrl: 'tpl.example.html',
  })
  .state('search', {
    parent: "root",
    url: '/search',
    templateUrl: 'tpl.example.html',
  })

Hope it does enlighten this a bit, because the power of UI-Router I see in multiviews, view nesting, scope inheritance and the logical state machine behind

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Thanks, Radim. Such a thoughtful and clear answer. I am going to take the entire day or as many days as it takes to get this clear in my head. I still have questions that hopefully after working on this I'll have figured out. For instance, in the first code snippet, I assume that layout.html has 3 views (top, left, main). So I assume that when I go to index.list it will replace layout.html whereas in my use case I would only want to replace the main view and update $scope items in top and left. Am I understanding correctly? – Lee Mar 03 '15 at 05:01
  • I decided to create brand new plunker and fully working example. I used another answer to describe this approach. Hope it will help to see how powerful UI-Router is... good luck – Radim Köhler Mar 03 '15 at 07:18