I am struggling to get nested states working with UI router
I want a page to view a device to be have a URL like /device/SERIAL_NUMBER/info where
/device is fixed
/SERIAL_NUMBER is variable aka :id
/info refers to a nested state
I have a number of nested states I want, but for simplicity I'm only showing a one state. Note that for info it shares the same controller as the parent view, other nested views do not.
State setup
.state('device', {
url: '/device/:id',
templateUrl: '/views/devices/device.html',
controller: 'viewDeviceController'
})
.state('device.info', {
url: 'info',
templateUrl: '/views/devices/device_info.html'
})
My main HTML looks something like this
<body>
<header><h1>Title</h1></header>
<div ui-view>
<!-- This is where /views/devices/device.html goes -->
</div>
/views/devices/device.html looks like so:
<div>General text about a device</div>
<div ui-view>
<!-- This is where /views/devices/device_info.html should go -->
</div>
If I navigate to /#/device/L340009 I see the main page and the device.html, I do not see device_info.html - this is expected but ideally I'd like the default to be to load the first route (info)
If I navigate to /#/device/L340009/info it redirects me to home (which is my otherwise) so something is wrong with the route
Where am I going wrong?
The url here should start with '/'
.state('device.info', {
// instead of this
// url: 'info',
// we need this
url: '/info',
templateUrl: '/views/devices/device_info.html'
})
that will support url concatenation
'/#/device/L340009' + '/info'
is '/#/device/L340009/info'
Related
I'm just trying to setup a boilerplate for angular 1.5.9 with UI Router 1.0.0. I can display my parent state component within the ui-view, however when I nest states within my parent, my components aren't being injected into my ui-view.
This is my index.html
<body ng-app="app">
<ui-view></ui-view>
</body>
This is the main component
<div class="main-container">
<banner></banner>
<div ui-view='ui-view></div>
</div>
It is at this point where in I'm unable to inject anything into the ui-view.
This is my javascript file
$stateProvider
.state('app', {
url: '/',
component: 'main'
})
.state('app.login', {
url: '/login',
views: {
'ui-view': {
templateUrl: './app/login/login.html'
}
}
});
I'm not sure what I'm doing wrong, any help/direction to the right path would be appreciated.
EDIT
Additional Info that might be helpful
When I reference login as a parent state everything works as expected.
The login component is part of a separate module that I've included in my main module.
For nesting one child state in each parent component, there is no need to use named views as you did by adding a value of "ui-view" for the ui-view directive used in your main component template. Those named views are only required when you want to address more than one ui-view. Then you need to reference them by name.
In your sample, you will not see any content because you also don't target the named view correctly. There are some rules on how to address those named views if the named views are defined in a template which is not the root file. In that case you need to be more specific by referencing the ui-view with a "ui-view-name#state" syntax which would mean "ui-view#app" in your case.
But as already mentioned: In your simple case, just leave out the name for the ui-view and replace the views section in your state config with a plain template (or a component reference).
.state('app.login', {
url: '/login',
templateUrl: './app/login/login.html'
});
For details on nesting views, please have a look at the great sample apps in the ui-router docs.
So this one is really strange, I've no explanation as to why it worked the way it did. All I did was change the javascript file to the one below
$stateProvider
.state('login', {
url: '/login',
component: 'main'
})
.state('login.default', {
url: '/default',
component: 'login'
});
Instead of my parent having '/', changed it to '/login'. I'd be keen to know if someone knows the reason behind this behaviour.
$stateProvider
.state('app', {
url: '/',
templateUrl: path/to/main_component.html
})
.state('app.login', {
url: '/login',
views: {
'ui-view': {
templateUrl: './app/login/login.html'
}
}
});
When you are in app.login view(state) ui-view will be checked in its parent states template. If you don't have a template, it doesn't know where to render.
'ui-view':{} is targetted to its parent view.
'ui-view#':{} is targetted to the root component that is index.html
I am working with angular and using ui router. The structure of my views are something like this:
<div ui-view>
<div ui-view="left">
-- list of items
</div>
<div ui-view="right">
-- details of item
</div>
</div>
Now if i select an item from left panel, an api is called to get the details of that item. Now want to load that information in right view.
All the view states have their own controller. Can someone please help me to pass the returned data from api tosecond view?
This is a pretty straightforward and common use case with ui-router. The main concept is of nested states and multiple named-views.
I would set this up with some states that look something like:
$stateProvider
.state('user', {
url: '/user',
views: {
'left': {
templateUrl: '/templates/states/user-list.tpl.html'
},
'right': {
template: '<p>This is default content that would appear in the right view until a user is selected. This is nice, but is completely optional.</p>'
}
}
})
.state('user.details', {
url: '/:userId',
views: {
'right': {
templateUrl: '/templates/states/user-details.tpl.html'
}
}
});
In the user-list template, you would use links something like:
<a ui-sref="user.details({userId: user.id})">{{user.name}}</a>
Because user.details is a child state of user, the user-list stays loaded into the left view while navigating through different users in the right view.
Imagine some html as follows:
<body ng-app="blocksApp">
Some content goes here
<div ui-view="monty">
<div ui-view="dave">Aaa</div>
<div ui-view="pete">Bbb</div>
<div ui-view="steve">Ccc</div>
</div>
</body>
Using ui-router, is there any way to code a state that will set "dave" to a new snippet of html, whilst leaving everything else untouched.
e.g. I'd like to do this:
$stateProvider
.state('daveonly',{
url: "/dave",
views:{
'dave':{template:"Dave now has content"}
}
})
I can't get it to work. The reason I want to do this is that sometimes I'd like to replace 'Dave' with a partial update, other times I'd like to replace the entire 'monty' with a partial update. It seems that ui-router does not like having nested ui-views in the same snippet of html.
From one point of view I'd like to suggest:
move html code to '.tpl.html' files
use 'templateUrl' instead of 'template'
And check if the following is suitable for you:
$stateProvider.state("daveonly", {
views: {
"dave": {
templateUrl: 'daveonly.tpl.html',
},
"pete": {
templateUrl: 'pete.tpl.html',
},
"steve": {
templateUrl: 'steve.tpl.html',
},
}
});
Take a look at page1 and page2 for more details.
But from another point of view it could be more useful to use only one ui-view and to redesign current ui-views to become the appropriate directives with controllers/services: usage of directives with controllers/services could help to manage partial reload correctly and to write unit-tests.
Yes it can be done easily with the help of abstract states and yes you are correct ui-router doesn't like direct nested views directly but it works fine if the views are in any child template.
Now consider this main page(index.html)
<body ng-app="app">
<div ng-view=""></div>
</body>
Now this template which will appear in this unnamed view. (parent.html)
<h3>This is the parent template</h3>
<div ng-view="child1"></div>
<div ng-view="child2"></div>
Now the JS file
$stateProvide.state('home',{
url:'/',
abstract:true,
views:{
"":{
templateUrl:'parent.html'
}
}
})
.state('home.child',{
url:"",
views:{
'child1#home':{
templateUrl:'child1.html'
},
'child2#home':{
template:'Child2'
}
}
})
.state('home.child.child1',{
url:"child1#home.child",
views:{
'child1#home':{
templateUrl:'child1viewchange.html'
}
}
});
(Now the manipulation part)
(child1.html)
<button ui-sref="home.child.child1">Child</button>
Now child1viewchange.html pe jana padega and wo dekhne wali hai kaunsi kaisi thi/......
(child1viewchange.html)
<h3>Child1's view change</h3>
So now when we click on the button in child view1 the content in the first view changes and if we assign controllers then they can use them to control data.
i'm setting up a project, and using ui-router.
requirement is to have url which keep on appending eg: #/home/contacts.
In order to achieve that, i have to use the nested states.
eg: home and home.contacts, where home state will have in template which will get populate.
But i want to have a single ui-view at root level, index.html, which will get templates when i will hit on url, eg, home or home/contacts.
Is it possible to get this behaviour with ui-router?
in nutshell, having nested behavior[not nested, i want appending url] with single ui-view at index.html.
Note
Could you specify the URL of the state to be explicitly home/contacts?
See below for an example:
app.config(function($stateProvider) {
var routes = [
{
state: 'home',
config: {
url: '/home',
template: '<h3>Home</h3>'
}
},
{
state: 'contacts',
config: {
url: '/home/contacts',
template: '<h3>Contacts</h3>'
}
}];
routes.forEach(function(route) {
if (route.state) {
$stateProvider.state(route.state, route.config);
}
});
});
View:
<body ng-controller="MainCtrl">
<a ui-sref="home">Home</a>
<a ui-sref="contacts">Contacts</a>
<div ui-view></div>
</body>
Working Plnkr example here.
Angular UI-Router works as expected as long as I do not use nested states. For example, this works:
$urlRouterProvider.otherwise("/marketing");
$stateProvider
.state('marketing', {
url: '/marketing',
templateUrl: 'partials/marketing',
})
.state('landing', {
url: '/landing',
templateUrl: 'partials/marketing-landing',
})
.state('features', {
url: '/features',
templateUrl: 'partials/marketing-features',
})
And this doesn't:
$urlRouterProvider.otherwise("/marketing");
$stateProvider
.state('marketing', {
url: '/marketing',
templateUrl: 'partials/marketing',
})
.state('marketing.landing', {
url: '/landing',
templateUrl: 'partials/marketing-landing',
})
.state('marketing.features', {
url: '/features',
templateUrl: 'partials/marketing-features',
})
In any case where a child URL (ie. /marketing/landing) is loaded either via a sref link or direct URL entry, only the parent partial (partials/marketing) is displayed, despite the address bar changing to the child's URL.
Index.jade:
div(ui-view)
marketing.jade:
h1 marketing layout
div(ui-view)
marketing-landing.jade:
h1 This is the landing page
marketing-features.jade:
h1 This is the features page
This is my first time using AngularUI. Let me know any other relevant information I can provide.
Turned out to be a bug in Jade / bad assumption made by UI-Router (not sure which). From: https://github.com/angular-ui/ui-router/issues/247
Use HTML in your jade file. Jade won't expand it.
First .ui-view - work correct!
But nested ui-view must be markup by plain HTML like this:
.row
.col-md-12
h4 Nested UI-VIEW
<div ui-view></div>
Assigning an empty string to the ui-view attribute seems to work for me. This keeps plain HTML out of the jade template and provides the ability to nest default jade content within the ui-view.
.row
.col-md-12
h4 Nested UI-VIEW
div(ui-view='')
p Using this approach we can have default content before ui-view is loaded