Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Here are a couple states from my app:

angular.module("app").config([
'$stateProvider', '$urlRouterProvider', '$httpProvider', function ($stateProvider, $urlRouterProvider, $httpProvider) {
    'use strict';

    $httpProvider.defaults.withCredentials = true;

    //#region Routing
    $urlRouterProvider.otherwise("/login");

    $stateProvider.state('client1', {
        onEnter: function () { },
        views: {
            "index": {
                templateUrl: 'indexView.html'
            }
        }
    }).state('client1.deliverables', {
        url: '/deliverables/:taxYear/:entity/:deliverable/:status',
        onEnter: function () { },
        views: {
            "nav": {
                templateUrl: 'Nav/nav.html',
                controller: 'NavController'
            },
            "content": {
                templateUrl: 'deliverables/deliverables.html',
                controller: 'DeliverablesController'
            },
            "footer": {
                templateUrl: 'footer.html',
            },
            reloadOnSearch: false
        }

On occasion, I want to load the deliverables state with default parameters. I'd prefer not to use dummy strings... Is there a better way to do this?

                    $state.go('^.deliverables', {
                        taxYear: null,
                        entity: null,
                        status: null
                    }); // Navigate to dashboard

But then I wind up with three slashes on my URL. http://example.com/#/deliverables////. Is there a way to make a more friendly URL without using dummy parameters? Is there a better way to do this without winding up with three slashes in a row? It's not the end of the world, but it looks foreign.

If I create two different states, then I have to replicate all of the state information twice.

EDIT: Sometimes I want to load this page with all nullable parameters. But when I do so, I get three consecutive slashes. Other times, I want to change to the state and provide actual values. That works fine. Is there a way to handle this without duplicating the state information into two states?

EDIT2: The page has 4 inputs that filter a jquery datatable. On first page load of the deliverables page, I would not like to filter by any of the inputs. I would also be able to do the angular equivalent of deep linking into the page. These deep links would then filter the table. This is why I have the parameters on the URL

share|improve this question
    
In the context of your application what does it mean to " to load the deliverables state with default parameters"? I'm looking to understand if it's a different state or just a special case of the one you have. –  Andrew E Nov 19 '14 at 15:29
    
I made an edit to try to explain better @AndrewE –  Hoppe Nov 19 '14 at 15:42
    
Thanks, but I understood that the first time. What I'm trying to understand is why you'd want to load it with empty parameters, because I think it holds the answer to a bigger question ("should I use a separate state or a special case of the current state") instead of a tactical "just make it work" question. For example, if the default parameters really means "show the most recent thing" then that's a different state. Be guided by that not the parameters. The logic can be put in a service to avoid duplication. Otherwise make the parameters some value like "now" instead of null. –  Andrew E Nov 19 '14 at 15:53
    
I agree with @AndrewE -- it would be helpful to understand what you're expecting to happen on that state when none of the parameters are defined. You could define another state that doesn't have any of the parameters, such as [url: "/deliverables"] if you're trying to define a state when nothing is selected (i.e. a list of all deliverables, or a state that simply shows select boxes where they're selecting the parameters) -- then you would call it without the parameters, rather than listing them with nulls. –  Mike Nov 19 '14 at 16:23
    
Thank you for clarifying. I added more info @Mike –  Hoppe Nov 19 '14 at 18:51

2 Answers 2

Ui-router 0.2.12 supports squashing of default param values.

See this issue for the RFC: https://github.com/angular-ui/ui-router/issues/1501

See this plunk: http://plnkr.co/edit/VMPc8D7oUG0B1R3QuiCE?p=preview for a demo.

You can specify how each param's default value is squashed.

Given the following states:

  $stateProvider.state({
    name: "user",
    url: "user/:username",
    parent: 'top',
    params: { 
      username: { 
        value: function(Session) { return Session.username; }
      } 
    }, 
    resolve: { 
      user: function($stateParams, users) { return users[$stateParams.username]; }, 
      galleries: function($stateParams, photos) { return photos[$stateParams.username] }
    },
    templateUrl: 'user.html',
    controller: function($scope, $state, user, galleries) { $scope.user = user; $scope.galleries = galleries; }
  });

  $stateProvider.state({
    name: "user.gallery",
    url: "/gallery/:galleryid",
    resolve: { 
      photos: function($stateParams, galleries) { return galleries[$stateParams.galleryid]; } 
    },
    params: { galleryid: { value: "favorites" } }, 
    templateUrl: 'gallery.html',
    controller: function($scope, $state, $stateParams, photos) { 
      $scope.gallery = $stateParams.galleryid; 
      $scope.photos = photos; 
    }
  });

  $stateProvider.state({
    name: "user.gallery.photo",
    url: "/photo/:photoid",
    resolve: { 
      photo: function($stateParams, photos) { 
        return photos.filter(function(photo) { return photo.id === $stateParams.photoid; })[0];
      } 
    },
    templateUrl: 'photo.html',
    controller: function($scope, $state, $stateParams, photo) { 
      $scope.gallery = $stateParams.galleryid; 
      $scope.photo = photo; 
    }
  });

These params:

{
  "username": "christopherthielen",
  "galleryid": "favorites",
  "photoid": "CN0ZRJw"
}

Will be squashed in the URL like so:

{
  false: "/user/christopherthielen/gallery/favorites/photo/CN0ZRJw",
  "-": "/user/-/gallery/-/photo/CN0ZRJw",
  "~": "/user/~/gallery/~/photo/CN0ZRJw",
  "": "/user//gallery//photo/CN0ZRJw",
  true: "/user/gallery/photo/CN0ZRJw"
}
share|improve this answer

I am not aware of a best practice for the specific situation you're describing. I think it would fall into two main use cases, that I can envision:

1) The core logic in the controllers and html in your partials of your 3 views is the same whether it has null for the parameters or valid values. In this case, what you have works fine, it just looks a little strange to have the consecutive slashes. There is no problem with that; however, if that bothers you, consider passing "0"s instead of Nulls (assuming 0 is an invalid value for your parameters).

2) If your views are actually different depending on whether there are values in the parameters or not, then you'd probably be better off having a separate state for just the "/deliverables" route. Yes, you'd have to duplicate the views definitions; however, if you have if/then blocks in your controller(s) (and/or ng-if/ng-show/ng-hide blocks in your partials) to handle the cases of null parameters, then you'd really just split that logic out into separate controllers/partials, so that they become simpler and the state definitions wouldn't be duplicative, as the two states would be using different controllers/partials (essentially splitting the existing controllers/partials into two different files each, with only the applicable logic in each).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.