11

I have been trying to make use of the param types with ui-router and can't seem to get them right.

$stateProvider.state({ name: 'home.foo', url: '/foo/{isBar:bool}', controller: function() { }, templateUrl: 'foo.html' });

My expectation is that I should be able to transition to that state like this:

$state.go(home.foo, { isBar: false })

or

ui-sref="home.foo({ isBar: false })"

however in the resulting $stateParams you will see isBar: true

Looking at the way the 'bool' param type is written I suppose true/false should be encoded as 0/1 on the url but this doesn't happen. If use 0/1 in the params for $state.go then it works and is decoded as false/true but to further confuse the issue this doesn't work if using the ui-sref.

Hopefully this plunker will explain it better. Any hints appreciated!

Edit: My goal in using the bool param type is to end up with a boolean data type in $stateParams

brahnp
  • 2,276
  • 1
  • 17
  • 22
  • 1
    This is buggy behavior in 0.2.13 and was fixed in this commit: https://github.com/angular-ui/ui-router/commit/b0c6aa2350fdd3ce8483144774adc12f5a72b7e9 . If you build from master, your plunk works. http://plnkr.co/edit/u3NsF0PSmNt3HWiQkdvP?p=preview – Chris T Dec 29 '14 at 15:58
  • Hey, thanks Chris! Would that also close off this issue for you? https://github.com/angular-ui/ui-router/issues/1655 – brahnp Dec 29 '14 at 18:35

2 Answers2

11

There is an updated and working plunker with boolean custom type

In case, we would like to work with a bool like type, which expects and accepts the:

true, false, 0, 1

we just have to register our custom type:

app.config(['$urlMatcherFactoryProvider', function($urlMatcherFactory) {

  $urlMatcherFactory.type('boolean',
    // our type custom type
    {
     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 then we can use this url defintion inside of any state:

...
, url: '/foo/{isBar:boolean}'
...

NOTE: why boolean? not bool? Because bool is already registered for 0|1 as far as I remember

Check it here

ORIGINAL

simple solution working with "strings" in this updated plunker,

... // states definitions
, url: '/foo/{isBar:(?:bool|true|0|1)}'
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • The type in $stateParam is a string though. I realise now that I am not explicit in my question but the result I am after is { isBar : true/false } – brahnp Nov 28 '14 at 10:51
  • The power of `UI-Router` is unlimited ;) Enjoy it ;) – Radim Köhler Nov 28 '14 at 12:01
  • Thanks Radim, it looks like more than I was after :) I did look at registering a custom type but wanted to try and understand why the default bool was not working first. I still don't quite understand what it is supposed to achieve or if it is just broken! – brahnp Nov 28 '14 at 12:34
  • **Luckily you have your answer with `boolean`** ;) if you want to know more, observe the source code here: https://github.com/angular-ui/ui-router/tree/master/src. Good luck with UI-Router ;) – Radim Köhler Nov 28 '14 at 12:35
  • Thanks @RadimKöhler. I wonder if it can detect when a querystring is `undefined`. For example `/foo?{isBar:boolean}` to give `false` when the actual url is `/foo` without querystring. I am trying to figure it out now. As far as I have tested, `undefined` does not match in `$state.includes`. – PSWai Jan 30 '15 at 03:41
  • I missed out the `params` object in `$stateProvider` configuration. Looks like we can set default value there. So problem solved :) – PSWai Jan 30 '15 at 04:05
  • can $urlMatcherFactory.type('boolean' <-------- can this be whatever you want? or does it have to be boolean,string etc....? Also what's the diff between that and the "name" property in the object? – btm1 Jul 27 '15 at 23:13
1

So after digging around multiple files I found why the last two ways (0,1) don't work in ui-sref. There is this call at line 106 of stateDirectives.js: newHref = $state.href(ref.state, params, options);

This will return null in the case of using 1 and 0. And since the above call is followed by this:

 if (newHref === null) {
      nav = false;
      return false;
    }

a link is never made. Now, the reason null is returned. state.href calls urlRouter.href. Inside that is a call to validate the params. The validation is this: result = result && (isOptional || !!param.type.is(val));

when you look at the is function for bool (is: function(val) { return val === true || val === false; }) you can see why this fails as 1 and 0 do not equal true or false. In my opinion it should also check for 1 and 0 if that is what it is ultimately converted to but at least now you know why it behaves the way it does.

Jason
  • 1,316
  • 13
  • 25
  • Thanks Jason. I have updated the plunker to include an example using $state.go however it is the same behaviour as ui-sref. In my more complicated application the 0/1 does decode to false/true correctly. I will continue to try and replicate that in the plunker. – brahnp Nov 27 '14 at 21:28