3

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.

1 Answer 1

1
+50

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.

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

3 Comments

Thank you for your reply @Sudarshan_SMD. I currently include a ui-view in the category-details view. This is the view set based on the category-details.selected or category-details.unselected states. The category-details.selected then holds the view with three ui-views for the child states. Your solution removes the highest parent and goes from my parent - child - multiple states design to child - multiple states. Requirement #1 of my question is not met. Does this make sense?
@MattGoodrich I got your point. Have edited the answer with category-details.html at parent. The solution that I have provided, works for me.
I thought I had tried the absolute selector [email protected] and it did not show any of the child views. I didn't include it in the SO post to prevent confusion, but I had a very top-level abstract state called index. I just tried [email protected] and it worked. Thanks for working through this with me and sorry about my silly mistake.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.