5

Is there a way to have an optional attribute at the beginning of the url in ui-router? If so, how?

I want to achieve sth like this:

.state('events',{
    url: '(/city:)?/events/:id'
    ...
})

So "city" would be optional.

Thank you for any input whatsoever.

Miha Eržen
  • 190
  • 1
  • 9

3 Answers3

7

It's probably bad practice to have two separate routes point to the same state, but nothing is keeping you from creating two different states that use the same resolutions/controller/template.

$stateProvider
.state('state1', {
  url: "/:city/events/:id",
  templateUrl: "partials/events.html",
  controller: eventsCtrl
})
.state('state2', {
  url: "/events/:id",
  templateUrl: "partials/events.html",
  controller: eventsCtrl
});

function eventsCtrl($scope){
  // shared controller
}

Again, this is probably bad practice but I can't think of a better solution

tommybananas
  • 5,718
  • 1
  • 28
  • 48
  • Yeah that is why I am asking this question, cause I want to avoid this... But yeah fair point. If no one knows better solution I guess this is the way to go. – Miha Eržen Aug 29 '14 at 13:23
7

I tried to answer the similar (if not same) here:

Angular js - route-ui add default parmeter

There is a working plunker, solving the issue for a language instead of for a city (but the concept is the same)

so, we would/should introduce some super state 'root'.

In our case, we can even use some regex to limit allowed values - because it would be hard to guess what is city and what is events

.state('root', {
    url: '/{city:(?:Prague|Bristol|Denver)}',
    abstract: true,
    template: '<div ui-view=""></div>',
    params: {lang : { squash : true, value: 'Prague' }}
})

What is important here is the setting params : {}. It says, that the default value is 'Prague' - so that would be the city if none is selected. What is also important - it should be squashed, skipped if there is a match with 'Prague' param value:

params: {lang : { squash : true, value: 'Prague' }}

Now, we can introduce some nested state(s) which would declare 'root' as their parent:

.state('events',{
    parent: 'root',
    url: '/events/:id'
    ...
})

Check the working example (with a language instead of city) here. For more details see the original Q & A

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
3

I see no reason why you wan't do it in a standard ui-router state setup.

DEMO

JAVASCRIPT

angular.module('app', ['ui.router'])

  .config(function($stateProvider, $urlRouterProvider) {

    $stateProvider

      .state('state1', {
        url: ':city/events/:id',
        templateUrl: 'partials/events.html',
        controller: 'EventsController'
      })

      .state('state2', {
        url: ':abc/cities/:x/:y',
        templateUrl: 'partials/cities.html',
        controller: 'CitiesController'
      });

  })

  .controller('EventsController', function($scope, $stateParams) {

    angular.extend($scope, $stateParams);

  })

  .controller('CitiesController', function($scope, $stateParams) {

    angular.extend($scope, $stateParams);

  });
ryeballar
  • 29,658
  • 10
  • 65
  • 74