ui-router: ui-sref-active not working correctly with abstract and child states

http://plnkr.co/edit/c7OS1pwI5IjAAs5cEi5s?p=preview

In the example above, clicking the Administration nav element shows a view with two tabs, Users and Roles.

These correspond to the states admin.users and admin.roles, while admin is an abstract state whose URL is inherited by admin.users. This all works fine except when setting the active class using ui-sref-active.

There are two problems in this scenario:

  1. The Administration nav element is not made active when on the Roles tab
  2. When refreshing the page (be sure to pop out the Plunker preview) while on the Roles tab, no elements get the active class set

I would like to avoid using $state.includes directly since ui-sref-active is supposed to work on child states since 0.2.11: https://github.com/angular-ui/ui-router/pull/927

Am I doing something wrong or is this a bug?

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Comments: 80 (6 by maintainers)

Commits related to this issue

Most upvoted comments

It seems like people are still looking at this even though the solution is in at least the most recent version! It is still undocumented, but just use an object (like with ng-class) and it will work.

This won’t work right:

<li ui-sref-active="active">
  <a ui-sref="admin.users">Administration Panel</a>
</li>

This will:

<li ui-sref-active="{ 'active': 'admin' }">
  <a ui-sref="admin.users">Administration Panel</a>
</li>

+1

I fixed this using a custom directive:

app.directive('uiSrefActiveIf', ['$state', function($state) {
    return {
        restrict: "A",
        controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
            var state = $attrs.uiSrefActiveIf;

            function update() {
                if ( $state.includes(state) || $state.is(state) ) {
                    $element.addClass("active");
                } else {
                    $element.removeClass("active");
                }
            }

            $scope.$on('$stateChangeSuccess', update);
            update();
        }]
    };
}])

Then you use matching HTML ui-sref-active-if=“parent” will add the class “active”

@tgrant59 Thanks for the example.

Notes: Angular developers are still workarounding integrated features like this one in this retarded framework. THE NEW INTEGRATED FEATURES ARE NOT DOCUMENTED AT ALL!!! Every developer must go first to the official documentation where he finds nothing useful, then he goes to stackoverflow where all solutions are outdated or bad practices, then he decides that he will either waste 2 more hours going in to the comments of a related issue and explore all pull request OR simply write a custom solution that in 100% of the cases simply overrides or workarounds core features of the framework.

Thanks to the google marketing team frameworks like angular are well sold to end clients without even thinking if this framework will be a major drawback for the entire project. And that’s how zillions of govnocode projects are born.

PS: wasted 3 hours to find an example of this feature and to determine if this feature is actually built in to the framework…

Finally I got a solution from the following issue: https://github.com/angular-ui/ui-router/issues/2954

ui-sref-active="{'active': 'administration.**'}"

+1

I run into this issue a lot and, off the top of my head, here are a couple ideas for how it could be fixed:

First, you could add additional options to ui-sref-active so that you can specify a route rather than just using the route provided to ui-sref. Maybe something like this:

<a ui-sref='admin.users' ui-sref-active="{class: 'active', state: 'admin'}">Link</a>

Another way that might also be generally useful would be to allow linking to abstract states if it provides a default child state. Then you could do the following:

For example:

      // ...
      .state('admin', {
        url: '/admin',
        abstract: true,
        defaultChild: 'admin.users',
        templateUrl: 'templates/adminPanel.html'
      })
      .state('admin.users', {
        url: '',
        templateUrl: 'templates/adminUsers.html'
      })
      // ...
<a ui-sref="admin" ui-sref-active="active">Administration Panel</a>

@samuil4 Nobody on the UI Router project works for Google. We all do this in our spare time. If you don’t like the situation, figure out the issue and submit a patch to the documentation. If everyone did that just once, you wouldn’t need StackOverflow.

I just had the same problem. In my app, I have an abstract ‘users’ state, and my menu link goes to users.list but then when selecting a user and going to users.details, I lost the ui-sref-active 😕

I like the idea to have an object intp ui-sref-active to specify the associated state 😃

     <li ui-sref-active="active"><a ui-sref="admin.users">Administration Panel</a>

The active class ‘ui-sref-active’ activates upon is not the abstract ‘admin’, but the ‘admin.users’ :? I guess the way this is suppose to be done is - making the admin non-abstract, and setting the url of the default child state to “” (however, THAT does not work for me for some reason, trying to figure out right now if it’s me or an issue) Switching to urls based navigation would work, but seems to me not to be the right intent