-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trailing slash in url breaks state routing #50
Comments
Edit: mapping optional trailing slashes is default behaviour in Angular $routeProvider: angular/angular.js#784
To understand why it's not the default behaviour to map URIs, consider that it's like asking the system to treat the resources
|
@cayuu That is unfortunetly wrong. Angular's Their
And a TestCase testing the behavior:
|
Dude you are right about this. And thanks for the test code. My initial comment stemmed from an active project I was hacking on that is not doing this rewiring (because zombies and god knows what else) - but a simple demo shows it works in practice. Edit: The zombies above happened to be this very project. If you add |
I was going to add support for this in the $route compat layer, but I'd like to hear some use cases for why this feature should be added to $state itself natively. The only case where not redirecting to the correct version (whether that's with slash or without) could cause a problem is if you're expecting users to manually type in or edit URLs. Surely any links should be using the correct canonical version of the URL to begin with. |
To be resolved as part of #17 |
I ended up here looking for a way to deal with the trailing slash issue. I've configured all routes/states to match a trailing slash then I'm using this snippet to redirect if missing.
|
Wow that's great, would you mind if I added that to the FAQ? |
Of course, please do! |
Regarding that snippet, To check for an empty object, use this helper function:
|
Better snippet (a la @tomteman): $urlRouterProvider.rule(function ($injector, $location) {
var path = $location.url();
// check to see if the path already has a slash where it should be
if ('/' === path[path.length - 1] || path.indexOf('/?') > -1) {
return;
}
if (path.indexOf('?') > -1) {
return path.replace('?', '/?');
}
return path + '/';
}); Older snippet: $urlRouterProvider.rule(function($injector, $location) {
var path = $location.path()
// Note: misnomer. This returns a query object, not a search string
, search = $location.search()
, params
;
// check to see if the path already ends in '/'
if (path[path.length - 1] === '/') {
return;
}
// If there was no search string / query params, return with a `/`
if (Object.keys(search).length === 0) {
return path + '/';
}
// Otherwise build the search string and return a `/?` prefix
params = [];
angular.forEach(search, function(v, k){
params.push(k + '=' + v);
});
return path + '/?' + params.join('&');
}); Then all routes in |
@coolaj86 could you also update the FAQ for me?! |
@timkindberg Done. |
Thanks man! |
How does one declare the
Attempting to navigate to either |
Hi Steve. You need to remove the first slash in the child state.
|
Thanks! |
To me solution proposed in FAQ wasn't nice enough, as I didn't want every view to end with slash, I rather wanted to get rid of trailing slash if it has been added. Here's what I ended up with - much simpler, much nicer IMO:
|
Nice! It is preference of course 😉 This working ok with |
It sure does work as it doesn't even touch search part of the url, just replacing path. |
@mwtorkowski, i like your solution...however, I'm not having any luck. My "otherwise" method keeps getting triggered. On login, my default page is @ myApp
.config( ($urlRouterProvider) ->
$urlRouterProvider.rule( ($injector, $location) ->
path = $location.path()
if path isnt "/" and path.slice(-1) is "/"
console.log( path.slice(0,-1) ) # returns path minus trailing "/" as expected!!!
$location.replace().path( path.slice(0, -1) )
return
)
$urlRouterProvider
.when("","/")
.when("/", "/manage/residents")
.when("/manage", "/manage/residents")
.when("/assess", "/assess/to_do")
.otherwise("/errors/404")
) |
Since $location.path() decodes the URL, the suggested solution caused problems for us when using special chars in the path. We came up with a solution which we believe is much cleaner and less disruptive, by using $location.url(), which doesn't affect the path values (i.e - doesn't decode):
|
+1 Nice I updated the wiki too: https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-make-a-trailing-slash-optional-for-all-routes |
This makes the inverse so much simpler as well: $urlRouterProvider.rule(function ($injector, $location) {
var path = $location.url();
// check to see if the path has a trailing slash
if ('/' === path[path.length - 1]) {
return path.replace(/\/$/, '');
}
if (path.indexOf('/?') > -1) {
return path.replace('/?', '?');
}
return path;
}); I didn't test it yet, but does that look right? |
Looks all right to me |
Perfect! @tomteman However I may be wrong but it removes the trailing space and this becomes wrong :
From my test it only works if there is no I put the snippet rule before adding any Of course any .htaccess to add trailing space becomes useless
|
I had to do the following when using @coolaj86 's 'no trailing slash' approach above (change
|
What version are you using? Have you looked at this as another option?
|
Thanks for your response, I updated ui-router to the last version and it works. But I still have to add this option in each module. Also, what strictMode exactly do? |
Fixing trailing slash issue - when navigating from home to any city (ex: boston) and reload the page, somehow '\' is added to the end of location.href, which breaks the routing. This code will remove the trailing slash Taken from angular-ui/ui-router#50 (comment)
I have had an issue with html5mode(true) and has an hash in a url it goes to infinite loop. http%3A%2F%2Fexample.com%2Fposts%2F |
@homerjam your last code snippet in this thread worked great for me! |
The snippet on the FAQ breaks when you This version from @homerjam works, however. |
If you just want to allow "/" at the end of the URL, then you can use regular expression like this:
|
Nice, @snaikaw! |
I found |
@jgentes you just saved my day! Thank you so much! |
Just want to say @jgentes method did not work for me |
@jml6m if you're using Node/Express, this is another approach to remove trailing slashes:
|
I ended up using this method: $urlRouterProvider.rule(function($injector, $location) {
var path = $location.path();
var hasTrailingSlash = path[path.length-1] === '/';
if(hasTrailingSlash) {
//if last charcter is a slash, return the same url without the slash
var newPath = path.substr(0, path.length - 1);
return newPath;
}
}); |
I've found @jml6m's method to be the simplest at getting rid of the trailing slash. |
I've found @jgentes solution to be the best. |
The solutions that add a Since I didn't want to add this to each module's route configuration, I ended up adding a function that does pretty much what @jml6m's solution does to the beginning of the // Check authentication before changing state
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
// Ensure we don't transition to a URL with a trailing slash
preventTransitionWithTrailingSlash(event);
...... // other logic that will execute if no trailing slash is found
});
function preventTransitionWithTrailingSlash(event) {
var path = $location.$$url;
// Check if the current transition has a trailing slash
if (path.length > 1 && path[path.length - 1] === '/') {
event.preventDefault();
// $location.path() needs an async operation to work
$timeout(function () {
$location.path(path.substr(0, path.length - 1));
});
}
} Does anyone see any issues with this approach? I would love a cleaner solution. I find it odd that there isn't an easier way to handle this at an application level. |
Hmm I'm not sure I understand why you can't just use the Also, you can put the snippet in a dedicated module and have all other modules depend on it. |
@stefanotorresi You're absolutely right! I was misinterpreting the behavior I was seeing, as the Rule not getting applied to my sub-modules. There seems to be a couple things going on with the issues that I'm having.
I'm working with the MEANJS project, and I've pushed a branch up to my fork to demonstrate the behavior I'm experiencing. The diffs will show you where I'm having issue, and I've added some inline comments to further explain. I apologize if this is a bit much, but at this point, I could use some more eyes on this; been working on this for over 10 hours now. |
Oh nevermind... it turns out that there's a race condition between |
@mleanos, your fix works for me, but I need to trigger it on |
@javoire ui-router offers deferIntercept for doing things before the URL is synchronized. |
Thanks for the info! I'll try it out
|
|
Hi Now ui-router have strictMode to handle it For more details you can refer this Link |
If the url contains a trailing slash the state routing does not recognize the url and transition to the correct state.
For example, if you define the following state:
When you go to #/contacts it routes to the 'contacts' state correctly, however if you go to #/contacts/ the route is not recognized.
The only workaround I have found is to define a second route which contains the trailing slash with a different name but that is quite cumbersome to have to do for every single state in an application.
Thanks!
The text was updated successfully, but these errors were encountered: