UI Router matching url with hash (fragment)

Issue

Using UI router I need to match URLs with hash (fragment) included in it (HTML5 mode).

.state('myState', {
            url: '/path/:id/page#:section',
            templateUrl: 'template.html',
            controller: 'MyController'
        });

While the setup above works when using ui-sref below..

<a ui-sref="myState({id: 1})"> ... // without hash => section == ''
<a ui-sref="myState({id: 1, section: 'abc'})"> ... // section == 'abc'

.. it fails when I redirect browser from other page manually by specifying the fragment in the address bar (or when a link including the hash was clicked on totally different site) in that case the URL matcher tries to match against URL without the hash and I am forced to create a new artificial state which is the same as above but without the hash and the param section in it’s url property. But that leaves me without possibility to have bookmarkable URL with hash included.

I need to have one state, where this fragment param is optional and is correctly matched by in-app state transition and by url matching mechanism when redirected to the page preserving the given section parameter (if present).

Solution

I resolved the issue by using # param instead:

<a ui-sref="myState({id: 1})"> ... // without hash => # == ''
<a ui-sref="myState({id: 1, '#': 'abc'})"> ... // # == 'abc'

And URL in the state definition is without hash all together:

url: '/path/:id/page',

This matches the state on page load with hash in URL, however it still doesn’t set the # value in state params. I resolved this by manually setting the param in $stateChangeStart event handler:

 $rootScope.$on('$stateChangeStart',
      function(event, toState, toParams, fromState, fromParams) {
            var hash = $location.hash();
            if (hash) {
                 toParams['#'] = hash;
            }
      }

Answered By – redhead

Answer Checked By – Marilyn (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.