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 :)
Related
My app is very simple. i have a home page that contains header and body. in body section I want to show login page and if URL changed to 'password/forget' I show password reset form. my templates:
index.html :
<header ui-view="header">
</header>
<div class="container-fluid">
<div class="row">
<div ui-view="main">
</div>
</div>
</div>
home.html:
<div ui-view>
</div>
And ui-router config is this:
$locationProvider.html5Mode({enabled: true, requireBase: false});
$stateProvider.state('home', {
url: '/',
views: {
'header': {
templateUrl: '/header.html'
},
'main': {
templateUrl: '/home.html'
}
}
}).state('home.forgetPassword', {
url: '/password/forget',
templateUrl: '/forgetPassword.html',
});
Now when I go "/password/forget" anything happen and index.html is showing.
I want to show forgetPassword.html when route changes to "/password/forget" .
Following this code in documentation of ui-router:
myApp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('state1', {
url: "/state1",
templateUrl: "partials/state1.html"
})
.state('state1.list', {
url: "/list",
templateUrl: "partials/state1.list.html",
controller: function($scope) {
$scope.items = ["A", "List", "Of", "Items"];
}
})
.state('state2', {
url: "/state2",
templateUrl: "partials/state2.html"
})
.state('state2.list', {
url: "/list",
templateUrl: "partials/state2.list.html",
controller: function($scope) {
$scope.things = ["A", "Set", "Of", "Things"];
}
});
});
What i suggest is to create the 'password' state first.
Try the following solution:
$stateProvider.state('home', {
url: '/',
views: {
'header': {
templateUrl: '/header.html'
},
'main': {
templateUrl: '/home.html'
}
}
}).state('password', {
url: '/password',
templateUrl: '/password.html',
}).state('password.forgetPassword', {
url: '/forget',
templateUrl: '/forgetPassword.html',
});
Create the file 'password.html' for now, later on it might be useful for '/password' view.
Problem solved. it was for / in parent state and repeat it on child states.
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
I am trying to extend a parent view to a child view.
My route.js
let view = {
'': {
templateUrl: '/app/content.html'
},
'sidebar': {
templateUrl: '/app/sidebar.html'
}
};
.state('profile', {
abstract: true,
url: '/profile',
views: view,
templateUrl: '/app/profile/profile.html'
})
.state('profile.about', {
parent: 'profile',
url: '/about',
views: {
'': {
templateUrl: '/app/profile/about.html'
}
}
})
My index.html:
<div ui-view></div>
My profile/profile.html:
//all other stuff (header, sidebar, etc)
<div>
<h1>Profile</h1>
<div ui-view=""></div>
</div>
My profile/about.html:
<div>
<h1>About</h1>
</div>
Everything works perfectly including the sidebar.
The problem is that about.html is showing the page but it is not extending the profile/profile.html page.
Any solutions?
Here is the plunker.
It's a little bit different but it is the same, considering how the route1 is not shown but the test.html is show.
Try this way:
let view = {
'': {
templateUrl: '/app/profile/index.html'
},
'content': {
templateUrl: '/app/content.html'
},
'sidebar': {
templateUrl: '/app/sidebar.html'
}
};
.state('profile', {
abstract: true,
url: '/profile',
views: view
})
.state('profile.about', {
parent: 'profile',
url: '/about',
views: {
'': {
templateUrl: '/app/profile/about.html'
}
}
})
My setup
app/learning/learning.js
angular.module('meanApp')
.config(function($stateProvider) {
$stateProvider
.state('learning',{
templateUrl: 'app/learning/learning.html',
url: '/learning',
controller: 'LearnCtrl',
views: {
'list': {
templateUrl: 'app/learning/learning.list.html',
controller: function($scope){ }
},
'magic': {
templateUrl: 'app/learning/learning.magic.html',
controller: function($scope){ }
}
}
});
});
app/learning/learning.html
<h1>Learning</h1>
<div ui-view="list"></div>
<div ui-view="magic"></div>
app/learning/learning.list.html
<p>A list</p>
app/learning/learning.magic.html
<h2>Magic</h2>
when I navigate to /learning I get a blank page, I'm not sure what I'm doing wrong so any help would be greatly appreciated.
You shouldn't load the base template inside state when there are nested ui-view,
Define the base template inside views.
Route Code
angular.module('meanApp')
.config(function($stateProvider) {
$stateProvider
.state('learning',{
url: '/learning',
views: {
'': {
templateUrl: 'app/learning/learning.html',
controller: 'LearnCtrl'
},
'list#learning': { //you missed state name here
templateUrl: 'app/learning/learning.list.html',
controller: function($scope){ }
},
'magic#learning': { //you missed state name here
templateUrl: 'app/learning/learning.magic.html',
controller: function($scope){ }
}
}
});
});
This could Help you, Thanks.
The problem was that I was trying to load the base template inside state and I missed out the state name as Pankaj said, so the solution is...
angular.module('meanApp')
.config(function($stateProvider) {
$stateProvider
.state('learning',{
url: '/learning',
views: {
'': {
templateUrl: 'app/learning/learning.html',
controller: 'LearnCtrl'
},
'list#learning': { //you missed state name here
templateUrl: 'app/learning/learning.list.html',
controller: function($scope){ }
},
'magic#learning': { //you missed state name here
templateUrl: 'app/learning/learning.magic.html',
controller: function($scope){ }
}
}
});
});
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.