I'm using UI-router's $stateProvider for the routing on an angularjs project and find myself repeating a lot of the same configuration for the route views.
For example:
$stateProvider.state('triage', {
url: '/operations/triage',
views: {
"header": {
controller: 'CommonCtrl',
templateUrl: 'common/header.tpl.html'
},
"submenu": {
controller: 'CommonCtrl',
templateUrl: 'common/submenu.tpl.html'
},
"content": {
controller: 'TriageCtrl',
templateUrl: 'operations/triage/triage.tpl.html'
},
"footer": {
templateUrl: 'common/footer.tpl.html'
}
},
The header, submenu and footer will be the same for almost every state, the content is really the only part that is variable.
Is there a way to configure the router to always use predefined controllers and templates unless otherwise specified.
Solution here could be called: layout root state. As in detail described here:
Angular UI Router - Nested States with multiple layouts
Nested states or views for layout with leftbar in ui-router?
One of the plunkers
we can create a super parent state 'index' or 'root' (there could be few of them for different state families, e.g. standard, login, doc) which is creating unnamed target for its child/ren (ui-view="") while injecting related templates around:
.state('index', {
abstract: true,
//url: '/',
views: {
'#' : {
templateUrl: 'layout.html',
controller: 'IndexCtrl'
},
'top#index' : { templateUrl: 'tpl.top.html',},
'left#index' : { templateUrl: 'tpl.left.html',},
// this one is unnamed - a target for children
'#index' : { templateUrl: 'tpl.main.html',},
},
})
So, in this example the layout.html would look like:
<div>
<section class="left">
<div ui-view="left"></div>
</section>
<section class="right">
<section class="top">
<div ui-view="top"></div>
</section>
<section class="main">
// here is the unnamed view - filled by this state
// but later target for the child states
<div ui-view=""></div>
</section>
</section>
</div>
Now, we can inject that root state into any existing state:
.state('client', {
parent: 'index',
...
})
.state('product', {
parent: 'index',
...
})
so they will have unchanged name ('client', 'product'), i.e. without prefix 'index' or 'root' but will be injected into existing template
The example
Related
What i'm trying to do:
<div id="chat">
<div ui-view>Here should people.htm be loaded</div>
<div ui-view="chat">Here is current person chat peopleChat.htm</div>
</div>
I already managed a nested structure. If "chat" is child of "people" - no problem.
But I want em to remain on the same level, but be in a different state. Something like.
$stateProvider
.state('people', {
url: '/people',
templateUrl: ...,
controller: ...
})
.state('people.chat', {
views: {
'chat': {
url: '/:personId',
templateUrl: ...,
controller: ...
}
}
})
My unnamed view is filling with data. After unnamed view is filling, i'm calling $state.go('people.chat', { personId: vm.personId });
But nothing is happening.
Name both views and you are ok:
<div id="chat">
<div ui-view="main">Here should people.htm be loaded</div>
<div ui-view="chat">Here is current person chat peopleChat.htm</div>
</div>
And your controler:
$stateProvider
.state('people', {
views: {
'main#': {
url: '/people',
templateUrl: ...,
controller: ...
}
}
})
.state('people.chat', {
views: {
'chat#': {
url: '/:personId',
templateUrl: ...,
controller: ...
}
}
})
Basically the # absolute targets the view.
Meaning if you use it like chat# it targets the named view chat in the root html.
If you want to nest the views you can use chat#people
which targets the ui-view loaded in the template that people state has injected.
Plunker
i am developing a site in AngularJs with ui-router. I have a situation where on button click i need to change and load three state into that page and the three looks like the image .Please help me how can i load multiple pages. in one page
You need to configure your router config like this:
$stateProvider
.state("state1", {
url: "/url1",
controller: "FirstController",
views: {
view1: { templateUrl: "templates/template1.html" },
view2: { templateUrl: "templates/template2.html" },
view3: { templateUrl: "templates/template3.html" }
}
}).state("state2", {
url: "/url2",
controller: "SecondController",
views: {
view1: { templateUrl: "templates/template4.html" },
view2: { templateUrl: "templates/template5.html" },
view3: { templateUrl: "templates/template6.html" }
}).state("state3", {
url: "/url3",
views: {
view1: {
templateUrl: "templates/template7.html",
controller: "ThirdController"
},
view2: {
templateUrl: "templates/template8.html",
controller: "FourthController"
},
view3: {
templateUrl: "templates/template9.html",
controller: "FifthController"
}
});
So you need to provide information about every view in every state: templates that your views use, controllers, resolves, etc. Then you need to give names to your ui-view containers (in this example view1, view2, view3). That's how ui-router will know what templates and controllers it needs to use for every view container.
And your view will look similar to this:
<section class="sidebar left">
<div ui-view="view1"></div>
</section>
<section class="sidebar right login">
<div ui-view="view2"></div>
</section>
<div ui-view="view3"></div>
I have a basic Index.html file which following structure:
<body class="{{$state.current.name.replace('.','-')}}">
<div ui-view>
<div ng-include src="'partials/menu.html'"></div>
<!-- <div ng-menu class="ui top blue sidebar menu active"></div> -->
<div class="view-height-100"></div>
</div>
...
</body>
When I am in the login state, it's working very well:
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'partials/login-area.html',
controller: 'LoginController',
});
But, when I am routing to the user.management state, nothing gets shown (but Chrome is loading the template, so I can access the scope and the .html file is there):
$stateProvider
.state('user', {
url: '/:buildingName',
controller: 'CurrentBuildingController',
data: {
access: ['user']
}
})
.state('user.management', {
url: '/management',
templateUrl: '/views/management.html',
controller: 'ManagementController'
})
Can someone explain me why?
Parent state simply must have target for its child (unless we use absolute naming to target some super parent, but it is another approach)
.state('user', {
url: '/:buildingName',
template: "<div ui-view></div>",
controller: 'CurrentBuildingController',
data: {
access: ['user']
}
})
see that we now have template: "<div ui-view></div>", which will serve as a view target for any child state 'user.xxx'
Check also:
AngularJS UI-Router : Abstract state + child states not working
EXTEND - let child to target the index.html
We can use absolute naming and child will then be injected directly into index.html. There is a working plunker (by intention parent won't load, it does not have any template)
.state('parent', {
url: "/parent",
//templateUrl: 'tpl.html',
})
.state('parent.child', {
url: "/child",
views: {
'#': {
templateUrl: 'tpl.html',
controller: 'ChildCtrl',
}
}
})
Check this for more info:
Angularjs ui-router not reaching child controller
I have an app which has three views (ui-view using Angular ui-router):
header, sidebar and content.
my index.html looks like this: (I omitted the actual classes for clearness)
<body>
<div ui-view="header" class="..."></div>
<div class="page-container">
<div ui-view="sidebar" class="..."></div>
<div class="page-content">
<div ui-view="content"></div>
</div>
</div>
</div>
</body>
This pattern works well with pages that have the header and sidebar.
But I have some pages that I don't want to display the header and sidebar, for example a login page that should fit on all page.
For this kind of pages I need something like:
ui-view which should look like this:
<body>
<div ui-view="content"></div>
</body>
So it won't be nested and under the other views <div>'s and affected by their classes.
I have some solutions in mind, but none of them gave me a good enough UX.
I tried adding <ng hide> to the header and sidebar depending on the state. It worked but there was annoying flickering (that I couldn't eliminate with ng-cloak for some reason..)
To make things more clear, here is an example of two states , one is "one pager" and the other is full page with header and sidebar:
.state('Login', {
url: '/login',
views: {
'content': {
templateUrl: './../templates/login.html',
controller: 'LoginCtrl'
}
}
})
.state('Users', {
url: '/users',
views: {
'header': {
templateUrl: './../templates/header.html',
controller: 'HeaderCtrl'
},
'sidebar': {
templateUrl: './../templates/sidebar.html',
controller: 'SidebarCtrl'
},
'content': {
templateUrl: './../templates/users.html',
controller: 'UsersCtrl'
}
}
})
I also think using nested views, but not sure whether this is the right approach.
Maybe try using nested states, ie:
.state('app', {
url: '/app',
abstract: true,
templateUrl: './../templates/treeViewTemplate.html'
})
.state('login', {
url: '/login',
templateUrl: './../templates/login.html',
controller: 'LoginCtrl'
})
.state('app.users', {
url: '/users',
views: {
'header': {
templateUrl: './../templates/header.html',
controller: 'HeaderCtrl'
},
'sidebar': {
templateUrl: './../templates/sidebar.html',
controller: 'SidebarCtrl'
},
'content': {
templateUrl: './../templates/users.html',
controller: 'UsersCtrl'
}
}
})
In your root abstract state you define a template for 3 view-layout. login state will instead take whole display.
I am trying to create a page where I have a fixed header and changing content, but the fixed header depends on the state route, I would also like the header and the content to have different controllers and templates.
For example for the URL
/user/:userId/profile
I would like the header to display the user name, so it needs to know the value of :userId.
I can achieve this by used named views and ui-router, but here us code duplication that I want to avoid
$stateProvider
.state('profile', {
url: '/user/:user_id/profile',
views: {
'header': {
templateUrl: 'user-header.html',
controller: 'HeaderController'
},
'info': {
templateUrl: 'profile.html',
controller: 'ProfileController'
}
}
})
.state('friends', {
url: '/user/:user_id/friends',
views: {
'header': {
templateUrl: 'user-header.html',
controller: 'HeaderController'
},
'info': {
templateUrl: 'friends.html',
controller: 'FriendsController'
}
}
})
<section id="startup-header" ui-view="header">
</section>
<section ui-view="info">
</section>
How can I define the header once, but have the content defined per content type.
I hope I formulate the questions in a way it's clear what I want to achieve.
Ok. Let's try this:
You can create a parent page with your header for user's profile that will be contain nested child pages:
<div id="header">
<a ui-sref="userPage.profile">Profile</a>
<a ui-sref="userPage.friends">Friends</a>
......
</div>
<div ui-view>
</div>
Read more about ui-sref ditective here
And in $stateProvider something like:
$stateProvider.state('userPage.profile', {
url: '/user/:user_id/profile',
templateUrl: 'profile.html',
controller: 'ProfileController'
}
}).state('friends', {
url: '/user/:user_id/friends',
templateUrl: 'friends.html',
controller: 'FriendsController'
}
})