web-dev-qa-db-fra.com

Comment mettre en évidence un élément de menu actuel?

AngularJS aide-t-il de quelque manière que ce soit à définir une classe active sur le lien de la page en cours?

J'imagine qu'il y a une façon magique de faire cela, mais je n'arrive pas à le trouver.

Mon menu ressemble à:

 <ul>
   <li><a class="active" href="/tasks">Tasks</a>
   <li><a href="/actions">Tasks</a>
 </ul>

et j'ai des contrôleurs pour chacun d'eux dans mes routes: TasksController et ActionsController.

Mais je ne peux pas trouver un moyen de lier la classe "active" sur les liens a aux contrôleurs.

Des allusions?

202
drozzy

en vue

<a ng-class="getClass('/tasks')" href="/tasks">Tasks</a>

sur le contrôleur

$scope.getClass = function (path) {
  return ($location.path().substr(0, path.length) === path) ? 'active' : '';
}

Avec cela, le lien tasks aura la classe active dans n'importe quelle URL commençant par '/tasks'(e.g.'/Tasks/1/reports ')

262

Je suggère d'utiliser une directive sur un lien.

Mais ce n'est pas encore parfait. Attention aux hashbangs;)

Voici le javascript pour la directive:

angular.module('link', []).
  directive('activeLink', ['$location', function (location) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs, controller) {
        var clazz = attrs.activeLink;
        var path = attrs.href;
        path = path.substring(1); //hack because path does not return including hashbang
        scope.location = location;
        scope.$watch('location.path()', function (newPath) {
          if (path === newPath) {
            element.addClass(clazz);
          } else {
            element.removeClass(clazz);
          }
        });
      }
    };
  }]);

et voici comment il serait utilisé en HTML:

<div ng-app="link">
  <a href="#/one" active-link="active">One</a>
  <a href="#/two" active-link="active">One</a>
  <a href="#" active-link="active">home</a>
</div>

après le style avec css:

.active { color: red; }
86
kfis

Voici une approche simple qui fonctionne bien avec Angular. 

<ul>
    <li ng-class="{ active: isActive('/View1') }"><a href="#/View1">View 1</a></li>
    <li ng-class="{ active: isActive('/View2') }"><a href="#/View2">View 2</a></li>
    <li ng-class="{ active: isActive('/View3') }"><a href="#/View3">View 3</a></li>
</ul>

Dans votre contrôleur AngularJS:

$scope.isActive = function (viewLocation) {
     var active = (viewLocation === $location.path());
     return active;
};

Ce fil a un certain nombre d'autres réponses similaires.

Comment définir la classe active bootstrap navbar avec Angular JS?

45
Ender2050

Juste pour ajouter mes deux cents dans le débat, j'ai créé un module purement angulaire (pas de jQuery), qui fonctionnera également avec des URL de hachage contenant des données. (par exemple, #/this/is/path?this=is&some=data)

Vous ajoutez simplement le module en tant que dépendance et auto-active à l'un des ancêtres du menu. Comme ça:

<ul auto-active>
    <li><a href="#/">main</a></li>
    <li><a href="#/first">first</a></li>
    <li><a href="#/second">second</a></li>
    <li><a href="#/third">third</a></li>
</ul>

Et le module ressemble à ceci:

(function () {
    angular.module('autoActive', [])
        .directive('autoActive', ['$location', function ($location) {
        return {
            restrict: 'A',
            scope: false,
            link: function (scope, element) {
                function setActive() {
                    var path = $location.path();
                    if (path) {
                        angular.forEach(element.find('li'), function (li) {
                            var anchor = li.querySelector('a');
                            if (anchor.href.match('#' + path + '(?=\\?|$)')) {
                                angular.element(li).addClass('active');
                            } else {
                                angular.element(li).removeClass('active');
                            }
                        });
                    }
                }

                setActive();

                scope.$on('$locationChangeSuccess', setActive);
            }
        }
    }]);
}());

(Vous pouvez bien sûr simplement utiliser la partie directive)

Il convient également de noter que cela ne fonctionne pas pour les hachages vides (par exemple, example.com/# ou simplement example.com), il doit comporter au moins example.com/#/ ou seulement example.com#/. Mais cela se produit automatiquement avec ngResource, etc.

Et voici le violon: http://jsfiddle.net/gy2an/8/

32
Pylinux

Dans mon cas, j'ai résolu ce problème en créant un contrôleur simple responsable de la navigation.

angular.module('DemoApp')
  .controller('NavigationCtrl', ['$scope', '$location', function ($scope, $location) {
    $scope.isCurrentPath = function (path) {
      return $location.path() == path;
    };
  }]);

Et en ajoutant simplement ng-class à l'élément comme ceci:

<ul class="nav" ng-controller="NavigationCtrl">
  <li ng-class="{ active: isCurrentPath('/') }"><a href="#/">Home</a></li>
  <li ng-class="{ active: isCurrentPath('/about') }"><a href="#/about">About</a></li>
  <li ng-class="{ active: isCurrentPath('/contact') }"><a href="#/contact">Contact</a></li>
</ul>
22
Djamel

Pour les utilisateurs de AngularUI Router:

<a ui-sref-active="active" ui-sref="app">

Et cela placera une classe active sur l'objet sélectionné.

14
frankie4fingers

Il existe une directive ng-class, qui lie variable et css class . Elle accepte également l’objet (paires className vs bool value).

Voici l'exemple, http://plnkr.co/edit/SWZAqj

13
Tosh

Le answer de @ Renan-tomal-fernandes est bon, mais quelques améliorations sont nécessaires pour fonctionner correctement. même si vous étiez dans une autre section.

Donc, je l’ai un peu amélioré, voici le code . Je travaille avec Bootstrap donc la partie active est dans l’élément <li> au lieu du <a>.

Manette

$scope.getClass = function(path) {
    var cur_path = $location.path().substr(0, path.length);
    if (cur_path == path) {
        if($location.path().substr(0).length > 1 && path.length == 1 )
            return "";
        else
            return "active";
    } else {
        return "";
    }
}

Modèle

<div class="nav-collapse collapse">
  <ul class="nav">
    <li ng-class="getClass('/')"><a href="#/">Home</a></li>
    <li ng-class="getClass('/contents/')"><a href="#/contests/">Contents</a></li>
    <li ng-class="getClass('/data/')"><a href="#/data/">Your data</a></li>
  </ul>
</div>
13
holographix

Voici la solution que j'ai trouvée après avoir lu certaines des excellentes suggestions ci-dessus. Dans ma situation particulière, j’essayais d’utiliser Le composant Onglets de Bootstrap en tant que mon menu, mais je ne voulais pas utiliser la version Angular-UI de cela car je voulais que les onglets agissent comme un menu, où chaque onglet compatible avec les signets, plutôt que les onglets agissant comme une navigation pour une seule page. (Voir http://angular-ui.github.io/bootstrap/#/tabs si vous êtes intéressé par ce à quoi ressemble la version Angular-UI des onglets de bootstrap).

J'ai vraiment aimé la réponse de Kfis sur la création de votre propre directive pour gérer cela, mais il semblait fastidieux d'avoir une directive qui devait être placée sur chaque lien. J'ai donc créé ma propre directive angulaire qui est placée à la place une fois sur la variable ul. Juste au cas où quelqu'un essaierait de faire la même chose, j'ai pensé l'afficher ici, bien que, comme je l'ai dit, nombre des solutions ci-dessus fonctionnent également. C'est une solution légèrement plus complexe en ce qui concerne le javascript, mais elle crée un composant réutilisable avec un balisage minimal.

Voici le javascript de la directive et le fournisseur de route pour ng:view:

var app = angular.module('plunker', ['ui.bootstrap']).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.
        when('/One', {templateUrl: 'one.html'}).
        when('/Two', {templateUrl: 'two.html'}).
        when('/Three', {templateUrl: 'three.html'}).
        otherwise({redirectTo: '/One'});
  }]).
  directive('navTabs', ['$location', function(location) {
    return {
        restrict: 'A',
        link: function(scope, element) {
            var $ul = $(element);
            $ul.addClass("nav nav-tabs");

            var $tabs = $ul.children();
            var tabMap = {};
            $tabs.each(function() {
              var $li = $(this);
              //Substring 1 to remove the # at the beginning (because location.path() below does not return the #)
              tabMap[$li.find('a').attr('href').substring(1)] = $li;
            });

            scope.location = location;
            scope.$watch('location.path()', function(newPath) {
                $tabs.removeClass("active");
                tabMap[newPath].addClass("active");
            });
        }

    };

 }]);

Alors dans votre html vous simplement:

<ul nav-tabs>
  <li><a href="#/One">One</a></li>
  <li><a href="#/Two">Two</a></li>
  <li><a href="#/Three">Three</a></li>
</ul>
<ng:view><!-- Content will appear here --></ng:view>

Voici le plunker pour cela: http://plnkr.co/edit/xwGtGqrT7kWoCKnGDHYN?p=preview .

10
corinnaerin

Vous pouvez implémenter ceci très simplement, voici un exemple:

<div ng-controller="MenuCtrl">
  <ul class="menu">
    <li ng-class="menuClass('home')"><a href="#home">Page1</a></li>
    <li ng-class="menuClass('about')"><a href="#about">Page2</a></li>
  </ul>

</div>

Et votre contrôleur devrait être ceci:

app.controller("MenuCtrl", function($scope, $location) {
  $scope.menuClass = function(page) {
    var current = $location.path().substring(1);
    return page === current ? "active" : "";
  };
});
8
Ejaz

utilisez la directive ui-sref-active de angular-ui-router https://github.com/angular-ui/ui-router/wiki/Quick-Reference#statename

<ul>
  <li ui-sref-active="active" class="item">
    <a href ui-sref="app.user({user: 'bilbobaggins'})">@bilbobaggins</a>
  </li>
  <!-- ... -->
</ul>

5
Cyanny

J'ai eu un problème similaire avec menu situé à l'extérieur la portée du contrôleur. Pas sûr que ce soit la meilleure solution ou celle recommandée, mais c'est ce qui a fonctionné pour moi. J'ai ajouté les éléments suivants à la configuration de mon application:

var app = angular.module('myApp');

app.run(function($rootScope, $location){
  $rootScope.menuActive = function(url, exactMatch){
    if (exactMatch){
      return $location.path() == url;
    }
    else {
      return $location.path().indexOf(url) == 0;
    }
  }
});

Alors dans la vue j'ai: 

<li><a href="/" ng-class="{true: 'active'}[menuActive('/', true)]">Home</a></li>
<li><a href="/register" ng-class="{true: 'active'}[menuActive('/register')]">
<li>...</li>
4
mrt

En utilisant une directive (puisque nous faisons ici des manipulations du DOM), ce qui suit est probablement le plus proche de faire les choses de la "manière angulaire":

$scope.timeFilters = [
  {'value':3600,'label':'1 hour'},
  {'value':10800,'label':'3 hours'},
  {'value':21600,'label':'6 hours'},
  {'value':43200,'label':'12 hours'},
  {'value':86400,'label':'24 hours'},
  {'value':604800,'label':'1 week'}
]

angular.module('whatever', []).directive('filter',function(){
return{
    restrict: 'A',
    template: '<li ng-repeat="time in timeFilters" class="filterItem"><a ng-click="changeTimeFilter(time)">{{time.label}}</a></li>',
    link: function linkFn(scope, lElement, attrs){

        var menuContext = attrs.filter;

        scope.changeTimeFilter = function(newTime){
          scope.selectedtimefilter = newTime;

        }

        lElement.bind('click', function(cevent){
            var currentSelection = angular.element(cevent.srcElement).parent();
            var previousSelection = scope[menuContext];

            if(previousSelection !== currentSelection){
                if(previousSelection){
                    angular.element(previousSelection).removeClass('active')
                }
                scope[menuContext] = currentSelection;

                scope.$apply(function(){
                    currentSelection.addClass('active');
                })
            }
        })
    }
}
})

Votre code HTML ressemblerait alors à:

<ul class="dropdown-menu" filter="times"></ul>
3
Wesley Hales

Ma solution à ce problème, utilisez route.current dans le modèle angulaire.

Comme vous devez sélectionner la route /tasks dans votre menu, vous pouvez ajouter votre propre propriété menuItem aux routes déclarées par votre module:

$routeProvider.
  when('/tasks', {
    menuItem: 'TASKS',
    templateUrl: 'my-templates/tasks.html',
    controller: 'TasksController'
  );

Ensuite, dans votre modèle tasks.html, vous pouvez utiliser la directive ng-class suivante:

<a href="app.html#/tasks" 
    ng-class="{active : route.current.menuItem === 'TASKS'}">Tasks</a>

À mon avis, cela est beaucoup plus propre que toutes les solutions proposées.

2

Je l'ai fait comme ça:

var myApp = angular.module('myApp', ['ngRoute']);

myApp.directive('trackActive', function($location) {
    function link(scope, element, attrs){
        scope.$watch(function() {
            return $location.path();
        }, function(){
            var links = element.find('a');
            links.removeClass('active');
            angular.forEach(links, function(value){
                var a = angular.element(value);
                if (a.attr('href') == '#' + $location.path() ){
                    a.addClass('active');
                }
            });
        });
    }
    return {link: link};
});

Cela vous permet d’avoir des liens dans une section qui a une directive track-active:

<nav track-active>
     <a href="#/">Page 1</a>
     <a href="#/page2">Page 2</a>
     <a href="#/page3">Page 3</a>
</nav>

Cette approche me semble beaucoup plus propre que les autres.

De plus, si vous utilisez jQuery, vous pouvez le rendre beaucoup plus simple car jQlite ne prend en charge que le sélecteur de base. Une version beaucoup plus propre avec jquery inclus avant include angular ressemblerait à ceci:

myApp.directive('trackActive', function($location) {
    function link(scope, element, attrs){
        scope.$watch(function() {
            return $location.path();
        }, function(){
            element.find('a').removeClass('active').find('[href="#'+$location.path()+'"]').addClass('active');
        });
    }
    return {link: link};
});

Voici un jsFiddle

2
konsumer

Selon la réponse de @kfis, il s’agit de commentaires, et je recommande la directive finale ci-dessous:

.directive('activeLink', ['$location', function (location) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs, controller) {
        var clazz = attrs.activeLink;        
        var path = attrs.href||attrs.ngHref;
        path = path.substring(1); //hack because path does not return including hashbang
        scope.location = location;
        scope.$watch('window.location.href', function () {
          var newPath = (window.location.pathname + window.location.search).substr(1);
          if (path === newPath) {
            element.addClass(clazz);
          } else {
            element.removeClass(clazz);
          }
        });
      }
    };
  }]);

et voici comment il serait utilisé en HTML:

<div ng-app="link">
  <a href="#/one" active-link="active">One</a>
  <a href="#/two" active-link="active">One</a>
  <a href="#" active-link="active">home</a>
</div>

après le style avec css:

.active { color: red; }
1
John_J

Voici encore une autre directive pour mettre en évidence les liens actifs.

Principales caractéristiques:

  • Fonctionne bien avec href qui contient des expressions angulaires dynamiques
  • Compatible avec la navigation par hash-bang 
  • Compatible avec Bootstrap où la classe active doit être appliquée au parent li et non au lien lui-même
  • Permet de rendre le lien actif si un chemin imbriqué est actif
  • Permet de rendre le lien désactivé s'il n'est pas actif

Code:

.directive('activeLink', ['$location', 
function($location) {
    return {
        restrict: 'A',
        link: function(scope, elem, attrs) {
            var path = attrs.activeLink ? 'activeLink' : 'href';
            var target = angular.isDefined(attrs.activeLinkParent) ? elem.parent() : elem;
            var disabled = angular.isDefined(attrs.activeLinkDisabled) ? true : false;
            var nested = angular.isDefined(attrs.activeLinkNested) ? true : false;

            function inPath(needle, haystack) {
                var current = (haystack == needle);
                if (nested) {
                    current |= (haystack.indexOf(needle + '/') == 0);
                }

                return current;
            }

            function toggleClass(linkPath, locationPath) {
                // remove hash prefix and trailing slashes
                linkPath = linkPath ? linkPath.replace(/^#!/, '').replace(/\/+$/, '') : '';
                locationPath = locationPath.replace(/\/+$/, '');

                if (linkPath && inPath(linkPath, locationPath)) {
                    target.addClass('active');
                    if (disabled) {
                        target.removeClass('disabled');
                    }
                } else {
                    target.removeClass('active');
                    if (disabled) {
                        target.addClass('disabled');
                    }
                }
            }

            // watch if attribute value changes / evaluated
            attrs.$observe(path, function(linkPath) {
                toggleClass(linkPath, $location.path());
            });

            // watch if location changes
            scope.$watch(
                function() {
                    return $location.path(); 
                }, 
                function(newPath) {
                    toggleClass(attrs[path], newPath);
                }
            );
        }
    };
}
]);

Usage:

Exemple simple avec une expression angulaire, disons $ scope.var = 2 , alors le lien sera actif si location est/url/2 :

<a href="#!/url/{{var}}" active-link>

Exemple de bootstrap, le parent li obtiendra la classe active:

<li>
    <a href="#!/url" active-link active-link-parent>
</li>

Exemple avec des URL imbriquées, le lien sera actif si une URL imbriquée est active (par exemple,/url/1 ,/url/2 , url/1/2/... )

<a href="#!/url" active-link active-link-nested>

Exemple complexe, le lien pointe vers une URL (/url1 ) mais sera actif si une autre est sélectionnée (/url2 ):

<a href="#!/url1" active-link="#!/url2" active-link-nested>

Exemple avec un lien désactivé, s'il n'est pas actif, il aura 'disabled' class:

<a href="#!/url" active-link active-link-disabled>

Tous les attributs active-link- * peuvent être utilisés dans n'importe quelle combinaison, ce qui permet de réaliser des conditions très complexes.

1
Eugene Fidelin

Pour ceux qui utilisent ui-router, ma réponse est un peu similaire à celle d'Ender2050, mais je préfère le faire via des tests de noms d'état:

$scope.isActive = function (stateName) {
  var active = (stateName === $state.current.name);
  return active;
};

hTML correspondant:

<ul class="nav nav-sidebar">
    <li ng-class="{ active: isActive('app.home') }"><a ui-sref="app.home">Dashboard</a></li>
    <li ng-class="{ active: isActive('app.tiles') }"><a ui-sref="app.tiles">Tiles</a></li>
</ul>
1
GONeale

Voici une extension de la directive kfis que j'ai créée pour permettre différents niveaux de correspondance de chemin. J'ai essentiellement trouvé qu'il était nécessaire de faire correspondre les chemins d'URL jusqu'à une certaine profondeur, car la correspondance exacte ne permet pas les redirections d'état d'imbrication et par défaut. J'espère que cela t'aides.

    .directive('selectedLink', ['$location', function(location) {
    return {
        restrict: 'A',
        scope:{
            selectedLink : '='
            },
        link: function(scope, element, attrs, controller) {
            var level = scope.selectedLink;
            var path = attrs.href;
            path = path.substring(1); //hack because path does not return including hashbang
            scope.location = location;
            scope.$watch('location.path()', function(newPath) {
                var i=0;
                p = path.split('/');
                n = newPath.split('/');
                for( i ; i < p.length; i++) { 
                    if( p[i] == 'undefined' || n[i] == 'undefined' || (p[i] != n[i]) ) break;
                    }

                if ( (i-1) >= level) {
                    element.addClass("selected");
                    } 
                else {
                    element.removeClass("selected");
                    }
                });
            }

        };
    }]);

Et voici comment j'utilise le lien

<nav>
    <a href="#/info/project/list"  selected-link="2">Project</a>
    <a href="#/info/company/list" selected-link="2">Company</a>
    <a href="#/info/person/list"  selected-link="2">Person</a>
</nav>

Cette directive correspondra au niveau de profondeur spécifié dans la valeur d'attribut pour la directive. Cela signifie simplement qu'il peut être utilisé ailleurs de nombreuses fois.

1
pkbyron

Si vous souhaitez que les liens de la directive soient placés dans un wrapper plutôt que de les sélectionner individuellement (cela facilite la consultation de la portée de Batarang), cela fonctionne également très bien:

  angular.module("app").directive("navigation", [
    "$location", function($location) {
      return {
        restrict: 'A',
        scope: {},
        link: function(scope, element) {
          var classSelected, navLinks;

          scope.location = $location;

          classSelected = 'selected';

          navLinks = element.find('a');

          scope.$watch('location.path()', function(newPath) {
            var el;
            el = navLinks.filter('[href="' + newPath + '"]');

            navLinks.not(el).closest('li').removeClass(classSelected);
            return el.closest('li').addClass(classSelected);
          });
        }
      };
    }
  ]);

Le balisage serait juste:

    <nav role="navigation" data-navigation>
        <ul>
            <li><a href="/messages">Messages</a></li>
            <li><a href="/help">Help</a></li>
            <li><a href="/details">Details</a></li>
        </ul>
    </nav>

Je devrais également mentionner que j'utilise jQuery 'full-fat' dans cet exemple, mais vous pouvez facilement modifier ce que j'ai fait avec le filtrage et ainsi de suite.

1
marksyzm

Aucune des propositions ci-dessus directive ne m’a été utile. Si vous avez une barre de navigation bootstrap comme celle-ci 

<ul class="nav navbar-nav">
    <li><a ng-href="#/">Home</a></li>
    <li><a ng-href="#/about">About</a></li>
  ...
</ul>

(cela pourrait être un démarrage de $ yo angular) alors vous voulez ajouter .active à la liste de classe d'élément parent <li>, pas l'élément lui-même; i.e <li class="active">..</li>. Alors j'ai écrit ceci:

.directive('setParentActive', ['$location', function($location) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs, controller) {
      var classActive = attrs.setParentActive || 'active',
          path = attrs.ngHref.replace('#', '');
      scope.location = $location;
      scope.$watch('location.path()', function(newPath) {
        if (path == newPath) {
          element.parent().addClass(classActive);
        } else {
          element.parent().removeClass(classActive);
        }
      })
    }
  }
}])

utilisation set-parent-active; .active est la valeur par défaut, il n'est donc pas nécessaire de le définir 

<li><a ng-href="#/about" set-parent-active>About</a></li>

et l'élément <li> parent sera .active lorsque le lien sera actif. Pour utiliser une autre classe .active telle que .highlight, il suffit de 

<li><a ng-href="#/about" set-parent-active="highlight">About</a></li>
1
davidkonrad

Utilisation de Angular Version 6 avec Bootstrap 4.1

J'ai pu le faire comme on le voit ci-dessous.

Dans l'exemple ci-dessous, lorsque l'URL voit '/ contact', l'amorçage actif est ensuite ajouté à la balise html. Lorsque l'URL change, il est ensuite supprimé.

<ul>
<li class="nav-item" routerLink="/contact" routerLinkActive="active">
    <a class="nav-link" href="/contact">Contact</a>
</li>
</ul>

Cette directive vous permet d'ajouter une classe CSS à un élément lorsque le lien est route devient active. 

En savoir plus sur Site angulaire

1
Jeacovy Gayle

J'ai trouvé la solution la plus simple. juste pour comparer indexOf en HTML 

var myApp = angular.module ('myApp', []);

myApp.run(function($rootScope) {
    $rootScope.$on("$locationChangeStart", function(event, next, current) { 
         $rootScope.isCurrentPath = $location.path();  
    });
});



<li class="{{isCurrentPath.indexOf('help')>-1 ? 'active' : '' }}">
<a href="/#/help/">
          Help
        </a>
</li>
0
NishantVerma.Me
$scope.getClass = function (path) {
return String(($location.absUrl().split('?')[0]).indexOf(path)) > -1 ? 'active' : ''
}


<li class="listing-head" ng-class="getClass('/v/bookings')"><a href="/v/bookings">MY BOOKING</a></li>
<li class="listing-head" ng-class="getClass('/v/fleets')"><a href="/v/fleets">MY FLEET</a></li>
<li class="listing-head" ng-class="getClass('/v/adddriver')"><a href="/v/adddriver">ADD DRIVER</a></li>
<li class="listing-head" ng-class="getClass('/v/bookings')"><a href="/v/invoice">INVOICE</a></li>
<li class="listing-head" ng-class="getClass('/v/profile')"><a href="/v/profile">MY PROFILE</a></li>
<li class="listing-head"><a href="/v/logout">LOG OUT</a></li>
0
Ashish Gupta

Voici mes deux cents, cela fonctionne très bien.

NOTE: Cela ne correspond pas à childpages (c'est ce dont j'avais besoin).

Vue:

<a ng-class="{active: isCurrentLocation('/my-path')}"  href="/my-path" >
  Some link
</a>

Manette:

// make sure you inject $location as a dependency

$scope.isCurrentLocation = function(path){
    return path === $location.path()
}
0
Justus Romijn

Le plus important pour moi était de ne pas changer du tout le code de démarrage par défaut . Ici, c’est mon contrôleur de menu qui recherche les options de menu et ajoute ensuite le comportement souhaité.

file: header.js
function HeaderCtrl ($scope, $http, $location) {
  $scope.menuLinkList = [];
  defineFunctions($scope);
  addOnClickEventsToMenuOptions($scope, $location);
}

function defineFunctions ($scope) {
  $scope.menuOptionOnClickFunction = function () {
    for ( var index in $scope.menuLinkList) {
      var link = $scope.menuLinkList[index];
      if (this.hash === link.hash) {
        link.parentElement.className = 'active';
      } else {
        link.parentElement.className = '';
      }
    }
  };
}

function addOnClickEventsToMenuOptions ($scope, $location) {
  var liList = angular.element.find('li');
  for ( var index in liList) {
    var liElement = liList[index];
    var link = liElement.firstChild;
    link.onclick = $scope.menuOptionOnClickFunction;
    $scope.menuLinkList.Push(link);
    var path = link.hash.replace("#", "");
    if ($location.path() === path) {
      link.parentElement.className = 'active';
    }
  }
}

     <script src="resources/js/app/header.js"></script>
 <div class="navbar navbar-fixed-top" ng:controller="HeaderCtrl">
    <div class="navbar-inner">
      <div class="container-fluid">
        <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
          <span class="icon-bar"></span> <span class="icon-bar"></span> 
<span     class="icon-bar"></span>
        </button>
        <a class="brand" href="#"> <img src="resources/img/fom-logo.png"
          style="width: 80px; height: auto;">
        </a>
        <div class="nav-collapse collapse">
          <ul class="nav">
            <li><a href="#/platforms">PLATFORMS</a></li>
            <li><a href="#/functionaltests">FUNCTIONAL TESTS</a></li>
          </ul> 
        </div>
      </div>
    </div>
  </div>
0
user2599258

Je viens d'écrire une directive pour cela.

Usage:

<ul class="nav navbar-nav">
  <li active><a href="#/link1">Link 1</a></li>
  <li active><a href="#/link2">Link 2</a></li>
</ul>

La mise en oeuvre:

angular.module('appName')
  .directive('active', function ($location, $timeout) {
    return {
      restrict: 'A',
      link: function (scope, element, attrs) {
        // Whenever the user navigates to a different page...
        scope.$on('$routeChangeSuccess', function () {
          // Defer for other directives to load first; this is important
          // so that in case other directives are used that this directive
          // depends on, such as ng-href, the href is evaluated before
          // it's checked here.
          $timeout(function () {
            // Find link inside li element
            var $link = element.children('a').first();

            // Get current location
            var currentPath = $location.path();

            // Get location the link is pointing to
            var linkPath = $link.attr('href').split('#').pop();

            // If they are the same, it means the user is currently
            // on the same page the link would point to, so it should
            // be marked as such
            if (currentPath === linkPath) {
              $(element).addClass('active');
            } else {
              // If they're not the same, a li element that is currently
              // marked as active needs to be "un-marked"
              element.removeClass('active');
            }
          });
        });
      }
    };
  });

Tests:

'use strict';

describe('Directive: active', function () {

  // load the directive's module
  beforeEach(module('appName'));

  var element,
      scope,
      location,
      compile,
      rootScope,
      timeout;

  beforeEach(inject(function ($rootScope, $location, $compile, $timeout) {
    scope = $rootScope.$new();
    location = $location;
    compile = $compile;
    rootScope = $rootScope;
    timeout = $timeout;
  }));

  describe('with an active link', function () {
    beforeEach(function () {
      // Trigger location change
      location.path('/foo');
    });

    describe('href', function () {
      beforeEach(function () {
        // Create and compile element with directive; note that the link
        // is the same as the current location after the location change.
        element = angular.element('<li active><a href="#/foo">Foo</a></li>');
        element = compile(element)(scope);

        // Broadcast location change; the directive waits for this signal
        rootScope.$broadcast('$routeChangeSuccess');

        // Flush timeout so we don't have to write asynchronous tests.
        // The directive defers any action using a timeout so that other
        // directives it might depend on, such as ng-href, are evaluated
        // beforehand.
        timeout.flush();
      });

      it('adds the class "active" to the li', function () {
        expect(element.hasClass('active')).toBeTruthy();
      });
    });

    describe('ng-href', function () {
      beforeEach(function () {
        // Create and compile element with directive; note that the link
        // is the same as the current location after the location change;
        // however this time with an ng-href instead of an href.
        element = angular.element('<li active><a ng-href="#/foo">Foo</a></li>');
        element = compile(element)(scope);

        // Broadcast location change; the directive waits for this signal
        rootScope.$broadcast('$routeChangeSuccess');

        // Flush timeout so we don't have to write asynchronous tests.
        // The directive defers any action using a timeout so that other
        // directives it might depend on, such as ng-href, are evaluated
        // beforehand.
        timeout.flush();
      });

      it('also works with ng-href', function () {
        expect(element.hasClass('active')).toBeTruthy();
      });
    });
  });

  describe('with an inactive link', function () {
    beforeEach(function () {
      // Trigger location change
      location.path('/bar');

      // Create and compile element with directive; note that the link
      // is the NOT same as the current location after the location change.
      element = angular.element('<li active><a href="#/foo">Foo</a></li>');
      element = compile(element)(scope);

      // Broadcast location change; the directive waits for this signal
      rootScope.$broadcast('$routeChangeSuccess');

      // Flush timeout so we don't have to write asynchronous tests.
      // The directive defers any action using a timeout so that other
      // directives it might depend on, such as ng-href, are evaluated
      // beforehand.
      timeout.flush();
    });

    it('does not add the class "active" to the li', function () {
      expect(element.hasClass('active')).not.toBeTruthy();
    });
  });

  describe('with a formerly active link', function () {
    beforeEach(function () {
      // Trigger location change
      location.path('/bar');

      // Create and compile element with directive; note that the link
      // is the same as the current location after the location change.
      // Also not that the li element already has the class "active".
      // This is to make sure that a link that is active right now will
      // not be active anymore when the user navigates somewhere else.
      element = angular.element('<li class="active" active><a href="#/foo">Foo</a></li>');
      element = compile(element)(scope);

      // Broadcast location change; the directive waits for this signal
      rootScope.$broadcast('$routeChangeSuccess');

      // Flush timeout so we don't have to write asynchronous tests.
      // The directive defers any action using a timeout so that other
      // directives it might depend on, such as ng-href, are evaluated
      // beforehand.
      timeout.flush();
    });

    it('removes the "active" class from the li', function () {
      expect(element.hasClass('active')).not.toBeTruthy();
    });
  });
});
0
weltschmerz

eu le même problème. Voici ma solution :

.directive('whenActive',
  [
    '$location',
    ($location)->
      scope: true,
      link: (scope, element, attr)->
        scope.$on '$routeChangeSuccess', 
          () ->
            loc = "#"+$location.path()
            href = element.attr('href')
            state = href.indexOf(loc)
            substate = -1

            if href.length > 3
              substate = loc.indexOf(href)
            if loc.length is 2
              state = -1

            #console.log "Is Loc: "+loc+" in Href: "+href+" = "+state+" and Substate = "+substate

            if state isnt -1 or substate isnt -1
              element.addClass 'selected'
              element.parent().addClass 'current-menu-item'
            else if href is '#' and loc is '#/'
              element.addClass 'selected'
              element.parent().addClass 'current-menu-item'
            else
              element.removeClass 'selected'
              element.parent().removeClass 'current-menu-item'
  ])
0
Naxmeify

Voici une bien meilleure façon de le faire

<ul>
    <li ng-class="{ active: isActive('/tasks')}"><a href="/">Tasks</a></li>
</ul>

function tasksController($scope, $location) 
{ 
    $scope.isActive = function (viewLocation) { 
        return viewLocation === $location.path();
    };
}
0
Oluwaseye

La route:

$routeProvider.when('/Account/', { templateUrl: '/Home/Account', controller: 'HomeController' });

Le menu html:

<li id="liInicio" ng-class="{'active':url=='account'}">

Le controlle:

angular.module('Home').controller('HomeController', function ($scope, $http, $location) {
    $scope.url = $location.url().replace(/\//g, "").toLowerCase();
...

Le problème que j'ai trouvé ici est que l'élément de menu n'est actif que lorsque la page entière est chargée. Lorsque la vue partielle est chargée, le menu ne change pas. Quelqu'un sait pourquoi cela se produit?

0
Dago MX