I have two states on my angular app.
First :
.state('profile', {
url: '/:user/:user_id',
templateUrl: 'modules/profile/templates/profile.html',
controller:'profileController',
showClose : 'false',
resolve: {
USERNAME : function($stateParams){
return $stateParams.user;
},
USERID : function($stateParams){
return $stateParams.user_id;
}
}
})
Second :
.state('sub-moments-everyday', {
url: '/moments-everyday/:moment',
templateUrl: 'modules/moments-everyday/templates/ME-submoments.html',
controller:'subMomentsEverydayController',
})
Whenever I typed a valid user and user_id on the profile state there are no problems. But whenever I type /moments-everyday/randomstring it seems like the ui-router is getting confused. It is using the controller and template for the profile state.
Please help. Thanks.
Have you tried checking the order in which the states are placed in the file? /:userid/:username checks for ANY URL that matches that pattern. That pattern contains two variable parameters so when you try and access /moments-everyday/:moments, it sees the /:userid/:username pattern and calls that state.
Try making sure you have your /moments-everyday/:moments pattern BEFORE the /:userid/:username pattern. UI-router starts at the top of the file and checks each pattern going down the file till it finds the first matching pattern.
Related
I have some states which look like this:
.state('patient.patient-login', {
abstract: true,
template: '<ui-view></ui-view>'
})
.state('patient.patient-login.practiceID', {
url: "/patient-login/:practiceID",
scope: true,
templateUrl: "views/patient-login.html"
})
The problem is the :practiceID variable can be quite long and not user friendly, I want to give a user the ability to create a custom URL which is tied to the practice ID, for example on Facebook when you create an account you start out with a profile URL like this: http://facebook.com/123456789 but then you can change it to http://facebook.com/whateveryouwant
So essentially I want to accomplish something like this:
POINTER
http://domain.com/companyname > http://domain.com/#/patient-login/companyid
ANOTHER EXAMPLE
http://domain.com/ladentist > http://domain.com/#/patient-login/-85k3jfGEioltold
I was able to allow a user to set their unique url but I'm not sure how to even start to setup the routing like that?
Not sure what the rest of your project looks like but you could update your state to handle both id's and unique urls in the resolve property. Which would roughly look like this:
.state('patient.patient-login.practiceID', {
url: "/patient-login/:practice",
scope: true,
templateUrl: "views/patient-login.html",
resolve: {
patientData: [
'$stateParams',
'practiceSvc', // replace practiceSvc with however you are fetching data from your server
function($stateParams, practiceSvc) {
// check if the :practice param is an id or unique url
if ($stateParams.practice === /* id check */) {
// Call to API - get practice by ID
return practiceSvc.getByID($stateParams.practice);
} else {
// Call to API - get practice by unique url
return practiceSvc.getBySlug($stateParams.practice);
}
}
]
}
})
This assumes you can tell the difference between a unique url and an id. If you can't do that you could update it to check for the id first then the unique url if no practice is found.
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
I have this simple state :
.state('search', {
url: '/search',
templateUrl: 'views/search.html',
controller: 'search'
})
And I would like to pass any extra unplanned parameters to the controller when using search state or /search route :
ui-sref="search({foo:1, bar:2})"
// would call '#/search?foo=1&bar2',
// match the state and pass foo and bar to the controller (through $stateParams)
When I try this, it matches the otherwise of the router instead. :(
I've read a lot of solutions that imply to declare each parameter in the state:
.state('search', {
url: '/search?param1¶m2¶m3?...',
})
But I cannot do this as far as the parameters list is not really defined and changes all the time depending on searched content.
Is there a way to achieve this ? Or am I wrong somewhere ?
Thx.
EDIT : When I try to call directly this url : #/search?foo=1, the state search matches but the foo parameter never goes to $stateParams which is empty. I don't know how to get it in.
.state('search', {
params: ['param1','param2','param3'],
templateUrl: '...',
controller: '...'
});
ui-sref="search({param1:1, param2:2})"
Credit goes to Parameters for states without URLs in ui-router for AngularJS
I'm currently working on a small application that shows a 'drill down' type of menu. Unlike a TreeView my component only displays the current level.
There are only 3 levels: main, submenu, item. Drilling deeper (on the item) will result in a new state that corresponds to a detail view of the selected item.
I have only 2 states, the first is valid for any of the three levels. The second is the detail state:
$stateProvider.state('menu', {
url: '/menu/:submenu/:item',
templateUrl: 'src/menu/views/menu.html',
controller: 'MenuController',
controllerAs: 'MenuController',
resolve: {
data: function($stateParams, MenuService){
return MenuService.loadUri($stateParams);
}
}
}).state('menu.details', {
url: '/:selectedItem',
templateUrl: 'src/menu/views/menu-details.html',
controller: 'MenuDetailsController',
controllerAs: 'MenuDetailsController',
resolve: {
data: function($stateParams, MenuService){
return MenuService.loadUri($stateParams);
}
}
});
This solutions works correctly, however I'm a bit annoyed by the fact I need to define the resolvemethod twice. I am required to do this as $stateParams contains only the params of that exact state (excluding child states) and I need all parameters to form a valid URL to fetch the corresponding resource via the MenuService.
I know that state.params can be used to get all state params, however it doesn't seem to work in the resolve method: it contains the parameters of the previous state.
Does anybody know how I could fix this? Having a child state that should simply trigger a new view, whilst using the resolve method of the parent state with all state parameters?
If you think I'm completely misunderstanding how states work, then please go ahead and tell me :)
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.