I'm using Angular's ui-router on my application to try and route to child views of a main view. Both the main and the child have their own associated IDs. Currently I can navigate to the parent, but my link to the child is not working.
In my Application.js
$stateProvider
//Working Route
.state('Project', {
url: '/Project/{projectId}',
views: {
"ContentMain" : {
templateUrl: "/Scripts/Dashboard/templates/MainContent/ProjectMainContent.html",
controller: function ($stateParams) {
console.log("Project state hit!");
}
},
...
}
})
//Non-Working Route
.state('Project.ViewResource', {
url: '/Resource/:resourceId',
parent: 'Project',
views: {
"ContentMain" : {
templateUrl: "/Scripts/Dashboard/templates/MainContent/ProjectResourceViewContent.html"
controller: function ($stateParams) {
console.log("Project.ViewResource state hit!");
}
},
...
}
});
In my HTML:
<!-- Working Link-->
<a ui-sref="Project({ projectId: 5 })"><h3> My Projects </h3></a>
<!-- Non-working Links -->
<a ui-sref="Project.ViewResource({ projectId: 5, resourceId: 3 })">View Project Resource. </a>
<a ui-sref="Project.ViewResource({ resourceId: 3})">I'm a Resource Image. </a>
The first link works, however when I click either of the "non-working" child links my browser updates to: "Home/Index/#/Project/5/Resource/3" which is the desired route, however the page content
Any idea where I'm going wrong?
Edit1: To add the lines of code in the 'views' object which should be swapping out.
Edit2: To further demonstrate the issue, I've added the controller code blocks. When I hit the first html link, my console outputs "Project state hit!" When I click either of the non-working links, there is no new output to the console. Ie, the route is likely not being hit.
Figured out what was happening. After taking a closer look at the document on multiple named views here, I realized that my child view was searching for ui-view tags within the parent template, rather than the root template. Essentially, my child was trying to nest within my parent, while my desired behavior was to replace the parent views.
So, to target ui-views within the root, my solution looked like:
.state('Project.Resource', {
url: '/Resource/{resourceId}',
parent: 'Project',
views: {
"MainControls#": { templateUrl: "/Scripts/Dashboard/templates/MainControls/MainControls.html" },
"ContentMain#": {
...
},
...
}
})
Related
My UI includes nested tabs (using Bootstrap). The tab in question is a template with its own controller, currently specified on a view with UI-Router:
.state('editBase.edit', {
url: '/:id',
views: {
'fooTab#editBase.edit': {
templateUrl: 'foo.html',
controller: 'FooController'
},
// more views...
The template uses ng-repeat to create a list of links. Each link goes to an editor child state:
<a ui-sref="editBase.edit.subEdit({itemId: item.id})">{{item.name}}</a>
What I want to happen when the link is clicked is for the contents of the tab (the list) to be replaced with the editor. On clicking a save button, the list would reappear refreshed.
I'm not looking for an in-place editor for a list; I want to hide the entire list, but leave the surrounding templates/tabs intact. In other words, I don't want to replace the root view. How can I do this?
Note: I found this post that explains multiple nested views and view names; this helped me a lot.
In the edit state, create a view that targets the list's <ui-view>
A parent state, just for demonstration. The parent state has a ui-view that the list state plugs into
$stateProvider.state({
name: 'app',
template: '<div ui-view="list"></div>'
});
The list state targets the <ui-view="list">, which was created by the parent state
$stateProvider.state({
name: 'app.list',
url: '/objects',
views: {
list: {
controller: ...
template: `<ul><li ng-repeat="..."></li></ul>
}
}
});
The edit state targets the <ui-view="list"> that was created by the app state. The ui-view was previously filled in by the app.list state. However, the child state's view targeting that ui-view takes precedence over the parent state view.
$stateProvider.state({
name: 'app.list.edit',
url: '/edit/:id',
views: {
"list#app": {
controller: ...
template: "<a ui-sref="^">Go back...</a><form>...</form>"
}
}
}) ;
Here's a working plunker that demonstrates it: http://plnkr.co/edit/Uc39R2ZHUg2Ru3xyEkfe?p=preview
What I am trying to achieve:
In the template of the main state (/model), I have links to a child state phase (/phase), but I also want to be able to link from the main state directly to a given child state of a given phase (/phase/1/task1).
My config:
$stateProvider
.state('model', {
url: '/model',
views: {
'': {
templateUrl: 'model.tpl.html',
controller: 'modelController'
}
},
})
.state('model.phase', {
url: '/phase/{phaseId:int}',
views: {
'#main.model': {
templateUrl: 'model.phase.tpl.html',
controller: 'phaseController'
}
}
})
.state('model.phase.task', {
url: '/task/{taskId:int}',
controller: 'taskController'
})
};
In model.tpl.html I list out all the phases with general information, and for each phase, I list out tasks from that phase like so:
<div ng-repeat="task in tasks | filter:{primary:true, knowledgeAreaId:area.id, phaseId:phase.id}:true" class="task" ng-class="{ active: task.active }">
<div class="task__content" ui.sref="LINKHERE"></div>
</div>
And it is here I want to build a link that goes directly from the main model page to a given child page for a given phase.
What I have tried in model.tpl.html is to add ui.sref like so
<a ui.sref=".phase({ phaseId: task.phaseId}.task({ taskId: task.taskId})">
But that gives me an error, so it seems that you cant 'chain' states with properties.
If I only wanted to link to a phase, then the following works just fine:
<a ui.sref=".phase({ phaseId: task.phaseId}">
Is there any 'correct' soloution in ui.router for this scenario, or do I have to manually build a string for the href value. That way I change the url to the route I want instead of changing to a given state. It seems wrong to do that, when everything else works by switching states.
Something like:
http://localhost/#/model/phase/1/task1
This should work:
ui.sref=".phase.task({ phaseId: task.phaseId, taskId: task.taskId })"
I have tried several examples on using the ui-router and the state manager. My nested views and routes are not working as I hoped. Here is an example of how I am configuring the states:
$stateProvider
.state("main", {
abstract: true,
url: "/main",
views: {
"layout": {
templateUrl: "main.index.html"
},
"mainNavigation#main": {
templateUrl: "main-navigation-partial.html"
}
},
onEnter: function() {
console.log("enter main");
}
})
.state("main.dashboard", {
url: "/dashboard",
views: {
"container#main": {
templateUrl:"main-dashboard.html"
}
}
});
As you can see, I have an abstract state named main. All main views will use the mainNavigation view. There is also a container view area where the content for each section will reside. There is an index.html that will be used by all states. So, I may, down the road have an abstract state name client with accompanying states and views.
I can see the individual html files being loaded, but the views are not being populated in the correct named view areas. I have created a plunk that demonstrates how I want to manage my templates and views.
Your main state is loading main.index.html into a ui-view named layout. In your plunker, your root ui-view is unnamed. So to fix this, add a name to that ui-view.
http://plnkr.co/edit/xKDcuk99OACQR73LR0hf?p=preview
<div ui-view='layout'>
Or, you could leave the ui-view unnamed and change the view to reflect that.
"": {
templateUrl: "main.index.html"
}
For more on view naming, see the ui-router wiki.
I'm new to using Angular UI Router and I seem to be having difficulty being able to update a parent view from it's child view.
I have the following HTML structure (restructured for easier reading, obviously views are in separate html files).
<div ui-view="main">
{ main content }
<div ui-view="tab">
{ tabbed content }
</div>
</div>
Inside tab I have the following sref:
<span ui-sref="silverstone.platforms.view({_id: platform._id})">{{platform.name}}</span>
And here are my states: (I'm using webpack, hence require)
$stateProvider
.state('silverstone', {
url: '/silverstone',
views: {
'main': {
controller: 'SilverstoneCtrl',
template: require('./templates/index.html')
}
}
});
$stateProvider
.state('silverstone.platforms', {
url: '/platforms',
views: {
'tab': {
controller: 'SilverstoneCtrl',
template: require('./templates/platforms.html')
}
}
});
$stateProvider
.state('silverstone.platforms.view', {
url: '/:_id',
views: {
'main': {
controller: 'SilverstoneCtrl',
template: require('./templates/platform-view.html')
}
}
});
When the above sref is clicked, the "main" view needs to be updated. The URL is updating but the views aren't...?
I was missing # in my silverstone.platforms.view state to explicitly address the parent view.
$stateProvider
.state('silverstone.platforms.view', {
url: '/:_id',
views: {
'main#': {
controller: 'SilverstoneCtrl',
template: require('./templates/platform-view.html')
}
}
});
Use reload: true parameter in yout ui-sref links like this.
ui-sref="silverstone.platforms.view({_id: platform._id})" ui-sref-opts="{reload: true}"
Edit:
Maybe your problem are caused by nested states combined with flat template structure.
Other solution may be to properly nest your templates, as states.
For example we have states app and app.substate, then we have two templates for both states. Tempalte of app state contains ui-view directive. (that means every state contains new ui-view directive for injecting of substate template). States are nested by default, this would represent appropriately nested templates.
I am using Angular UI Router and seem to be experiencing an odd issue. When I click a link that has a ui-sref directive attached to it, it successfully loads the new view as I would expect, HOWEVER, it does not update the URL bar. I believe this is ocurring because the parent state's url is a dynamic StateParam /:room. How do I get around this issue?
Here is a snippet of my UI Router
// Room
.state({
name: 'room',
url: "/:room",
views: {
"main": {
templateUrl: "views/pages/chat.html",
controller: "RoomCtrl"
},
"login#room": {
templateUrl: "views/partials/_login.html"
},
"navigation#room": {
templateUrl: "views/partials/_navigation.html",
controller: "NavigationCtrl"
}
},
resolve: {
userLocation: function(geolocationFactory) {
return geolocationFactory;
}
}
})
// Share
.state({
name: 'room.share',
url: "/share",
views: {
"share#room": {
templateUrl: "views/partials/_share.html",
controller: "ShareCtrl"
}
}
});
ui-sref
<button id="share-button" ui-sref="room.share">Share</button>
I created a plunker to demonstrate what is happening
So we can navigate among rooms like this:
<a ui-sref="room({room:1})">room 1</a>
<a ui-sref="room({room:2})">room 2</a>
<a ui-sref="room({room:3})">room 3</a>
this will in fact creat the url like this
#/1 // where 1 represents the id of the :room
#/2
#/3
Now, we can navigate to the substate .share without specifying the :room id
<a ui-sref="room.share">room.share</a>
And what will happen? Firstly the place for :room will be empty ... no room is selected.
Secondly - the previously selected room (its :room id) won't be changed. So the resulting URL will depend on the already selected room. If we were in a room 2, the generated url will be:
#//share
but we will be redirected to
#/2/share
becuase there is still $stateParams.room === 2
Finally, we should always pass the complete state signature:
<a ui-sref="room.share({room:1})">room.share({room:1})</a>
<a ui-sref="room.share({room:2})">room.share({room:2})</a>
<a ui-sref="room.share({room:3})">room.share({room:3})</a>
Check that all here (click the top right corner blue icon to open the prview in sepearate window with url)
I had this problem because my parameter names did not match my URL definition.
For example, I had a parameter set like this:
{
page: {...},
results: {...},
sort: {...},
}
...and a URL like this:
url: '/foo?page&results&orderby'
After fixing the mismatch between sort and orderby, the address bar updated as expected.