I have a articledetail state, which I navigate to:
$state.go('articledetail', { 'article': article.itemNumber });
In articleDetail.html, I'd like to load the subviews, all at the same time:
<div class="tab-content col-xs-7">
<div ui-view="tab1"></div>
<div ui-view="tab2"></div>
<div ui-view="tab3"></div>
<div ui-view="tab4"></div>
<br />
</div>
Below is my state config. I have already tried using both # and without #, but none of my views (not even the main one) gets loaded and I'm not getting any errors.
$stateProvider.state('articledetail', {
url: '/articledetail/:article',
templateUrl: '/articledetail/articleDetail.html',
controller: 'articleDetailController',
controllerAs: 'vm',
views: {
'tab1#': {
templateUrl: '/articledetail/tab1.html'
},
'tab2#': {
templateUrl: '/articledetail/tab2.html'
},
'tab3#': {
templateUrl: '/articledetail/tab3.html'
},
'tab4#': {
templateUrl: '/articledetail/tab4.html'
}
}
});
The frustrating thing is I don't get any errors, so I have no idea what I'm doing wrong. I've already enabled error logging as explained in the ui-router FAQ, but without result.
What am I doing wrong?
You would need this in index.html
<div ui-view=""></div>
And then the state could be changed to this:
$stateProvider.state('articledetail', {
url: '/articledetail/:article',
views: {
// this would instractu UI-Router
// to inject the articleDetail.html into index.html
// into target ui-view="" (would be the same as '#')
'': {
templateUrl: '/articledetail/articleDetail.html',
controller: 'articleDetailController',
controllerAs: 'vm',
},
// these will now be injected into above view,
// and absolute name says: viewName#stateName
// and the state is 'articleDetail'
// so we need 'tab1#articledetail'
'tab1#articledetail': {
templateUrl: '/articledetail/tab1.html'
},
'tab2#articledetail': {
templateUrl: '/articledetail/tab2.html'
},
'tab3#articledetail': {
templateUrl: '/articledetail/tab3.html'
},
'tab4#articledetail': {
templateUrl: '/articledetail/tab4.html'
}
}
});
Related
I would like to have a common state with all the common views like the header and the sidebar, and a template where I would like to load different views that can change when the state is changing.
I have an index HTML file like this:
...
<div ui-view="header"></div>
<div ui-view="sidebar"></div>
<div class="container">
<div class="wrapper">
<div ui-view="content"></div>
</div>
</div>
...
While the AngularJS config is something like this:
$stateProvider
.state('mainCommonState', {
url: '',
abstract: true,
views: {
header: {
templateUrl: 'app/common/header.html',
controller: 'headerCtrl',
controllerAs: 'vm'
},
sidebar: {
templateUrl: 'app/common/sidebar.html',
controller: 'sidebarCtrl',
controllerAs: 'vm'
},
content: {}
},
resolve: {
apiEnvironment: function ($q, environmentApiService) {
var deferred = $q.defer();
deferred.resolve(environmentApiService.getApiEnvironment());
return deferred.promise;
}
}
})
.state('first-page-content', {
url: '/first-page-content',
parent: 'mainCommonState',
views: {
content: {
templateUrl: 'app/components/first-page-content.html'
controller: 'firstPageCtrl',
controllerAs: 'vm'
}
}
})
.state('second-page-content', {
url: '/second-page-content',
parent: 'mainCommonState',
views: {
content: {
templateUrl: 'app/components/second-page-content.html'
controller: 'secondPageCtrl',
controllerAs: 'vm'
}
}
})
.state('third-page-content', {
url: '/third-page-content',
parent: 'mainCommonState',
views: {
content: {
templateUrl: 'app/components/third-page-content.html'
controller: 'thirdPageCtrl',
controllerAs: 'vm'
}
}
})
For some reason this is not working: I have an empty view instead of the 3 templates that I would like to show in the content ui-view.
If I define a template (even a blank template) inside the the abstract state, the view that is always showing is the one inside the abstract state mainCommonState.
Where am I wrong?
1st Edit: UPDATE Following the first answer
Following the suggestion from Chris T, I have updated my code, but there still something missing.
I have created a Plunker so you can help me fixing the issues.
2nd Edit
Following the suggestions from Chris T, I have updated the code using the absolute path for the content view and now the contents are switching correctly.
I have updated the Plunker accordingly to that and introduced a new level of nesting view (tabs in the first page), and I would like to have the first tab active when the first page content is loaded.
If I follow these solutions and set empty the url of the first page and set it to the first tab instead, this is not working.
Any suggestions?
Your views are targeting the wrong named ui-view.
.state('second-page-content', {
url: '/second-page-content',
parent: 'mainCommonState',
views: {
content: {
templateUrl: 'app/components/second-page-content.html'
controller: 'secondPageCtrl',
controllerAs: 'vm'
}
}
})
In this snippet, it targets the ui-view named content from the parent state which is mainCommonState. However, the content ui-view was not created in the mainCommonState. It was created in the root template.
Change your view declarations to target the view at the correct state, for example this targets the content view at the root state (which is named empty string):
.state('second-page-content', {
url: '/second-page-content',
parent: 'mainCommonState',
views: {
'content#': {
templateUrl: 'app/components/second-page-content.html'
controller: 'secondPageCtrl',
controllerAs: 'vm'
}
}
})
In ui-router 1.0 and higher you can also use absolute ui-view names by prefixing with an exclamation
.state('second-page-content', {
url: '/second-page-content',
parent: 'mainCommonState',
views: {
'!content': {
templateUrl: 'app/components/second-page-content.html'
controller: 'secondPageCtrl',
controllerAs: 'vm'
}
}
})
Read more about view targeting in the UI-Router views guide:
https://ui-router.github.io/guide/views#view-name-only
Is it possible to define multiple views in child state with parent child state relationship using UI-Router?
I have the following code in my config
$urlRouterProvider.otherwise("/child");
$stateProvider
.state('parent', {
abstract: true,
views: {
'parent': {
templateUrl: "parent.html",
controller: "parentCtrl as parentCtrl"
},
}
})
.state('parent.child', {
url: '/child',
views: {
'state1#parent.child': {
templateUrl: "child.html",
controller: "childCtrl as childCtrl"
},
}
});
I verify that my parent.html is showing up, but my child.html is not
If I move my child.html to the parent views object like
$stateProvider
.state('parent', {
abstract: true,
views: {
'parent': {
templateUrl: "parent.html",
controller: "parentCtrl as parentCtrl"
},
'state1#parent.child': {
templateUrl: "child.html",
controller: "childCtrl as childCtrl"
},
}
})
Than child.html works.
I verify using console.log($state.$current.name); in my parentCtrl that my current state is parent.child.
Can someone give me some hint?
Thanks
There is a working plunker
I adjusted your states and mostly child views : {} like this
$stateProvider
.state('parent', {
abstract: true,
views: {
'parent': {
templateUrl: "parent.html",
controller: "parentCtrl as parentCtrl"
},
}
})
.state('parent.child', {
url: '/child',
views: {
//'state1#parent.child': {
'view1#parent': {
templateUrl: "child.html",
controller: "childCtrl as childCtrl"
},
// the same as view2#parent
'view2': {
templateUrl: "child.html",
controller: "childCtrl as childCtrl"
},
'view3#': {
templateUrl: "child.html",
controller: "childCtrl as childCtrl"
},
}
the construct '...#parent.child' is wrong, because it is a absolute naming... trying to say, that we search a ui-view="..." inside of the 'parent.child' state. And that is not the case.
So, let's place this into index:
// place for parent
<div ui-view="parent"></div>
// place for child view number 3
place in index for view 3
<div ui-view="view3"></div>
And parent template could be like this
<div ui-view="view1"></div>
<div ui-view="view2"></div>
Then the above state def will target view1 with absolute naming, the same for view3 - being in index.html; view2 will go to parent with relative name
check it here
Could someone give a hint on ui-view?
I have one main ui-view and then two nested views, but for some reason these two are not getting loaded.
$stateProvider
.state('index',{
url:'',
templateUrl: './app/modules/main.html'
})
.state('index.feed',{
parent:'index',
templateUrl: './app/modules/feed.html'
})
.state('index.status',{
parent: 'index',
templateUrl: './app/modules/status.html'
});
The main page is loading but the two other views not
in my main.html I have:
<div class="voucher-display" ui-view="index.feed"></div>
<div class="feed" ui-view="index.feed"></div>
I just get an empty file.
The value you pass to ui-view in your html is not the name of the state, it should be the name of the view.
Is the html in feed.html and status.html supposed to replace or be displayed along with main.html? Either scenario will change the solution, but assuming you always want main.html, and want to display the feed.html and status.html where their respective nested views are selected, you'd do something like this:
.state('index', {
url: '/',
views: {
'main': {
templateUrl: './app/modules/main.html'
}
}
})
.state('index', {
views: {
'main': {
templateUrl: './app/modules/main.html',
},
'detail': {
templateUrl: './app/modules/feed.html'
}
}
})
.state('index.status', {
views: {
'main': {
templateUrl: './app/modules/main.html',
},
'detail': {
templateUrl: './app/modules/status.html'
}
}
});
And in your html you'd need two div tags that map the view.
<div ui-view="main"></div>
<div ui-view="detail"></div>
Now main.html should always show up in the first div, and feed.html or status.html, when their states are active, will show up in the second div.
Here is the docs for the ui-view directive, and here is a good blog post about ui-view.
After a couple of attempts, this worked to load the nested:
$stateProvider
.state('index', {
url: '',
views: {
'main': {
templateUrl: './app/modules/main.html'
},
'status#index': {
templateUrl: './app/modules/status.html'
},
'feed#index':{
templateUrl: './app/modules/feed.html'
}
}
})
index.html has:
<main ui-view="main"></main>
and inside the main.html I have:
<div class="voucher-display" ui-view="feed"></div>
<aside ui-view='status'></aside>
but now I got another problem, if I want to load another ui-view from my index.html, what should I do? because this does not work:
.state('clients',{
url:'/clients',
templateUrl: './app/modules/clients.html'
});
I want to give 2 parts of my UI the same controller but still let them have each of their own unique controllers.
$stateProvider
.state('standard.page', {
url: '/:page',
resolve: {
page: function($stateParams) {
...
},
},
views: {
'content': {
templateUrl: '/tmpl/page',
controller: 'controllercontent'
},
'sideMenu': {
templateUrl: '/tmpl/menu',
controller: 'controllermenu',
}
}
})
So I want both content and sideMenu to share a controller. If I add a controller above the views then it requires a new template, I want to use the standard template instead of making a unique template for this state. Any ideas how I can get 3 controllers going in this example? Thanks.
I battled with this at some point in time, and I believe I made a template file that isn't directly accessible (via abstract: true). Here's an example...
.state('standard', {
url: '/standard',
abstract: true,
templateUrl: '/tmpl/standard.html',
controller: 'SharedController'
},
})
.state('standard.page', {
url: '/:page',
resolve: {
page: function($stateParams) {
...
},
},
views: {
'content': {
templateUrl: '/tmpl/page',
controller: 'controllercontent'
},
'sideMenu': {
templateUrl: '/tmpl/menu',
controller: 'controllermenu',
}
}
});
In your tmpl/standard.html file, make sure this exists somewhere within the file:
<div ui-view="sideMenu">
<div ui-view="content">
Hope this points you in the right direction.
I have an app with 3 views (A,B,C) and 2 states(1,2)
html
<div ui-view="A"></div>
<div ui-view="B"></div>
<div ui-view="C"></div>
The two states are called list and create. In both states the template and controller of view A + B stay the same but view c should change templates and controllers. I can get view c's content to change but it refreshes view A and view B as it does ie things that are in their controllers run again.
What is the correct way to organise the router to prevent this?
js so far
$urlRouterProvider.otherwise("/basestate/list");
$stateProvider
.state('baseState', function() {
url:"/basestate",
templateUrl: "basestate.html",
controller: 'BaseStateCtrl'
})
.state('baseState.list', function() {
url: "/list",
views: {
"viewA#baseState": {
templateUrl: "viewA.html"
controller: "ViewACtrl"
},
"viewB#baseState": {
templateUrl: "viewB.html"
controller: "ViewBCtrl"
},
"viewC#baseState": {
templateUrl: "list.html"
controller: "listCtrl"
}
}
})
.state('baseState.create', function() {
url: "/create",
views: {
"viewA#baseState": {
templateUrl: "viewA.html"
controller: "ViewACtrl"
},
"viewB#baseState": {
templateUrl: "viewB.html"
controller: "ViewBCtrl"
},
"viewC#baseState": {
templateUrl: "create.html"
controller: "createCtrl"
}
}
})
To achieve that you basically need to freeze your viewA and viewC at the level of baseState and make that state abstract:
.state('basestate', {
url: '/basestate',
abstract: true,
views: {
"viewA": {
templateUrl: "viewA.html",
controller: "ViewACtrl"
},
"viewB": {
templateUrl: "viewB.html",
controller: "ViewBCtrl"
},
"viewC": {
template: '<div ui-view="viewC_child"></div>'
}
}
})
Note that for viewC we are making a placeholder that will contain our nested view (either list or create):
.state('basestate.list',{
url: "/list",
views: {
"viewC_child": {
templateUrl: "list.html",
controller: "ListCtrl"
}
}
})
.state('basestate.create', {
url: "/create",
views: {
"viewC_child": {
templateUrl: "create.html",
controller: "CreateCtrl"
}
}
})
Check this plunkr and be careful with commas in your code :)