Matt Goodrich
Matt Goodrich

Reputation: 5095

Angular UI-Router Multiple Named Views

Desired Behavior

I'm using AngularJS and the Angular UI-Router.

  1. I want to allow two child states to share a parent state.
  2. I want the child states to fill a ui-view in the parent state's view with their own view.
  3. I want one of the two child states to have three ui-view's in their view, each filled with views.

Attempt at a diagram:

Parent: <ui-view>
        filled by
          Child:  <ui-view> <ui-view> <ui-view>
                    filled    filled   filled

Specific Details for My Situation

I have a state called category-details. Inside the view for this abstract state I have an unnamed ui-view. In one of the two child states (category-details.selected) I want to use multiple named views.

Current WORKING Strategy

Here is the abstract state. Very basic, but included for your reference.

.state('category-details', {
    abstract: true,
    data: {
        pageTitle: 'Category Details'
    },
    templateUrl: "views/category-details.html",
})

In the category-details.selected state (the state which will have multiple named views), I set the unnamed ui-view of category-details.html to category-details-selected.html:

.state('category-details.selected', {
    views: {
        '': {
            templateUrl: 'views/category-details-selected.html',
            controller: 'CategoryDetailsSelectedCtrl'
        }
    }
})

Inside of the category-details-selected.html view I have three named ui-views:

<div ui-view="firstNamedView"></div>
<div ui-view="secondNamedView"></div>
<div ui-view="thirdNamedView"></div>

Finally, I define a state for setting these three ui-view's to meet the third part of my desired behavior:

.state('category-details.selected.aspect', {
    url:"/category-details/:selectedCategory",
    views: {
        'firstNamedView': {
            templateUrl: 'views/first-named-view.html',
            controller: 'FirstNamedViewCtrl'
        },
        'secondNamedView': {
            templateUrl: 'views/second-named-view.html',
            controller: 'SecondNamedViewCtrl'
        },
        'thirdNamedView': {
            templateUrl: 'views/third-named-view.html',
            controller: 'ThirdNamedViewCtrl'
        }
    }
});

Why My Solution is Awkward and Suboptimal

Adding the category-details.selected.aspect state to set constant elements (the three ui-view's) of the category-details-selected view is unnecessary. It forces creating an extra state every time I want multiple named views.

What I've Tried

I believe I should be able to move the url and views of the category-details.selected.aspect state into the views component of its parent state (category-details.selected). This would look like:

.state('category-details.selected', {
    url:"/category-details/:selectedCategory",
    views: {
        '': {
            templateUrl: 'views/category-details-selected.html',
            controller: 'CategoryDetailsSelectedCtrl'
        },
        'firstNamedView': {
            templateUrl: 'views/first-named-view.html',
            controller: 'FirstNamedViewCtrl'
        },
        'secondNamedView': {
            templateUrl: 'views/second-named-view.html',
            controller: 'SecondNamedViewCtrl'
        },
        'thirdNamedView': {
            templateUrl: 'views/third-named-view.html',
            controller: 'ThirdNamedViewCtrl'
        }
    }
})

This resulted in the unnamed ui-view being set correctly, but the three named ui-view's were not filled.

Since selecting the three named ui-view's was the problem, I then attempted to select them with absolute selectors described here instead. This did not fix the problem. I tried:

firstNamedView
firstNamedView@
[email protected]
(others of course)

Closing Remarks

Is what I'm imagining possible, is another way better, or is my current method the best? It boils down to assigning the child ui-views of a parent ui-view being set at the same time. I thought the last sentence was too confusing alone, so I included the entire example.

Please let me know if I can provide any more clarification such as versions. Thank you.

Upvotes: 3

Views: 561

Answers (1)

Sudarshan_SMD
Sudarshan_SMD

Reputation: 2587

Abstract states need their own <ui-view/> for their children to plug into.

Parent state category-details is abstract state. Child state will need some reference ui-view to plug that state into. In your I believe the view /category-details.html does not any ui-view (as you have mentioned that category-details-selected.html contains the ui-view).

Try this:

.state('category-details', {
  abstract: true,
  data: {
    pageTitle: 'Category Details'
  },
  templateUrl: "views/category-details-selected.html",
})

.state('category-details.selected', {
  url:"/category-details/:selectedCategory",
  views: {       
    'firstNamedView': {
        templateUrl: 'views/first-named-view.html',
        controller: 'FirstNamedViewCtrl'
    },
    'secondNamedView': {
        templateUrl: 'views/second-named-view.html',
        controller: 'SecondNamedViewCtrl'
    },
    'thirdNamedView': {
        templateUrl: 'views/third-named-view.html',
        controller: 'ThirdNamedViewCtrl'
    }
  }
})

Here, we are giving abstract view a template, which has ui-view in it, for child to populate.

Have a look at documentation of ui-router: Abstract State for more information.


EDIT: I had assumed that views/category-details.html does not contain any ui-view. However, it was then pointed out that, views/views/category-details.html does have ui-view

This is what works for me:

category-details.html:

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

category-details-selected.html:

<div ui-view="firstNamedView"></div>
<div ui-view="secondNamedView"></div>
<div ui-view="thirdNamedView"></div>

router:

    .state('category-details', {
        abstract: true,
        data: {
            pageTitle: 'Category Details'
        },
        templateUrl: "../app/atest/category-details.html",
    })


    .state('category-details.selected', {
        url: "/atest",
        views: {
            '': {
                templateUrl: "../app/atest/category-details-selected.html",
                //   controller: 'approvalsCtrl as vm',
            },
            '[email protected]': {
                templateUrl: '../app/atest/first.html',
                //    controller: 'approvalsCtrl as vm',
            },
            '[email protected]': {
                templateUrl: '../app/atest/second.html',
                //   controller: 'approvalsCtrl as vm',
            },
            '[email protected]': {
                templateUrl: '../app/atest/third.html',
                //   controller: 'approvalsCtrl as vm',
            }
        }
    })

I could see that you have mentioned you tried out using [email protected], but it didn't worked for you. The above example is working for me. Check if you category-details.html and category-details-selected.html view contain proper ui-view.

Upvotes: 1

Related Questions