Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>First of all, your <code>firedEvents</code> means how many time the callback has been called, not how many times the location actually changed, it's not the "number of path-change events"!</p> <p>You have 20 (as in your fiddle) scopes are watching the location change, when you click on a different link other than the current active one, the location changes, <strong>ALL</strong> of the 20 scopes will see the change and call their <strong>own</strong> <code>$watch</code> callback functions, and each call to the callback will increase your <code>firedEvents</code>, so the result is what you have seen: the count goes up by 20.</p> <p>Therefore, if you want to make the <code>firedEvents</code> to count how many time location has changed, you should move <code>scope.$parent.firedEvents++;</code> into the <code>if</code>. But keep in mind that every click will still cause the callback function be called by 20 times!</p> <p>There are many ways to achieve the same effect you're trying to do here, I have a solution for you without digging into directive at all. Here you go:</p> <p>HTML</p> <pre><code>&lt;ul ng-controller="MenuCtrl"&gt; &lt;li ng-repeat="link in menuDef" ng-class="{activeLink: link.isActive}" ng-click="onLinkClick(link)"&gt;&lt;a href="{{link.url}}"&gt;{{link.linkName}}&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; </code></pre> <p>JS</p> <pre><code>app.controller("MenuCtrl", function ($scope, $location) { var menugen = []; for (var i = 1; i &lt;= 20; i++) { menugen.push({ linkName: "Link " + i, url: "#/url" + i }); } $scope.menuDef = menugen; var activeLink = null; $scope.onLinkClick = function (link) { if (activeLink &amp;&amp; $scope.activeLink !== link) { activeLink.isActive = false; } link.isActive = true; activeLink = link; }; }); </code></pre> <p><kbd><a href="http://jsfiddle.net/jaux/rRgE5/" rel="nofollow">jsFiddle</a></kbd></p> <h2>Update</h2> <p>My first attempt is targeting simplicity, but as @VirtualVoid pointed out, it has a huge drawback -- it can't easily handle location change from outside of the menu.</p> <p>Here, I came up a better solution: adding a directive to the <code>ul</code>, watch location change in there, <em>and</em> update activeLink in the callback function of the watch. In this way, one <code>$watch</code> is called, and only one callback will be called for a click.</p> <p>JS</p> <pre><code>app.directive('menu', function ($location) { return { restrict: 'A', controller: function ($scope, $location) { var links = []; this.registerLink = function (elem, path) { links.push({ elem: elem, path: path }); }; $scope.$watch(function () { return $location.path(); }, function (path) { for (var i = 0; i &lt; links.length; i++) { if (path === links[i].path) { links[i].elem.addClass('activeLink'); } else { links[i].elem.removeClass('activeLink'); } } }); } }; }). directive("testdir", function () { return { restrict: 'A', require: '^menu', link: function (scope, element, attrs, controller) { controller.registerLink(element, scope.link.url.substring(1)); } }; }); </code></pre> <p>HTML</p> <pre><code>&lt;ul ng-app="test" ng-controller="MenuCtrl" menu&gt; &lt;li ng-repeat="link in menuDef" testdir&gt; &lt;a href="{{link.url}}"&gt;{{link.linkName}}&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; </code></pre> <p>jsFiddle: <a href="http://jsfiddle.net/jaux/MFYCX/" rel="nofollow">http://jsfiddle.net/jaux/MFYCX/</a></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload