5

Consider such scenario of a state with query parameters. I'd like to have them declared as flags so I can fetch then in the controller and get true, false or undefined

$stateProvider.state('foo.bar', {
         url: '/foobar?flag1&flag2',
         templateUrl: 'foo/bar/template.tpl.html',
         controller: 'FooBarCtrl'
});

myModule.controller('FooBarCtrl', function($stateParams){
         $stateParams.flag1 <<--- is string but can it be of type bool?
         $stateParams.flag2 <<--- is string but can it be of type bool?

});

Some URL examples:

/foobar?flag1=true    -->> should yield {flag1: true, flag2: undefined}
/foobar?flag2=false    -->> should yield {flag1: undefined, flag2: false}
/foobar?flag1=false&flag2=true    -->> should yield {flag1: false, flag2: true}
/foobar?flag1=1&flag2=0    -->> should yield {flag1: true, flag2: false}

etc...

At the moment $stateParams delivers only strings. Is there away to make the router to parse the params as flags? That would be much more elegant than doing the parsing manually in the controller.

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
amit
  • 1,991
  • 1
  • 18
  • 29

2 Answers2

7

You should be able to use the bool as a type

url: '/foobar?{flag1:bool}&{flag2:bool}',

But we can even use our custom type (let's call it boolean):

app.config(['$urlMatcherFactoryProvider', function($urlMatcherFactory) {
  $urlMatcherFactory.type('boolean',
{
 name : 'boolean',
 decode: function(val) { return val == true ? true : val == "true" ? true : false },
 encode: function(val) { return val ? 1 : 0; },
 equals: function(a, b) { return this.is(a) && a === b; },
 is: function(val) { return [true,false,0,1].indexOf(val) >= 0 },
 pattern: /bool|true|0|1/
})
}]);

And the state def for url would be like this:

url: '/foobar?{flag1:boolean}&{flag2:boolean}',

and this should work:

<a ui-sref="foobar({ flag1: 0, flag2:true })">
<a ui-sref="foobar({ flag1: 1, flag2:false })">

Here is plunker with example

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • 2
    this seems to work as long as you are feeding the router with int or boolean primitives but doesn't work with strings, which are what the router is actually getting from the URL. – amit Dec 11 '14 at 14:23
  • 3
    I wish this feature was better documented in the ui-router docs.. I've spent so much time working around queryParam parsing. Here's the [source with some other types](https://github.com/angular-ui/ui-router/blob/0c123c302a3b52e5f932f86a043886c809c64bf7/src/params/paramTypes.ts) – ichigolas Apr 01 '16 at 14:55
1

Eventually the following has worked for me:

    var stringToBoolean = function (s) {
        if (typeof s != 'string') {
            return undefined
        }

        if (/1|true|TRUE/.test(s)) {
            return true
        } else if (/0|false|FALSE/.test(s)) {
            return false
        } else {
            return undefined
        }
     };

     $stateProvider.state('foo.bar', {
                 url: '/foobar?{flag1}',
                 ...
                 onEnter: function ($stateParams) {
                        $stateParams.flag1 = stringToBoolean($stateParams.flag1);
                 }
      });

It doesn't feel super clean, I'd rather to have had this functionality integrated into ui-router but at least I was able in this way to solve this in the level of the states, without polluting my controllers with this logic.

amit
  • 1,991
  • 1
  • 18
  • 29