I have three route states - an abstract state, a state that shows the listing and a state that specifically shows a detail of one particular object.
My states are configured as follows:
.state('movies', {
url: "/movies",
template: '<ui-view ng-show="isLoaded" />',
abstract: true,
ncyBreadcrumb: {
skip: true
}
})
.state('movies.index', {
url: "?genres&tags&year&season&page&perpage",
templateUrl: "views/movies.html",
controller: 'MoviesViewController',
ncyBreadcrumb: {
label: 'Movies'
}
})
.state('movies.show', {
url: "/:id/:slug",
controller: 'MoviesItemController',
templateUrl: "views/movies/details.html",
ncyBreadcrumb: {
parent: 'movies.index',
label: '{{item.title_main}}'
}
})
I'd like to add the posibility of movies.index also beginning with a slash, so the URL can either be /movies or /movies/. However with my design, I have no idea how to do that.
I'm also not sure if I understand the concept behind abstract states correctly. I can either use this, or have movies.index be the parent state, in which case, how do I replace its content by the child's template? Also, I have noticed that since the parent controller also gets called, an unnecessary GET request is sent to my API, which can slow things down (especially since it's completely useless information). Can anyone give me a hand in this?
I understand that this use case is supported by $urlMatcherFactory.strictMode(false)
Take a look her
http://angular-ui.github.io/ui-router/site/#/api/ui.router.util.$urlMatcherFactory#methods_strictmode
Related
Edit: Here is the complete code at Plunker. Though I can not c anything in execution but same code working at local. However gives a console error though
It all works perfect. But due to :id in /news/:id/, i am getting jquery/angular errors in console which can not be tracked anywhere in my code
I can not c What i am doing wrong.
Edit: Solved plunker https://plnkr.co/edit/FWcuBgGpVdMj3CroFrYJ
First of all you are trying to use ui-router but you're including ngRoute script in your plunker. Change it to
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.min.js"></script>
Then everything should work fine!
I suggest you a few changes...
1. Use ui-sref instead of href because it's much easier to define
ui-sref="post({id:1})" which turns into href="#/news/1"
If you would like to change url some day, then you will have to just change your route file, not each href.
$stateProvider
.state('post', {
url: "news/:id"
or
$stateProvider
.state('post', {
url: "archive/:id"
or
$stateProvider
.state('post', {
url: "whatever/:id"
2. Use abstract state
In your example it's a way better to define abstract state which holds header, content and footer - it's a typical use case.
ui-router
Abstract States
An abstract state can have child states but can not get activated
itself. An 'abstract' state is simply a state that can't be
transitioned to. It is activated implicitly when one of its
descendants are activated.
Some examples of how you might use an abstract state are:
To prepend a url to all child state urls. To insert a template with
its own ui-view(s) that its child states will populate. Optionally
assign a controller to the template. The controller must pair to a
template. Additionally, inherit $scope objects down to children, just
understand that this happens via the view hierarchy, not the state
hierarchy. To provide resolved dependencies via resolve for use by
child states. To provide inherited custom data via data for use by
child states or an event listener. To run an onEnter or onExit
function that may modify the application in someway. Any combination
of the above. Remember: Abstract states still need their own
for their children to plug into. So if you are using an
abstract state just to prepend a url, set resolves/data, or run an
onEnter/Exit function, then you'll additionally need to set template:
"".
Here's a plunker which shows how I would do it.
https://plnkr.co/edit/5FvJaelyxdl5MuALt5VY?p=preview
Hope it helps.
Look at the documentation for ui router named views,
You can use following syntax for using multiple views
$stateProvider
.state('state',{
url: '',
views: {
'header': {
templateUrl: 'views/header.html',
controller: 'headerCtrl'
},
'content': {
template: '<div ui-view=" "></div>', //<-- child templates loaded to here
},
'footer': {
templateUrl: 'views/footer.html',
controller: 'footerCtrl'
}
}
})
.state('state.post', {
url: 'news/:id/:KeyWords'
templateUrl: 'views/post.html' //<-- This goes into content's ui-view
});
I'm guessing you want to keep the header and footer and change content views.
You can achieve this by making this state as parent to all other states
suppose
.state('main',{
abstract: true,
views: {
'header': ... ,
'content': {
template: '<ui-view></ui-view>',
}
'footer': ...
}
})
then all the child views will load their views in the ,
ex: in main.child etc, your template will load in the content's <ui-view></ui-view> tag
If you need to use a custom template depending on keywords you can do the following:
.config(['$routeProvider',
function($routeProvider, $routeParams) {
$routeProvider
.when('/news/:id/:keyWords', {
template: '<div ng-include="url"></div>',
controller: "exampleController"
})
then in the exampleController
function($routeParams, $scope) {
$scope.url = $routeParams.keyWords;
}
I have an Angular app which has several dynamic fields, each of these fields are changed updated based on config which comes from a backend database.
In order to control what config is used I need to dynamically switch a single variable - I've decided that the URL is the best way to set/switch the variable as there need to be multiple permutations of the site based on the URL so:-
/:dynamicVariable/
I'm looking for some guidance as to whether this is the best way to do it and what the best way to do it would be? I'm struggling as I don't want to have to set each route for each section like this /:dynamicVariable/homepage /:dynamicVariable/about-us etc etc. Ideally the core module checks it and sets it but the routing ignores it so /:dynamicVariable/ becomes the root.
Hope that makes sense, thanks in advance for your help.
I ended up doing this by using ui.router and nesting states within an abstract parent state which held the client, like so :-
.state('rootClient', {
abstract: true,
url: '/:client',
templateUrl: 'app/layout/layout.html',
controller: 'Layout',
controllerAs: 'layout',
noClient: false,
resolve: {
client: function ($stateParams, ClientService) {
return ClientService.getClient($stateParams.client);
}
}
})
.state('rootClient.home', {
url: '/homepage',
views: {
'content': {
templateUrl: 'app/homepage/homepage.html',
controller: 'Homepage',
controllerAs: 'home'
}
}
});
This way all the routes are under the parent route, I also added a resolve to make sure the client exists before moving to the route. Hopefully this will help someone else down the line.
Cheers
we have three pages in our app which can be classified under one parent page as below.
1)Parent
I)Child1
II)Child2
III)ChildIII
.state('Parent', {
url: '/Parent/:ID',
templateUrl: 'parent.html',
controller:'parentcontroller'
})
.state('Parent.Child1', {
url: '/Child1',
templateUrl: 'Child1.html'
})
.state('Parent.Child2', {
url: '/Child2',
templateUrl: 'Child2.html'
})
.state('Parent.Child3', {
url: '/Child3',
templateUrl: 'Child3.html'
})
sometimes we need to call this child pages sequentially one after another from child1 to child3 without parameters and sometimes we need to call those child pages individually but requests needs to go through parent controller so that we do not have to instantiate new controller instance for each one of those child pages. to accomplish this i'm using href but i want to be able to call parent and child with out passing any params.
working href ex: <a href='../Parent/{{ID}}/child1'
Not working ex: <a href='../Parent/child1'
can anyone please guide me to accomplish this?? Thanks!!
solution:
.state('Parent', {
url: '/Parent/:ID',
templateUrl: 'parent.html',
controller:'parentcontroller',
params:{ID:null}
})
.state('Parent.Child1', {
url: '/Child1',
templateUrl: 'Child1.html'
})
.state('Parent.Child2', {
url: '/Child2',
templateUrl: 'Child2.html'
})
.state('Parent.Child3', {
url: '/Child3',
templateUrl: 'Child3.html'
})
From HTML:<a ui-sref="(Parent.Child1{ID:{{value}}})">Home</a>
i wasn't aware that if we use SREF as above and controller declared at parent value can still read the params but gave a shot and it worked!!
Yes, you can do this. First you should define your params in your .state(), if you are passing params to child1 state, then it should defined by like below,
.state('Parent.Child1', {
url: '/Child1',
templateUrl: 'Child1.html',
params: {
paramName: '' //here paramName can be named by your wish.
}
})
after this you should pass the call the state and pass param in ui-sref like below,
<a ui-sref="Parent.Child1({paramName: scopeName})">Click</a>
here scopeName is the name of the scope which have the value to param, if you want hard code a string, then you can pass in qoutes, ({paramName: 'some string'})
I'm a little confused about what you're asking, but the way it sounds is that all the pages use the same controller. If that's the case, just let them. Controllers will eventually be destroyed when they are no longer needed, so instantiating a new one is fine. If you're routing to a new page, it's going to look for the accompanying controller.
--Edit based on OP's comment--
If the goal is to only get data once, you can store that in a service. Every service is a singleton, so if you grab data and save it in your service, you can inject that service elsewhere and have access to it.
I am using Angular UI-Router and need to have a single parent state that several other states can inherit the results of a resolve from. I have tried every solution found here on SO for this but NOTHING is working. My states look like this:
.state('transaction', {
abstract:true,
url: '/register/pos/:screen/:document_sid',
template:'<div ui-view></div>',
resolve: {
Document: //the thing I need to have all the children access
}
})
.state('transaction.view', {
url:'',
views:{
'':{
templateUrl: '/views/docs/pos-transaction-outer-partial.htm',
controller:'posdocumentController'
}
}
})
.state('transaction.edit', {
url: '/:mode',
views:{
'':{
templateUrl: '/views/docs/pos-transaction-outer-partial.htm',
controller:'posdocumentController'
}
}
})
.state('transaction.returns', {
url: '/returns',
views:{
'':{
templateUrl: '/views/pos-itemreturn-partial.htm',
controller: 'posItemReturnsController'
}
}
})
When I use $state.go('transaction.edit') it works perfectly. Inside the 'posdocumentController' I have a function that calls $state.go('transaction.returns') and I can see the route change and the partial is requested, but the view never changes. According to the docs for multiple named views the specified views should load in the parents ui-view that is contained within the template. Obviously, for me this is not happening and for the life of me I have not been able to figure out why. I've tried this both with and without the views option and get the same results. Can someone explain why and how I fix this?
In details is hidden... in very small detail, in this case.
I. Why not working?
Here is a plunker with broken navigation (exactly as described in the question above)
These would be the calls to the above states:
ui-sref
transaction.view ({ screen: 1 ,document_sid:2 ,mode:5 })
transaction.edit ({ screen: 1 ,document_sid:2 ,mode:5 })
transaction.returns ({ screen: 1 ,document_sid:2 ,mode:5 })
href
#/register/pos/1/2
#/register/pos/1/2/5
#/register/pos/1/2/returns
so, while these could seem as proper state calls, the last two, edit and returns, could be observed as:
// edit link result
params
{
"screen": "1",
"document_sid": "2",
"mode": 5
}
state
{
"url": "/:mode",
...
// returns link result
params
{
"screen": "1",
"document_sid": "2",
"mode": "returns"
}
state
{
"url": "/:mode",
Now it should be clear. The third link (to state returns) is in fact navigating to edit again. Why? because of this states definition:
.state('transaction.edit', {
url: '/:mode', // here we say :mode is param
...
.state('transaction.returns', {
url: '/returns', // and 'returns' here is already mapped... above as :mode
Check the not working solution here
II. How to make it working
There is a link to working plunker. The change made is:
firstly define returns and then edit state
.state('transaction.returns', {
url: '/returns', // 'returns' would be evaulated first, and used
...
.state('transaction.edit', {
url: '/:mode', // only other then returns values will be used here
Working solution is here
Other solution, maybe better, would be to use some regex... to narrow :mode values: Regex Parameters
'/user/{id:[^/]*}' - Same as '/user/{id}' from the previous example.
'/user/{id:[0-9a-fA-F]{1,8}}' - Similar to the previous example, but only matches if the id parameter consists of 1 to 8 hex digits.
'/files/{path:.*}' - Matches any URL starting with '/files/' and captures the rest of the path into the parameter 'path'.
'/files/*path' - Ditto. Special syntax for catch all.
I'm using ui-router 0.2.10. My application has two different templates, index.html & index2.html. I've created an abstract state, and i'm referencing both indexs' in their respective states, The problem is I can access the first route fine, but when I try to access the next route it just keeps defaulting to the first route. The abstract templates live in the same folder.
What am I missing here?
.config(["$stateProvider", "$urlRouterProvider", function(sp, urp) {
urp.otherwise("/index1");
sp.state("index1", {
abstract:true,
url: "/index1",
templateUrl: "index.html"
});
sp.state("index1.id", {
url: "/id",
template: "views/partials/index.partial.html",
controller: function($scope,$state){
$state.go('index1.id');
}
});
sp.state("index2", {
abstract:true,
url: "/index2",
templateUrl: "index2.html"
});
sp.state("index2.id", {
url: "/id",
template: "views/partials/index2.partial.html",
controller: function($scope,$state){
$state.go('index2.id');
}
});
}])
I'm assuming that you're trying to go to an abstract state and that won't work as abstract states will only be activated when you go to a child of that abstract state, i.e. you can't direct go to index1 or index2, so this is not legal:
urp.otherwise("/index1"); it should be: urp.otherwise("/index1/id"); instead.
also why are you going to the states again within their own controller? $state.go('index2.id'); is pointless since by the time that line of code is reached you are already in the state index2.id. I think you meant to put those lines of code inside the controllers of the abstract states! Last bit not least don't forget that your abstract states MUST have a ui-view themselves as they are hosting child states.
See plunk.