This should be simple but I just can't figure it out.
I have two routes:
$stateProvider
.state('users', {
url: '/users',
views: {'#': {
templateUrl: 'templates/users.tpl.html',
controller: 'UsersCtrl as users'
}}
})
.state('users.edit', {
url: '/{userId}',
views: {'#': {
templateUrl: 'templates/editUser.tpl.html',
controller: 'EditUserCtrl as editUser'
}}
});
This works fine if you use a ui-sref or $state.go to navigate to the "users" state by name, but if you type domain.com/users/ into the URL bar it goes to the edit state with empty userId parameter even though there is nothing after the trailing stash.
Normally this wouldn't be a problem but firing the editUser route with no userId causes console errors which would be a pain to fix.
Is this easily fixable?
Take a look to this post:
https://github.com/angular-ui/ui-router/issues/50
and this link referenced in the post:
https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-make-a-trailing-slash-optional-for-all-routes
Your states definition should be
$stateProvider
.state('users', {
url: '/users',
views: {'#': {
templateUrl: 'templates/users.tpl.html',
controller: 'UsersCtrl as users'
}}
})
.state('users.edit', {
url: '/edit/{userId}',
views: {'#': {
templateUrl: 'templates/editUser.tpl.html',
controller: 'EditUserCtrl as editUser'
}}
});
your child state url should be '/edit/{userId}'. When we create a child state its url automatically added its parent state url. So if your url is '/{userId}' it will be 'domain.com/users/{userId}'. That's why for domain.com/users/ its navigate to the state users.edit with null parameter value.
https://github.com/angular-ui/ui-router/wiki/nested-states-%26-nested-views
Related
I'm new angularjs student.
I'm using state provider in my project, i don't want to change this. Because the code is done.
Here is my code:
function config($stateProvider, $urlRouterProvider) {
$urlRouterProvider
.when('/SecondMain', '/SecondMain/OtherPageOne')
.when('/Main', '/Main/PageOne')
.otherwise("/notfound")
$stateProvider
.state('Main', {
abstract: true,
url: "/Main",
templateUrl: "/templates/Common/Main.html"
})
.state('SecondMain', {
abstract: true,
url: "/SecondMain",
templateUrl: "/templates/Common/SecondMain.html"
})
.state('notfound', {
url: "/NotFound",
templateUrl: "/templates/Common/NotFound.html"
})
.state('Main.PageOne', {
url: "/Main/PageOne",
templateUrl: "/templates/Main/PageOne.html"
})
.state('Main.PageTwo', {
url: "/Main/PageTwo",
templateUrl: "/templates/Main/PageTwo.html"
})
.state('SecondMain.OtherPageOne', {
url: "/SecondMain/PageOne",
templateUrl: "/templates/SecondMain/OtherPageOne.html"
})
.state('SecondMain.OtherPageTwo', {
url: "/SecondMain/PageTwo",
templateUrl: "/templates/SecondMain/OtherPageTwo.html"
})
angular
.module('inspinia')
.config(config)
.run(function ($rootScope, $state) {
$rootScope.$state = $state;
});
}
I want a logic like this: If the user put:
/Main/PageThree
This page does not exist, but the user start URL with
/Main
so that he need to go to -> /Main/PageOne
if the user put:
/Ma/PageOne
/Ma does not exist, the user starts URL totally wrong, so that he goes to -> /Notfound Basically if the user put /Main/WRONG_LINK, he go to /Main/PageOne . And if he does not start with /Main, he go to NotFound.
Can anyone help me please?
Thanks a lot!!!
You are missing this configuration
$urlRouterProvider.otherwise('/NotFound');
Just add this line if no matching route is found then it will redirect you to the /NotFound url
This answer is inspired by this answer.
First of all, you will have to make the Main state non-abstract, so that it can be visited. Then, you can write config related to where you want to redirect (for example, I've used redirectTo with the state):
$stateProvider
.state('Main', {
redirectTo: "Main.PageOne",
url: "/Main",
templateUrl: "/templates/Common/Main.html"
})
// ... Rest of code
So, whenever the URL is changed to /Main, this state will get activated. The second config will be to create a listener for $stateChangeStart event as follows:
angular
.module('inspinia')
.config(config)
.run(function ($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function(evt, to, params) {
if (to.redirectTo) {
evt.preventDefault();
$state.go(to.redirectTo, params, { location: 'replace' })
}
});
});
Now, if a URL like /Ma/* is hit, it automatically be redirected to /NotFound. And if a URL like /Main is hit, it will redirect to /Main/PageOne.
You can follow up on further discussion on this link for any kind of troubleshooting.
Clearly read the statements below
Why are you using this line?
when('/Main', '/Main/PageOne')
For your redirection problem, have a look at the below state
.state('Main', {
abstract: true,
url: "/Main",
templateUrl: "/templates/Common/Main.html"
})
abstract: true ==> This denotes that this particular state is an abstract which can never be activated without its child.
SOURCE: ui-router js code. Refer the below snippet
Since you have this main state as abstract, you are redirected to the otherwise.
Hope this
My question is simple, but I couldn't find solution anywhere else.
For example I have a normal route state with parameter,
.state('page', {
url: '/page/:pageid',
templateUrl: 'templates/pages.html',
controller: 'pagesCtrl'
})
However for example, if I have 1000 pages, but for the Number 1 and Number 999 pages I have to use another template. How could I simply do this? Something like
.state('page', {
url: '/page/:pageid',
templateUrl: 'templates/pages.html',
controller: 'pagesCtrl'
})
.state('page', {
url: '/page/1',
templateUrl: 'templates/page1.html',
controller: 'pagesCtrl'
})
.state('page', {
url: '/page/999',
templateUrl: 'templates/page999.html',
controller: 'pagesCtrl'
})
Will this work?I tested, the later 2 options are not overriding the original state with parameter.
If I wish to use the same controller, how to load the 1 and the 999 as the pageid parameter in the controller?
Definitely you shouldn't have two more state for separate template. You should use single generic state which will take templateUrl with the help of passed state parameter.
Code
.state('page', {
url: '/page/:id',
templateUrl: function($stateParams){
var template = $stateParams.id.indexOf([1, 1000]) > -1?'pages.html'
:'page'+$stateParams.id+'.html';
return 'templates/'+template ,
}
controller: 'pagesCtrl'
})
I'm using UI-Router module for routing. I have 2 states that router should match the urls with them according to nested routes laws :
// Dashboard
.state('dashboard', {
url: "/dashboard",
templateUrl: "dashboard/views/index.html",
controller: "DashboardController",
...
})
// Users
.state('users', {
url: "/users",
templateUrl: "users/views/index.html",
controller: "UsersController",
...
})
// Single User
.state('users.id', {
url: "/{id:(?:[a-z0-9_-]{3,16})}",
templateUrl: "users/views/show.html",
controller: "UserController",
...
})
also I have set a default route :
$urlRouterProvider.otherwise("/dashboard");
Problem :
when I go to http://127.0.0.1:8000/app/#/users/testuser123, it shows index.html from users state instead of show.html from users.id state. What's the Problem ?
You should add users within your url definition for users.id if you call http://127.0.0.1:8000/app/#/users/testuser123
.state('users.id', {
url: "/users/{id:(?:[a-z0-9_-]{3,16})}",
templateUrl: "users/views/show.html",
controller: "UserController",
...
})
I am using UI-Router in my angular Meteor project.
When I am in route /search and want to relocate to /search/:term (for example /search/starwars) and I use in my controller
$state.go( 'private.search.feed', { term: 'starwars' } )
then it URL in my browser turns in to /search/search/starwars instead of /search/starwars.
My route setup (I have 2 layouts, hence the abstract views)
$stateProvider
# abstract views / layout
.state 'private',
url: ''
abstract: true
views:
'app':
templateUrl: 'client/views/layouts/privateLayout.html'
.state 'public',
url: ''
abstract: true
views:
'app':
templateUrl: 'client/views/layouts/publicLayout.html'
# end abstract views / layout
.state 'private.home',
url: '/'
views:
"container#private":
templateUrl: 'client/views/home/home.html'
.state 'private.search',
url: '/search'
views:
"container#private":
templateUrl: 'client/views/search/search.html'
controller: 'searchCtrl'
.state 'private.search.feed',
url: '/search/:term'
views:
"container#private":
templateUrl: 'client/views/search/feed/feed.html'
controller: 'searchCtrl'
When I change the route to
.state 'private.searchFeed',
url: '/search/:term'
views:
"container#private":
templateUrl: 'client/views/search/feed/feed.html'
controller: 'searchCtrl'
and call
$state.go( 'private.searchFeed', { term: 'starwars' } )
the url is correct.
I reckon I defined a child state in the first setup, but I don't understand why it would repeat search in the URL.
Any thoughts?
You private.search.feed state url should be '/:term' because the URL of parent state gets inherited in state derived from it. As your derived state has to be like /:term will apparently become/accessible via /search/:term
Code
.state 'private.search.feed',
url: '/:term'
views:
"container#private":
templateUrl: 'client/views/search/feed/feed.html'
controller: 'searchCtrl'
Using a dot in the name of a state indicates to ui-router that it is a child state of whatever state is defined by the dotpath. For example:
State 1: home (/home)
State 2: home.dashboard (/home/dashboard)
State 3: home.dashboard.settings (/home/dashboard/settings)
You cannot create a new state State 4 called home.dashboard.settings.save whose route does not begin with the URL given to State 3, as State 4's dotpath indicates that it should inherit from State 3.
So you need to ensure that a URL for a child state does not repeat the URL of its parent:
.state 'private.search.feed',
url: '/:term'
How i can go to a state and add query params to the url at the same time?
Lets say i have this state:
$stateProvider
.state('cart', {
templateUrl: 'client/cart/cart.html',
url: '/my-cart',
controller: 'CartController'
})
I want from some views to $state.go('cart') and from some views to $state.go('cart') but with query params added to it like, /cart?purchase=complete
So i found the answer, i hope it will help for someone else.
$stateProvider
.state('cart', {
templateUrl: 'client/cart/cart.html',
url: '/my-cart?purchase',
controller: 'CartController'
});
And then:
$state.go('cart', {'purchase': 'complete'});
The results will be:
my-cart?purchase=complete
try this
$state.go('cart', {'purchase': 'complete'});