25

I'm building a new angularJS app, based from the AngularJS SPA Visual studio template (http://visualstudiogallery.msdn.microsoft.com/5af151b2-9ed2-4809-bfe8-27566bfe7d83)

this uses ui-router (https://github.com/angular-ui/ui-router) for its routing.

however, it seems to be case sensitive.

Any idea how I would instruct angular/ui-router to ignore the case of the url parameter?

case sensitivity doesn't matter while in the app, though should a user type a url to enter the application at a specific page, we need to ensure that about is also the same as aBouT

Cheers

Darren Wainwright
  • 30,247
  • 21
  • 76
  • 127

4 Answers4

30

You can now configure ui-router to be case insensitive directly. Here is how you can use it:

angular.module('main', ['ui.router']);

angular.module('main').config(['$urlMatcherFactoryProvider', '$stateProvider', '$urlRouterProvider',
  function($urlMatcherFactory, $stateProvider, $urlRouter) {
    $urlMatcherFactory.caseInsensitive(true);
    $urlMatcherFactory.strictMode(false);
    $stateProvider.state('foo', {
      url: '/foo',
      template: '<b>The Foo View</b>'
    });
    $stateProvider.state('bar', {
      url: '/bar',
      template: '<b>The Bar View</b>'
    });
    $stateProvider.state('nomatch', {
      url: '/nomatch',
      template: '<b>No match found View</b>'
    });

    $urlRouter.otherwise('/nomatch');
  }
]);

In the latest release (0.2.11), this is broken. A fix has been pushed already that can be seen at Github. So, currently, the best solution is to clone ui-router and build the head of master manually. Alternatively, you can just alter the source manually until the next release comes.

UPDATE (11/18/2014):

A release has now been made that incorporates the fix from above so that you no longer have to pull source and build manually. You can view the release on Github or just get the latest build.

kmkemp
  • 1,656
  • 3
  • 18
  • 21
15

Following the link in the comments to the original question, i was able to get the answer I needed.

Before my $stateProvider.state(......) routes I now have this piece of code:

$urlRouterProvider.rule(function ($injector, $location) {
       //what this function returns will be set as the $location.url
        var path = $location.path(), normalized = path.toLowerCase();
        if (path != normalized) {
            //instead of returning a new url string, I'll just change the $location.path directly so I don't have to worry about constructing a new url string and so a new state change is not triggered
            $location.replace().path(normalized);
        }
        // because we've returned nothing, no state change occurs
    });

Essentially it will toLowerCase() a url that isn't all lowercase already.

Once done, it replaces the url rather than redirects. Then carries on with matching a state.

Darren Wainwright
  • 30,247
  • 21
  • 76
  • 127
  • As of version 0.2.12 and later, this can be accomplished with a single line without rewriting the URLs. See @kmkemp's answer. – Matt DeKrey Apr 02 '15 at 01:35
  • Ageed with@MattDeKrey doing this will result in having $stateChangeSuccess trigger twice because of the rewriting of the url. Just put $urlMatcherFactory.caseInsensitive(true); in the run() function – Axel Oct 01 '15 at 15:30
  • @Axel - StateChangeSuccess won't fire twice. It only fires once. Also mentions this in the comment in the code – Darren Wainwright Oct 01 '15 at 19:34
  • @Darren well, it happened to me just today, with the above code, using go(state) triggered twice stateChangeSuccess one with lowercase toParam and one with uppercase toParam....Commenting the line $location.replace().path(normalized); stopped this beviours... – Axel Oct 01 '15 at 19:58
3

You shouldn't change how ui-route handles URL matching to accept case insensitive URLs (that will have unexpected problems), but you can attempt to correct URLs for the user automatically when the routes fail.

When ui-route can not match a URL to a route it triggers the otherWise() callback. I'll show you have to redirect using this callback.

The following makes the assumption that all URLs for your app should be in lower case.

var stateHandler = function($urlRouterProvider)
{
    $urlRouterProvider.otherwise(function($injector, $location)
    {
        var url = $location.absUrl();
        var redirect = url.toLowerCase();
        if(url == redirect)
        {
             return;
        }
        $window.location = redirect;
    });
};

YourAngularApp.config(['$urlRouterProvider',stateHandler]);

If you need more control, then use a regex to select which URLs need rewriting.

Reactgular
  • 52,335
  • 19
  • 158
  • 208
  • I'm not sure how this really differs from the method I ended up using (via the link in the question comments - `$urlRouterProvider.rule()` - other than the rule will apply any changes before attempting to find a route. Where as your solution is first checking all known routes, then changing the url and then redirecting. – Darren Wainwright Sep 19 '14 at 16:35
  • And by the way - you would want to use `$window` vs `window` to keep it all 'within' angualr. – Darren Wainwright Sep 19 '14 at 16:36
  • @Darren Yea I only saw the link in the comment after I posted. I'd go with `rule()` – Reactgular Sep 19 '14 at 16:36
  • ah ok :) I supposed I should put an answer in here to help others :) - i'll do that now... – Darren Wainwright Sep 19 '14 at 16:42
-2

According to official wiki,

https://github.com/angular-ui/ui-router/wiki/URL-Routing

Darren's answer looks right:

app.config(function ($urlRouterProvider) {
  // Here's an example of how you might allow case insensitive urls
   $urlRouterProvider.rule(function ($injector, $location) {
   //what this function returns will be set as the $location.url
    var path = $location.path(), normalized = path.toLowerCase();
    if (path != normalized) {
        //instead of returning a new url string, I'll just change the $location.path directly so I don't have to worry about constructing a new url string and so a new state change is not triggered
        $location.replace().path(normalized);
    }
    // because we've returned nothing, no state change occurs
});}
ApiFox
  • 123
  • 1
  • 5