Angular UI-Router Multiple Named Views
Desired behavior
I am using AngularJS and Angular UI-Router.
- I want to allow two child states to share the parent state.
- I want the child states to populate
ui-view
in the parent state view with their own view. - I want one of the two child states to have three
ui-view
in its view, each populated with views.
Attempted diagram:
Parent: <ui-view>
filled by
Child: <ui-view> <ui-view> <ui-view>
filled filled filled
Specific details of my situation
I have a state named category-details
. Inside the view for this abstract state, I have an unnamed one ui-view
. In one of two child states ( category-details.selected
), I want to use multiple named views .
Current work strategy
Here is an abstract state. Very basic, but included for your reference.
.state('category-details', {
abstract: true,
data: {
pageTitle: 'Category Details'
},
templateUrl: "views/category-details.html",
})
In state category-details.selected
(state that will have multiple named views), I set unnamed ui-view
from category-details.html
in category-details-selected.html
:
.state('category-details.selected', {
views: {
'': {
templateUrl: 'views/category-details-selected.html',
controller: 'CategoryDetailsSelectedCtrl'
}
}
})
Inside the view category-details-selected.html
, I have three names ui-views
:
<div ui-view="firstNamedView"></div>
<div ui-view="secondNamedView"></div>
<div ui-view="thirdNamedView"></div>
Finally, I define a state to set these three ui-view
to satisfy 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 is my solution inconvenient and suboptimal
Adding state category-details.selected.aspect
to set persistent items (three ui-view
's) in the view is category-details-selected
not required. This forces additional state to be created every time I need multiple named views.
What i tried
I believe I need to move the url and state views category-details.selected.aspect
to the component of views
my parent state ( category-details.selected
). It will look like this:
.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 three names ui-view
were not filled in.
Since choosing the three named ui-view
was a problem, I then tried to select them using the ones absolute selectors
described here . This didn't fix the problem. I tried:
firstNamedView
firstNamedView@
firstNamedView@category-details.selected
(others of course)
Concluding remarks
Is what I imagine possible, is another way better, or is my current method better? It boils down to assigning a child to a ui-view
parent ui-view
set at the same time. I thought the last sentence was too confusing on its own, so I included the whole example.
Please let me know if I can provide more clarifications such as versions. Thank.
source to share
Abstract states need their own
<ui-view/>
for their children to connect.
The state of the parent state category-details
is a state abstract
. The child state requires some reference u-view to connect that state. In yours, I believe the view /category-details.html
does not have any ui-view (as you mentioned, what category-details-selected.html
ui-view contains).
Try the following:
.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 give an abstract view of the template, which has a ui-view, to fill the child.
Check out the documentation for ui-router: Abstract State for more information.
EDIT : I assumed it views/category-details.html
doesn't contain any ui-view. However, it was then pointed out that it views/views/category-details.html
has a 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',
},
'firstNamedView@category-details.selected': {
templateUrl: '../app/atest/first.html',
// controller: 'approvalsCtrl as vm',
},
'secondNamedView@category-details.selected': {
templateUrl: '../app/atest/second.html',
// controller: 'approvalsCtrl as vm',
},
'thirdNamedView@category-details.selected': {
templateUrl: '../app/atest/third.html',
// controller: 'approvalsCtrl as vm',
}
}
})
I could see you mentioned that you tried using it firstNamedView@category-details.selected
, but it didn't work for you. The above example works for me. Check if you have category-details.html
and category-details-selected.html
view2 → 2>.
source to share