3

I have a couple of routes in my AngularJS app, I'm using UI-Router for routing between states/pages in my site. An issue I am having is that I have conflicting routes because of a optional parameter I have/need for the homepage of the site.

I have a route for the homepage(example.com) defined more or less like so:

$stateProvider
    .state('home', {
       url: '/:filter',
       params: {
           filter: { squash: true, value: null }
       }
    });

I can activate this state by going to the homepage(example.com), as well as by adding the optional parameter example.com/apples which I use to filter out the contents on the homepage.

My problem now is that I have other routes defined like /login, /about, /help and by going to example.com/login or example.com/help, will only activate the home state because of the /:filter optional placeholder parameter I have defined which catches any route following /.

A workaround I have tried is adding a trailing slash to my other route definitions and links url: /login/ and to activate: example.com/login/ which works but I won't be able to use UI router's ui-sref directive to refer to my states by name instead of URL inside my app and the trailing slash just looks plain ugly.

What I am trying to achieve is to be able to have the optional parameter for the homepage /:filter and still be able to go the my other routes /login, /register, etc.. without having to workaround it by adding trailing slashes.

Has anyone been in this or similar situation before? Any insight or suggestion is very much appreciated. Thanks in advance.

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
dsan
  • 1,552
  • 12
  • 17

2 Answers2

8

There is a working example

The point here is to define home state as the last:

// this url will be registered as first
.state('login', {
      url: "/login",
      templateUrl: 'tpl.html',
})
// this as second
.state('about', {
      url: "/about",
      templateUrl: 'tpl.html',
})
...
// this will be registered as the last
.state('home', {
      url: "/:filter",
      templateUrl: 'tpl.html',
      params: {
        filter: { squash: true, value: null }
      }
})

UI-Router iterates the registered states in that order, and tries to find out first match. This way - all other states (login, about) will have precedence of 'home' state...

Check it here

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Ah, so UI-Router will iterate through the registered states in the order they are defined. My routes however are defined in modules, by that I mean my angular app is broken into modules, like the login page is a module, about page is a module, etc.. and the routes for them are defined inside each module. The modules are then being brought together through a app module. Is there a way to do it without having to define every route inside one $stateProvider or module? – dsan Sep 04 '15 at 16:17
  • I'd say - modules are different topic, here. It could be many modules, it could be just one.. E.g. I use few modules, with really distinct url prefixes... so it does not matter at the end. But in your case, what is essential is **the order of the state registration**. There is now way around. Simply UI-Router must find some way, how to decide the precedence. And it is by design the order of registration. Hope it helps a bit... – Radim Köhler Sep 04 '15 at 16:20
  • Yes it does help! like a lot, my routing conflict has been resolved because of your answer, especially your comment **the order of the state registration**. Thank you so much, its been a day+ of me trying to resolve this. Cheers! – dsan Sep 04 '15 at 16:33
  • Great to see that sir, really ;) Enjoy mighty UI-Router! – Radim Köhler Sep 04 '15 at 16:34
0

Best practice would say that this should probably be a query string parameter rather than a route parameter since you are using it to filter out data. To do this with ui-router just define it like so:

$stateProvider
.state('home', {
   url: '/?filter'
});

Now just do

$state.go('home', {filter: 'apples'})
Long Nguyen
  • 426
  • 3
  • 8