Summery - I have two states. Both of them have two views in them col1 and col2. In both states col1 has same templateUrl i.e. FirstTemplate.html.
Question - How can I change from state one to state two without reloading FirstTemplate.html.
I have done this by making state two a child of state one and it is working fine that way, but I find it to be an incomplete solution since parent-child structure is not suitable for me in some scenarios.
$stateProvider
.state('one',{
views: {
'col1': {
templateUrl: 'FirstTemplate.html'
},
'col2': {
templateUrl: 'SecondTemplate.html'
}
},
.state('two',{
views: {
'col1': {
templateUrl: 'FirstTemplate.html'
},
'col2': {
templateUrl: 'ChangedTemplate.html'
}
}
})
I think the best solution might be to use a parent abstract state, like on this way:
.state( 'parent', {
abstract : true,
templateUrl : 'FirstTemplate.html'
})
.state( 'parent.one', {
templateUrl : 'SecondTemplate.html',
})
.state( 'parent.two', {
templateUrl : 'ChangedTemplate.html',
})
And, in order to yield both children views, you have to add this on FirstTemplate:
<div ui-view></div>
I think this will solve your problem.
PS: you need to specify also the url on the states
You'll need a hierarchical state structure, but both views have the same parent.
$stateProvider
.state('root', {
abstract: true,
url: '/root',
views: {
'col1': {
templateUrl: 'FirstTemplate.html',
controller: function($scope) {
$scope.lastUpdate = new Date();
}
}
}
}).state('root.one', {
url: '/one',
views: {
'col2': {
templateUrl: 'SecondTemplate.html',
controller: function($scope) {
$scope.lastUpdate = new Date();
}
}
}
})
.state('root.two', {
url: '/two',
views: {
'col2': {
templateUrl: 'ChangedTemplate.html',
controller: function($scope) {
$scope.lastUpdate = new Date();
}
}
}
});
Plunker
Related
I am attempting to get multiple views to use the same controller. I've tried a couple of things so far, none seem to work. By "doesnt work" I mean the controller MapController isnt instantiated and the views cannot see the controller
1
$stateProvider.state(PageStateNames.COMPONENTS_LIVEMAP, {
url: "/components/vehicles/:vehicle/:panel",
views: {
"": {
controller: "MapController as vm"
},
"content#app": {
templateUrl: "....html"
},
"sidenav#app": {
templateUrl: "....html"
}
}
});
2
$stateProvider.state(PageStateNames.COMPONENTS_LIVEMAP, {
url: "/components/vehicles/:vehicle/:panel",
controller: "MapController as vm"
views: {
"content#app": {
templateUrl: "....html"
},
"sidenav#app": {
templateUrl: "....html"
}
}
});
Having looked at existing questions this should work. Have I missed something?
$stateProvider.state(PageStateNames.COMPONENTS_LIVEMAP, {
url: "/components/vehicles/:vehicle/:panel",
views: {
"": {
templateUrl: "......html",
controller: "MapController as vm"
},
"content#app": {
templateUrl: "....html",
controller: "MapController as vm"
},
"sidenav#app": {
templateUrl: "....html",
controller: "MapController as vm"
}
}
});
To use the same controller in a state, you can use child-parent nested state. For example :
$stateProvider.state('home', {
templateUrl: '....html',
controller: 'ParentController'
})
.state('home.livemap', { // << this state will use parent controller instance, this is the dot notation to make livemap a child state of home (more info here https://github.com/angular-ui/ui-router/wiki/Nested-States-and-Nested-Views
templateUrl: '....html'
});
I'm trying to provide some initial "partial" views through an abstract state using Angular and Angular UI router but somewhere along the way I'm making a misinterpretation which breaks my implementation...
As you can see I tried some variations with specifying a customLayout.html template to the abstract state. This also didn't work.
What does work (but isn't what I want) is specifying the shared partial templates on each state.
I've implemented that what does and what does not here:
See this: JSBin.
Look at: //REMOVE COMMENT HERE to switch between an "inherited" or "child" state.
$stateProvider
.state("layout", {
abstract: true,
url: "",
//templateUrl: "customLayout.html",
views: {
"header" : {
templateUrl: 'shared/header.html',
}
}
})
//REMOVE COMMENT HERE
//.state("layout.demo")
.state("demo", {
url: "/demo",
views: {
"" : {
templateUrl: 'demo.html',
},
"header" : {
templateUrl: 'shared/header.html'
}
}
});
Edit:
With help of this:
$stateProvider
.state("layout", {
abstract: true,
url: "",
//templateUrl: "customLayout.html",
views: {
"header" : {
templateUrl: 'shared/header.html',
},
//ADDED THIS, ESSENTIALLY PROXYING THE NAMELESS TEMPLATE
'': {
template: '<ui-view />'
}
}
})
Try this:
app.config([
'$stateProvider',
'$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
console.log("app: states");
$urlRouterProvider
.otherwise('/demo');
$stateProvider
.state("layout", {
abstract: true,
url: "",
//templateUrl: "customLayout.html",
views: {
"" : {
templateUrl: 'demo.html'
},
"header" : {
templateUrl: 'shared/header.html'
}
}
})
//REMOVE COMMENT HERE
//.state("layout.demo")
.state("layout.demo", {
url: "/demo",
});
}
]);
Here is the working link:
http://jsbin.com/zehejovaco/1/edit?html,output
index.html
--navbar.html
--content.html
--customer.html
--netScore.html
--useExp.html
--useExpNest1.html
--useExpNest2.html
--internalPerformance.html
--leftNavPanel.html
I have this kind of view structure and I want to load them all at once so I'm planning to put this in a single state. I saw this answer but it seems that its only applicable for a simple/double nested views(I have 3 or more nested views). How can I put this in a single state, or is there a better way if not possible?
EDIT
I've come up with this solution and it works somehow.
.state('index', {
url: '/',
views: {
'': {
templateUrl: 'app/modules/bulletin/views/index.view.html',
controller: 'indexController'
},
'navbar#index': {
templateUrl: 'app/modules/bulletin/views/index/navbar.view.html',
controller: 'navbarController'
},
'content#index': {
templateUrl: 'app/modules/bulletin/views/index/content.view.html',
controller: 'contentController'
},
'leftNavPanel#index': {
templateUrl: 'app/modules/bulletin/views/index/leftNavPanel.view.html',
controller: 'contentController'
}
}
})
.state('index.content', {
views: {
'customer#index': {
templateUrl: 'app/modules/bulletin/views/index/content/customer.view.html'
},
'internalPerformance#index': {
templateUrl: 'app/modules/bulletin/views/index/content/internalPerformance.view.html'
}
}
})
.state('index.content.customer', {
views: {
'netScore#index.content': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/netScore.view.html'
},
'useExp#index.content': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/useExp.view.html'
}
}
})
.state('index.content.customer.useExp', {
views: {
'useExpNest1#index.content.customer': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/useExp/useExpNest1.view.html'
},
'useExpNest2#index.content.customer': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/useExp/useExpNest2.view.html'
}
}
})
And then add this code to the indexController(most parent controller)
$state.go('index.content');
$state.go('index.content.customer');
$state.go('index.content.customer.useExp');
But this answer is still wrong because, let's say that netScore.html has some child views, we will create route for it then go to that state, but netScore and useExp states are on the same level so only one of them will be loaded if we use
$state.go('index.content');
$state.go('index.content.customer');
$state.go('index.content.customer.netScore');
$state.go('index.content.customer.useExp');
EDIT 2
Here's a plunker of what I've done so far. The view names are slightly different but you will see clearly the problem there
You can use a combination of named views plus abstract: true property to load child views by default
angular.module('sampleModule', [
'ui.router'
]);
angular.module('sampleModule')
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.when('','/');
$stateProvider
.state('main', {
url: '',
abstract: true,
templateUrl: 'main.view.html'
})
.state('main.load', {
url: '/',
abstract: true,
views:{
'content':{
templateUrl:'content.view.html',
},
'navbar':{
templateUrl:'navbar.view.html',
}
}
})
.state('main.load.customer', {
url: '',
abstract: true,
views:{
'customerPerception':{
templateUrl:'content-customerPerception.view.html'
},
'customerExperience':{
templateUrl:'content-customerExperience.view.html'
}
}
})
.state('main.load.customer.netTrustScore', {
url: '',
abstract: true,
views: {
'netTrustScore': {
templateUrl: 'content-customerPerception-netTrustScore.view.html'
},
'useExperience': {
templateUrl: 'content-customerPerception-useExperience.view.html'
},
'trustStatements': {
templateUrl: 'content-customerPerception-trustStatements.view.html'
}
}
})
.state('main.load.customer.netTrustScore.somethingElse', {
url: '',
views: {
'abc': {
templateUrl: 'content-customerExperience-customerComplaints.view.html'
},
'': {
templateUrl: 'content-customerExperience-networkQualityIndex.view.html'
}
}
})
;
}])
.controller('mainController', ['$scope', '$state', function($scope, $state) {
console.log('mainController initialized!');
}]);
here's a plnkr
https://plnkr.co/edit/BBAeWjnGbTsbO1lMguU9?p=preview
Thanks to the guys from AngularJS group in FB. The problem is I put two sibling views in two different states. UI router cant load two states at the same time. So the solution is to put all same level views in a single subState.
Lets assume we have this kind of structure:
index.html
--navbar.html
--content.html
--customer.html
--netScore.html
--netScoreNest1.html
--netScoreNest2.html
--useExp.html
--useExpNest1.html
--useExpNest2.html
--internalPerformance.html
--leftNavPanel.html
the proper routing for this would be like this
.state('index', {
url: '/',
views: {
'': {
templateUrl: 'index.view.html',
controller: 'mainController'
},
'navbar#main': {
templateUrl: 'index/navbar.view.html'
},
'content#main': {
templateUrl: 'index/content.view.html'
},
'leftNavPanel#main': {
templateUrl: 'index/leftNavPanel.view.html'
}
}
})
.state('index.subLevel', {
views: {
'customer#index': {
templateUrl: 'index/content/customer.view.html'
},
'internalPerformance#index': {
templateUrl: 'index/content/internalPerformance.view.html'
}
// IF LEFTNAVPANEL OR NAVBAR HAVE SUB VIEWS, PUT IT HERE
}
})
.state('index.subLevel.subLevel2', {
views: {
'netScore#index.subLevel': {
templateUrl: 'index/content/customer/netScore.view.html'
},
'useExp#index.subLevel': {
templateUrl: 'index/content/customer/useExp.view.html'
}
// IF INTERNALPERFORMANCE HAVE SUB VIEWS, PUT IT HERE
}
})
.state('index.subLevel.subLevel2.subLevel3', {
views: {
'netScoreNest1#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/netScore/netScoreNest1.view.html'
},
'netScoreNest2#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/netScore/netScoreNest2.view.html'
},
'useExpNest1#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/useExp/useExpNest1.view.html'
},
'useExpNest2#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/useExp/useExpNest2.view.html'
}
}
})
And then in mainController, load the inner most child state, this will automatically load the views of all its parent(up to topmost parent state 'index')
$state.go('index.subLevel.subLevel2.subLevel3');
And thats it. And also here's a plunker to make it easier to understand. (Views and structure are slightly different from this post different. Too lazy to edit)
I have states defined as below in my angularjs app using angular ui router state provider. And, I would like to define multiple states with the same configuration ie. with the same template and controller.
$stateProvider
.state('parent', {
templateUrl: 'parent.html',
abstract: true,
parent: 'apm'
})
.state('parent.list', {
abstract: true,
url: '/list',
templateUrl: 'list.html',
controller: 'ListCtrl'
})
.state('parent.list.closed', {
url: '/q',
templateUrl: 'closed.html'
})
.state('parent.list.details', { // would like to have same template, controller on different state parent.details without list
url: '/:id/:name',
abstract: true,
templateUrl: 'details.html',
controller: 'DetailsCtrl',
resolve: {
.....
.....
}
})
.state('parent.list.details.data', { // would like to have same template, controller on different state parent.details.data without list
url: '/details',
views : {
'view1' : {
templateUrl : 'view1.html'
},
'view2' : {
templateUrl : 'view2.html',
controller : 'View2Ctrl'
},
'view3' : {
templateUrl : 'view3.html'
},
'view4' : {
templateUrl : 'view4.html'
}
}
})
Is it possible to do something like
.state(['parent.list.details', 'parent.details'], {
url: '/:id/:name',
abstract: true,
templateUrl: 'details.html',
controller: 'DetailsCtrl',
resolve: {
.....
.....
}
})
Any help or suggestions?
Each state needs to be defined in it's own .state() method. You will run into multiple problems trying to do it the way you listed above. Most importantly would be the url.
You can simply do this:
.state('parent.list', {
url: '/list',
abstract: true,
templateUrl: 'details.html',
controller: 'DetailsCtrl',
resolve: {
.....
.....
}
.state('parent.list.details', {
url: '/:id/:name',
abstract: true,
templateUrl: 'details.html',
controller: 'DetailsCtrl',
resolve: {
.....
.....
}
})
While the code is not condensed or efficient in the sense you have to declare the controller and partial used on each state, it is necessary because each state needs its own .state() method
I wanted the same and made it like this:
//add a new Function to the object $stateProvider
$stateProvider.states = (statesArr, obj) => {
for (var i in statesArr) {
var state = statesArr[i];
$stateProvider.state(state, obj);
}
return $stateProvider;
};
//use the new function
$stateProvider
.states(["main", "main.test"], {
url: '/main',
templateUrl: 'modules/ViewContainer.html',
controllerAs: 'currentCtrl',
controller: 'MainCtrl'
})
My angular app is routed as following:
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html"
})
// Each tab has its own nav history stack:
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab-dotnet.html',
controller: 'QuestionsCtrl'
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab-sql.html',
controller: 'QuestionsCtrl'
}
}
})
The above two routes use the same controller but different html pages.
Since both the pages are same, I want to have a single html page in my application instead of two different tab-sql and tab-dotnet pages.
But I will need a differentiation variable to be injected to the controller when selecting the tabs.
Basically I need something like this:
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
type: 'dotnet' // so that i get this type in my Controller
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
type: 'sql'
}
}
})
How to achieve this?
You can pass data to controllers in a state using resolve.
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
resolve: {
type: 'dotnet';
}
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
resolve: {
type: 'sql';
}
}
}
})
https://github.com/angular-ui/ui-router/wiki#resolve