1

I have a user layout file that is the template for any user pages:

<div class="user-wrapper">
    <div ui-view="menu"></div>
    <div ui-view="content"></div>
</div>

Depending on the state I want the menu to be different. Such as:

    .state('user', {
        url: '/user',
        templateUrl: 'partials/user.html',
        controller: 'userController',
    })

    .state('user.one', {
        url: '/one',
        controller: 'oneController',
        views: {
            "menu": { templateUrl: "partials/client-menu.html" },
            "content": { templateUrl: "partials/one.html" }
        },
    });

    .state('user.two', {
        url: '/two',
        controller: 'twoController',
        views: {
            "menu": { templateUrl: "partials/client-menu.html" },
            "content": { templateUrl: "partials/two.html" }
        },
    });

    .state('user.three', {
        url: '/three',
        controller: 'threeController',
        views: {
            "menu": { templateUrl: "partials/admin-menu.html" },
            "content": { templateUrl: "partials/three.html" }
        },
    });

Now you can see "one" and "two" both use the same menu but "three" uses a different menu. This all works fine but is there a way to avoid duplicating the menu on "one" and "two".

Such as making a "user.client" state that uses the "user-menu.html" then "one" would be "user.client.one" instead and only have to specify the content.

I think the main problem is the

<div ui-view="content"></div>

is on the grandfather of the "user.client.one" so how can it specify the content?

2 Answers 2

1

I would say, that the trick is to move the "menu" view definition into parent state "user"

.state('user', {
    url: '/user',
    views: {
      "" : {
        templateUrl: 'partials/user.html',
        controller: 'userController',
      },
      "menu@user": { templateUrl: "partials/client-menu.html" },
     },
     ...

So, what happened? any child state of the "user" will already have the content of the "menu" filled, with the default templateUrl: "partials/client-menu.html"

Any other child, can override that...

.state('user.one', {
    url: '/one',
    controller: 'oneController',
    views: {
        // "menu": already set by parent
        "content": { templateUrl: "partials/one.html" }
     ....

.state('user.two', {
    url: '/two',
    views: {
        // "menu": set in parent
        "content": { templateUrl: "partials/two.html" }
        ...

.state('user.three', {
    url: '/three',
    controller: 'threeController',
    views: {
        // here we override that
        "menu": { templateUrl: "partials/admin-menu.html" },
        "content": { templateUrl: "partials/three.html" }
    ...

Maybe, check this Q & A for some more ideas about multi view nesting:

Sign up to request clarification or add additional context in comments.

5 Comments

Hm ic so just make the client-menu default and if its a admin state override it.
YES Exactly... that's how I do handle this for state: entity / list / detail. Before the detail is selected... its area can contain some default content... Check the link in the answer... for some other point of view about the layout... But, my answer should be clear, I'd say. Hope it helps. Enjoy UI-Router anyhow
Thanks. I think a found another way using the absolute views if you see above. It seems to work so far.
Yes, it is variation of my solution. Glad if that works for you
Good luck with UI-Router ;)
0

I think a found a solution user the @ for absolute views:

.state('user', {
    url: '/user',
    templateUrl: 'partials/user.html',
    controller: 'userController',
})

.state('user.client', {
    url: '/client',
    views: {
        "menu": { templateUrl: "partials/client-menu.html" }
    },
})

.state('user.admin', {
    url: '/admin',
    views: {
        "menu": { templateUrl: "partials/admin-menu.html" }
    },
})

.state('user.client.one', {
    url: '/one',
    controller: 'oneController',
    views: {
        "content@user": { templateUrl: "partials/one.html" }
    },
});

.state('user.client.two', {
    url: '/two',
    controller: 'twoController',
    views: {
        "content@user": { templateUrl: "partials/two.html" }
    },
});

.state('user.admin.three', {
    url: '/three',
    controller: 'threeController',
    views: {
        "content@user": { templateUrl: "partials/three.html" }
    },
});

It feels abit cleaner but I'm not sure if its the right approach still.

Comments