Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular JS: "active" class on menu items created by a controller

Tags:

angularjs

I'm using a JSON service to list menu items (links). When navigating the different routes/pages I want an "active" class added to the link that is currently active (i.e. the page the user is on).

I've used this jsfiddle as a starting point: http://jsfiddle.net/p3ZMR/4/

I've also found several answers here on stackoverflow, but all of them are similar to the solution above.

But, that solution doesn't work if the links are generated via ng-repeat:

  <ul class="main-menu">
    <li ng-repeat="page in pages">
      <a href="/#/{{page.id}}" active-link="active">{{page.name}}</a>
    </li>
  </ul>

It seems as if the directive is called before the controller adds the links.

Is there any way to get around this?

like image 1000
Adam Gerthel Avatar asked May 15 '13 19:05

Adam Gerthel


2 Answers

HTML for repeating links

<div ng-app="link">
    <div data-ng-controller="myController">
        <a href="#/{{ link.url }}" data-ng-repeat="link in links" data-ng-class="(link.url == location.path() && 'active')">
            {{ link.name }}
        </a> 
    </div>
</div>

Javascript

angular.module('link', [])

function myController($scope, $location){
    $scope.location = $location;
     $scope.links = [
         { url: "one", name: "One"},
         { url: "two", name: "Two"},
         { url: "", name: "Three"}
    ];
}

This will produce links one/two/three with three being highlighted in the red color. Here's a jsfiddle: http://jsfiddle.net/4mFYy/1/

like image 191
Mathew Berg Avatar answered Oct 16 '22 19:10

Mathew Berg


As the author of your starting point, I updated the fiddle, so it should work now for your dynamic urls :).

angular.module('link', []).
  directive('activeLink', ['$location', function(location) {
  return {
      restrict: 'A',
      link: function(scope, element, attrs, controller) {
          var clazz = attrs.activeLink;
          scope.location = location;
          scope.$watch('location.path()', function(newPath) {
              if (attrs.href.substring(1) === newPath) {  //<------ Here it is already interpolated
                element.addClass(clazz);
              } else {
                element.removeClass(clazz);
              }
          });
      }

  };

  }]).
  controller('MyCtrl', ['$scope', function(scope) {
    scope.pages=[
       { url: "one", name: "One"},
       { url: "two", name: "Two"},
       { url: "three", name: "Three"},
       { url: "", name: "home"}
    ];
  }]);

http://jsfiddle.net/p3ZMR/59/

The problem is, that the directive is reading out the href attribute, before it gets interpolated. I just changed it in a way, that the href will get read out, after it is interpolated.

like image 21
kfis Avatar answered Oct 16 '22 21:10

kfis