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


306

Si j'ai une barre de navigation en bootstrap avec les articles

Home | About | Contact

Comment définir la classe active pour chaque élément de menu lorsqu'ils sont actifs? Autrement dit, comment puis-je définir class="active"lorsque la route angulaire est à

  1. #/ Pour la maison
  2. #/about pour la page à propos
  3. #/contact pour la page contact


10
C'est similaire, mais ce n'est pas une "manière angulaire" de mettre en surbrillance les boutons de navigation.
user1876508


Si vous utilisez le routage angulaire , veuillez noter que la réponse parfaite est enterrée ci-dessous: stackoverflow.com/a/43822400/474189 .
Duncan Jones

Réponses:


598

Une manière très élégante consiste à utiliser ng-controller pour exécuter un seul contrôleur en dehors de la vue ng:

<div class="collapse navbar-collapse" ng-controller="HeaderController">
    <ul class="nav navbar-nav">
        <li ng-class="{ active: isActive('/')}"><a href="/">Home</a></li>
        <li ng-class="{ active: isActive('/dogs')}"><a href="/dogs">Dogs</a></li>
        <li ng-class="{ active: isActive('/cats')}"><a href="/cats">Cats</a></li>
    </ul>
</div>
<div ng-view></div>

et inclure dans controllers.js:

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

10
Étant donné que je suis nouveau dans ce domaine, j'apprécierais si vous pouviez fournir un exemple sur la façon de mettre cela dans une directive d'en-tête, s'il vous plaît.
mono68

41
Je suggère d'utiliser à la return $location.path().indexOf(viewLocation) == 0;place pour que vous puissiez également attraper des pages avec des paramètres
Sven Hecht

7
Cela fait le travail, mais ce n'est guère elegant- le nom de la route, par exemple, /dogsdoit être dupliqué dans l'appel àisActive('/dogs')
wal

7
Si vous utilisez UI Router, vous pouvez utiliser les ui-sref-active/ui-sref-active-eqdirectives, c'est-à-dire. ui-sref-active-eq='active'ou ui-sref-active='active'pour obtenir les mêmes résultats
Dan Pantry

10
@SvenHecht Le problème avec cette logique est qu'un lien vers la page d'accueil (/) correspondrait à tous les autres chemins.
mwotton

51

Je viens d'écrire une directive pour gérer cela, vous pouvez donc simplement ajouter l'attribut bs-active-linkà l' <ul>élément parent , et chaque fois que la route changera, il trouvera le lien correspondant et ajoutera la activeclasse au correspondant <li>.

Vous pouvez le voir en action ici: http://jsfiddle.net/8mcedv3b/

Exemple HTML:

<ul class="nav navbar-nav" bs-active-link>
  <li><a href="/home">Home</a></li>
  <li><a href="/contact">Contact</a></li>
</ul>

Javascript:

angular.module('appName')
.directive('bsActiveLink', ['$location', function ($location) {
return {
    restrict: 'A', //use as attribute 
    replace: false,
    link: function (scope, elem) {
        //after the route has changed
        scope.$on("$routeChangeSuccess", function () {
            var hrefs = ['/#' + $location.path(),
                         '#' + $location.path(), //html5: false
                         $location.path()]; //html5: true
            angular.forEach(elem.find('a'), function (a) {
                a = angular.element(a);
                if (-1 !== hrefs.indexOf(a.attr('href'))) {
                    a.parent().addClass('active');
                } else {
                    a.parent().removeClass('active');   
                };
            });     
        });
    }
}
}]);

1
j'aime mieux cela que la réponse acceptée car il n'y a pas de duplication des données de configuration, c'est-à-dire que les routes elles-mêmes restent en un seul endroit et cela fonctionne juste ..
Aaron Anodide

1
travaillé pour moi en utilisant scope. $ watch ("$ routeChangeSuccess", function () {.... au lieu de scope. $ on ("$ routeChangeSuccess", function () {....
aemad

J'ai dû peaufiner cela un peu à mes propres fins, mais réponse géniale! Assez facile à comprendre.
Tony Anziano

38

Vous pouvez jeter un œil à AngularStrap , la directive navbar semble être ce que vous cherchez:

https://github.com/mgcrea/angular-strap/blob/master/src/navbar/navbar.js

.directive('bsNavbar', function($location) {
  'use strict';

  return {
    restrict: 'A',
    link: function postLink(scope, element, attrs, controller) {
      // Watch for the $location
      scope.$watch(function() {
        return $location.path();
      }, function(newValue, oldValue) {

        $('li[data-match-route]', element).each(function(k, li) {
          var $li = angular.element(li),
            // data('match-rout') does not work with dynamic attributes
            pattern = $li.attr('data-match-route'),
            regexp = new RegExp('^' + pattern + '$', ['i']);

          if(regexp.test(newValue)) {
            $li.addClass('active');
          } else {
            $li.removeClass('active');
          }

        });
      });
    }
  };
});

Pour utiliser cette directive:

  1. Téléchargez AngularStrap depuis http://mgcrea.github.io/angular-strap/

  2. Incluez le script sur votre page après bootstrap.js:
    <script src="lib/angular-strap.js"></script>

  3. Ajoutez les directives à votre module:
    angular.module('myApp', ['$strap.directives'])

  4. Ajoutez la directive à votre barre de navigation:
    <div class="navbar" bs-navbar>

  5. Ajoutez des expressions régulières sur chaque élément de navigation:
    <li data-match-route="/about"><a href="#/about">About</a></li>


1
Merci. Cela m'a aidé à corriger ma propre directive (le point de vue manquant pour moi était le scope.$watch)
Ngure Nyaga

Pourquoi la elementvariable est-elle transmise au sélecteur jquery? $('...', element)
Lucio

@Lucio la méthode prend 2 arguments - jQuery (sélecteur, contexte) - le deuxième argument est de passer le contexte du sélecteur, soit l'élément DOM parent ou un autre objet jQuery lui-même - lire la suite ici
CoderTR

Cela fonctionne parfaitement pour moi - j'ai cependant dû faire un changement, par mgcrea.github.io/angular-strap, la directive à ajouter à votre module n'est mgcrea.ngStrappas$strap.directives
Vixxd

33

Voici une approche simple qui fonctionne bien avec Angular.

<ul class="nav navbar-nav">
    <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>

Au sein de votre contrôleur AngularJS:

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

2
Belle approche. Je l'ai modifié un peu - utilisé la directive ng-class (ng-class = {active: isActive ('/ View1')}) et mis à jour la fonction isActive pour renvoyer true / false au lieu du nom de classe lui-même.
patelsan

J'ai tout copié comme votre exemple, et pour moi $ location.path () n'a pas fonctionné ... basculé sur $ location.url (), et cela a fonctionné!
Paulo Oliveira

14

Si vous travaillez avec un routeur angulaire, la directive RouterLinkActive peut être utilisée de manière très élégante:

<ul class="navbar-nav">
  <li class="nav-item"><a class="nav-link" routerLink="home" routerLinkActive="active">Home</a></li>
  <li class="nav-item"><a class="nav-link" routerLink="gallery" routerLinkActive="active">Gallery</a></li>
  <li class="nav-item"><a class="nav-link" routerLink="pricing" routerLinkActive="active">Prices</a></li>
  <li class="nav-item"><a class="nav-link" routerLink="contact" routerLinkActive="active">Contact</a></li>
</ul>

2
Je pense que cela devrait être la réponse acceptée (pour angulaire 2+ au moins), pourquoi implémenter quelque chose est déjà implémenté? Mais pour Bootstrap 3.3, la activeclasse devrait être dans le <li>(vous pouvez mettre routerLinkActive avec routerLink ou son parent)
PhoneixS

3
Remarque: si vous utilisez /comme votre page d'accueil, routerLinkActiveconsidérera que actif pour toute URL commençant par /, par exemple /foo/, /foo/baretc. Pour correspondre exactement, vous avez besoin routerLinkActive="active" [routerLinkActiveOptions]="{exact:true}".
Duncan Jones

8

Tout d'abord, ce problème peut être résolu de nombreuses façons. Cette voie n'est peut-être pas la plus élégante, mais elle fonctionne toujours.

Voici une solution simple que vous devriez pouvoir ajouter à n'importe quel projet. Vous pouvez simplement ajouter une "pageKey" ou une autre propriété lorsque vous configurez votre itinéraire que vous pouvez utiliser pour vous déconnecter. En outre, vous pouvez implémenter un écouteur sur la méthode $ routeChangeSuccess de l'objet $ route pour écouter la réussite d'une modification de route.

Lorsque votre gestionnaire se déclenche, vous obtenez la clé de page et utilisez cette clé pour localiser les éléments qui doivent être «ACTIFS» pour cette page et vous appliquez la classe ACTIVE.

Gardez à l'esprit que vous avez besoin d'un moyen de rendre TOUS les éléments "EN ACTIVITÉ". Comme vous pouvez le voir, j'utilise la classe .pageKey sur mes éléments de navigation pour les désactiver tous, et j'utilise le .pageKey_ {PAGEKEY} pour les activer individuellement. Les passer tous à inactifs serait considéré comme une approche naïve, vous obtiendriez potentiellement de meilleures performances en utilisant la route précédente pour ne rendre inactifs que les éléments actifs, ou vous pourriez modifier le sélecteur jquery pour sélectionner uniquement les éléments actifs à rendre inactifs. L'utilisation de jquery pour sélectionner tous les éléments actifs est probablement la meilleure solution car elle garantit que tout est nettoyé pour l'itinéraire actuel en cas de bogues CSS qui pourraient avoir été présents sur l'itinéraire précédent.

Ce qui signifierait changer cette ligne de code:

$(".pagekey").toggleClass("active", false);

à celui-ci

$(".active").toggleClass("active", false);

Voici un exemple de code:

Étant donné une barre de navigation bootstrap de

<div class="navbar navbar-inverse">
    <div class="navbar-inner">
        <a class="brand" href="#">Title</a>
        <ul class="nav">
            <li><a href="#!/" class="pagekey pagekey_HOME">Home</a></li>
            <li><a href="#!/page1/create" class="pagekey pagekey_CREATE">Page 1 Create</a></li>
            <li><a href="#!/page1/edit/1" class="pagekey pagekey_EDIT">Page 1 Edit</a></li>
            <li><a href="#!/page1/published/1" class="pagekey pagekey_PUBLISH">Page 1 Published</a></li>
        </ul>
    </div>
</div>

Et un module angulaire et un contrôleur comme celui-ci:

<script type="text/javascript">

    function Ctrl($scope, $http, $routeParams, $location, $route) {

    }



    angular.module('BookingFormBuilder', []).
        config(function ($routeProvider, $locationProvider) {
            $routeProvider.
                when('/', { 
                   template: 'I\'m on the home page', 
                   controller: Ctrl, 
                   pageKey: 'HOME' }).
                when('/page1/create', { 
                   template: 'I\'m on page 1 create', 
                   controller: Ctrl, 
                   pageKey: 'CREATE' }).
                when('/page1/edit/:id', { 
                   template: 'I\'m on page 1 edit {id}', 
                   controller: Ctrl, pageKey: 'EDIT' }).
                when('/page1/published/:id', { 
                   template: 'I\'m on page 1 publish {id}', 
                   controller: Ctrl, pageKey: 'PUBLISH' }).
                otherwise({ redirectTo: '/' });

            $locationProvider.hashPrefix("!");
        }).run(function ($rootScope, $http, $route) {

            $rootScope.$on("$routeChangeSuccess", 
                           function (angularEvent, 
                                     currentRoute,
                                     previousRoute) {

                var pageKey = currentRoute.pageKey;
                $(".pagekey").toggleClass("active", false);
                $(".pagekey_" + pageKey).toggleClass("active", true);
            });

        });

</script>

Vous devez faire défiler vers la droite pour voir les valeurs de pageKey sur les itinéraires, c'est la clé de toute cette solution.
Mark At Ramp51

16
Cela peut fonctionner, mais est contraire aux conseils généraux pour les applications Angular.js: dans Angular, vous devez vous abstenir de jouer avec le DOM à l'aide de jQuery; si vous devez toucher le DOM, écrivez une directive.
Paulo Scardine

c'est parfait, si la manipulation dom vous dérange, ajoutez simplement une directive sur la .navbar, ajoutez un événement $ broadcast dans routechangesuccess, $ rootScope. $ broadcast ('routeChanged', current.pageKey); puis le capturer sur votre directive et y faire les manipulations dom
Irshu

7

Vous pouvez réellement utiliser la directive angular-ui-utilsui-route :

<a ui-route ng-href="/">Home</a>
<a ui-route ng-href="/about">About</a>
<a ui-route ng-href="/contact">Contact</a>

ou:

Contrôleur d'en-tête

/**
 * Header controller
 */
angular.module('myApp')
  .controller('HeaderCtrl', function ($scope) {
    $scope.menuItems = [
      {
        name: 'Home',
        url:  '/',
        title: 'Go to homepage.'
      },
      {
        name:   'About',
        url:    '/about',
        title:  'Learn about the project.'
      },
      {
        name:   'Contact',
        url:    '/contact',
        title:  'Contact us.'
      }
    ];
  });

Sommaire

<!-- index.html: -->
<div class="header" ng-controller="HeaderCtrl">
  <ul class="nav navbar-nav navbar-right">
    <li ui-route="{{menuItem.url}}" ng-class="{active: $uiRoute}"
      ng-repeat="menuItem in menuItems">
      <a ng-href="#{{menuItem.url}}" title="{{menuItem.title}}">
        {{menuItem.name}}
      </a>
    </li>
  </ul>
</div>

Si vous utilisez ui-utils, vous pouvez également être intéressé par ui-router pour gérer les vues partielles / imbriquées.


L'approche ui-route est très séduisante mais jusqu'à présent je n'ai pas réussi à la faire fonctionner sur le projet généré par le générateur angulaire de Yeoman.
gabuzo

@ gabuzo: Avez-vous installé angular-ui-utils via bower?
Lèse majesté

6

Je trouve toutes ces réponses un peu trop compliquées pour moi, désolé. J'ai donc créé une petite directive qui devrait fonctionner par barre de navigation:

app.directive('activeLink', function () {
    return {
        link: function (scope, element, attrs) {
            element.find('.nav a').on('click', function () {
                angular.element(this)
                    .parent().siblings('.active')
                    .removeClass('active');
                angular.element(this)
                    .parent()
                    .addClass('active');
            });
        }
    };
});

Usage:

<ul class="nav navbar-nav navbar-right" active-link>
    <li class="nav active"><a href="home">Home</a></li>
    <li class="nav"><a href="foo">Foo</a></li>
    <li class="nav"><a href="bar">Bar</a></li>
</ul>

Votre méthode ne fonctionne qu'après avoir cliqué sur un lien dans la barre de navigation. Si vous commencez sur une URL qui est "Foo", "Home" sera initialement sélectionné. Par exemple, si vous démarrez sur localhost: 9000 / # / contact , le domicile apparaît sélectionné dans la barre de navigation.
Adam Plocher

5

J'utilise la directive ng-class avec $ location pour y parvenir.

<ul class="nav">
<li data-ng-class="{active: ($location.path() == '/') }">
    <a href="#/">Carpeta Amarilla</a>
</li>
<li class="dropdown" data-ng-class="{active: ($location.path() == '/auditoria' || $location.path() == '/auditoria/todos') }">
    <a class="dropdown-toggle" data-toggle="dropdown" href="#">
        Auditoria
        <b class="caret"></b>
    </a>
    <ul class="dropdown-menu pull-right">
        <li data-ng-class="{active: ($location.path() == '/auditoria') }">
            <a href="#/auditoria">Por Legajo</a>
        </li>
        <li data-ng-class="{active: ($location.path() == '/auditoria/todos') }">
            <a href="#/auditoria/todos">General</a>
        </li>
    </ul>
</li>
</ul>

Il nécessite que la barre de navigation soit à l'intérieur d'un contrôleur principal avec accès au service $ location comme ceci:

bajasApp.controller('MenuCntl', ['$scope','$route', '$routeParams', '$location', 
   function MenuCntl($scope, $route, $routeParams, $location) {
   $scope.$route = $route;
   $scope.$location = $location;
   $scope.$routeParams = $routeParams;
}]);

4

Vous pouvez y parvenir avec un conditionnel dans une expression angulaire, tel que:

<a href="#" class="{{ condition ? 'active' : '' }}">link</a>

Cela étant dit, je trouve qu'une directive angulaire est la façon la plus "appropriée" de le faire, même si l'externalisation d'une grande partie de cette mini-logique peut quelque peu polluer votre base de code.

J'utilise des conditions pour le style GUI de temps en temps pendant le développement, car c'est un peu plus rapide que la création de directives. Je ne pourrais pas vous dire cependant une instance dans laquelle ils sont restés dans la base de code pendant longtemps. En fin de compte, je la transforme en directive ou je trouve un meilleur moyen de résoudre le problème.


4

Si vous utilisez ui-router , l'exemple suivant devrait satisfaire vos besoins en fonction du commentaire de @ DanPantry sur la réponse acceptée sans ajouter de code côté contrôleur:

<div class="collapse navbar-collapse" ng-controller="HeaderController">
    <ul class="nav navbar-nav">
        <li ui-sref-active="active"><a ui-sref="app.home()" href="/">Home</a></li>
        <li ui-sref-active="active"><a ui-sref="app.dogs()" href="/dogs">Dogs</a></li>
        <li ui-sref-active="active"><a ui-sref="app.cats()" href="/cats">Cats</a></li>
    </ul>
</div>
<div ng-view></div>

Vous pouvez consulter la documentation pour plus d'informations à ce sujet.


parfait! sûrement la solution la plus propre
Aryeh Beitz

tout simplement la meilleure solution qui soit. qui n'utilise pas ui.router!
rosée du

3

Si vous préférez ne pas utiliser AngularStrap, cette directive devrait faire l'affaire!. Il s'agit d'une modification de https://stackoverflow.com/a/16231859/910764 .

Javascript

angular.module('myApp').directive('bsNavbar', ['$location', function ($location) {
  return {
    restrict: 'A',
    link: function postLink(scope, element) {
      scope.$watch(function () {
        return $location.path();
      }, function (path) {
        angular.forEach(element.children(), (function (li) {
          var $li = angular.element(li),
            regex = new RegExp('^' + $li.attr('data-match-route') + '$', 'i'),
            isActive = regex.test(path);
          $li.toggleClass('active', isActive);
        }));
      });
    }
  };
}]);

HTML

<ul class="nav navbar-nav" bs-navbar>
  <li data-match-route="/home"><a href="#/home">Home</a></li>
  <li data-match-route="/about"><a href="#/about">About</a></li>
</ul>

Remarque: Les classes HTML ci-dessus supposent que vous utilisez Bootstrap 3.x


3

Voici ma façon de voir les choses. Un peu d'une combinaison de réponses trouvées sur ce post. J'avais un cas légèrement différent, donc ma solution consiste à séparer le menu dans son propre modèle à utiliser dans la définition de directive Ojbect, puis à ajouter ma barre de navigation à la page sur laquelle j'en avais besoin. Fondamentalement, j'avais une page de connexion sur laquelle je ne voulais pas inclure mon menu, j'ai donc utilisé ngInclude et inséré cette directive lors de la connexion:

DIRECTIF:

module.directive('compModal', function(){


return {
    restrict: 'E',
    replace: true,
    transclude: true,
    scope: true,
    templateUrl: 'templates/menu.html',
    controller: function($scope, $element, $location){
        $scope.isActive = function(viewLocation){

            var active = false;

            if(viewLocation === $location.path()){
                active = true;
            }

            return active;

        }
    }
 }
});

MODÈLE DE DIRECTIVE (templates / menu.html)

<ul class="nav navbar-nav">
  <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>

HTML QUI COMPREND LA DIRECTIVE

<comp-navbar/>

J'espère que cela t'aides


1
La fonction peut être raccourcie à seulement $ scope.isActive = function (viewLocation) {return viewLocation === $ location.path (); };
WP McNeill

2

En étendant la réponse myl, j'avais besoin de cela pour gérer une structure comme celle-ci.

-indice

-events <-active
--- liste- d'événements --- édition-
événement
--- carte-événement <-cliqué

-places
--- place-list
--- place-edit
--- place-map

donc au lieu de correspondre, j'ai dû utiliser indexOf, afin de valider les liens enfants qui sont formatés pour correspondre à la condition. Donc pour les «événements»:

<li ng-class="{ active: isActive('/event')}" class="divider-vertical dropdown">


function NavController($scope, $location) { 
$scope.isActive = function (viewLocation) {
    var s=false;
    if($location.path().indexOf(viewLocation) != -1){
     s = true;
    }
    return s;
};}

2

Ceci est une solution simple

<ul class="nav navbar-nav navbar-right navbar-default menu">
  <li ng-class="menuIndice == 1 ? 'active':''">
    <a ng-click="menuIndice = 1" href="#/item1">item1</a>
  </li>
  <li ng-class="menuIndice == 2 ? 'active':''">
    <a ng-click="menuIndice = 2" href="#/item2">item2</a>
  </li>
  <li ng-class="menuIndice == 3 ? 'active':''">
    <a ng-click="menuIndice = 3" href="#/item3">item3</a>
  </li>
</ul>

1

En conjonction avec la réponse AngularStrap de @ Olivier, j'ai également implémenté la réponse de kevinknelson à partir de: https://github.com/twbs/bootstrap/issues/9013 .

De manière native, la barre de navigation Bootstrap3 n'était pas conçue pour une application d'une seule page (par exemple angulaire) et donc le menu sur un petit écran ne s'effondrait pas au clic.


1

Javascript

/**
 * Main AngularJS Web Application
 */

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


/**
 * Setup Main Menu
 */

app.controller('MainNavCtrl', [ '$scope', '$location', function ( $scope, $location) {
    $scope.menuItems = [
        {
            name: 'Home',
            url:  '/home',
            title: 'Welcome to our Website'
        },
        {
            name: 'ABOUT',
            url:  '/about',
            title: 'Know about our work culture'
        },
        {
            name:   'CONTACT',
            url:    '/contact',
            title:  'Get in touch with us'
        }
    ];

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

HTML

  <div class="navbar-collapse collapse" ng-controller="MainNavCtrl">
    <ul id="add-magic-line" class="nav navbar-nav navbar-right">
      <li data-ng-class="{current_page_item: isActive('{{ menuItem.url }}')}" data-ng-repeat="menuItem in menuItems">
        <a data-ng-href="#{{menuItem.url}}" title="{{menuItem.title}}">
          {{menuItem.name}}
        </a>
      </li>
    </ul>
  </div>

Cela ne fonctionne pas - il n'ajoute pas la classe actuelle au DOM
TheBlackBenzKid

1

Merci à @Pylinux . J'ai utilisé sa technique et l'ai également modifiée pour prendre en charge "un" niveau de menu déroulant (sub ul / li), car c'est ce dont j'avais besoin. Voyez-le en action dans le lien violon ci-dessous.

Mise à jour de Fiddle basée sur la réponse de pylinux - http://jsfiddle.net/abhatia/en4qxw6g/

J'ai apporté les trois changements suivants, afin de prendre en charge un menu déroulant d'un niveau:
1. Ajout d'une valeur de classe dd (liste déroulante) pour l'élément "a" sous li qui doit avoir une liste sub ul.

         <li><a class="dd">This link points to #/fun5</a>
          <ul>
            <li><a href="#/fun6?some=data">This link points to #/fun6</a>
            </li>
            <li><a href="#/fun7?some=data">This link points to #/fun7</a>
            </li>
            <li><a href="#/fun8?some=data">This link points to #/fun8</a>
            </li>
            <li><a href="#/fun9?some=data">This link points to #/fun9</a>
            </li>
          </ul>
        </li>


2. Javascript mis à jour pour ajouter la nouvelle logique suivante.

 if(angular.element(li).parent().parent().children('a').hasClass("dd"))
 {angular.element(li).parent().parent().children('a.dd').addClass('active');}


3. CSS mis à jour pour ajouter ce qui suit:

a.active {background-color:red;}

J'espère que cela sera utile à quelqu'un qui cherche à implémenter un menu déroulant à un seul niveau.


1

Utilisez un objet comme variable de commutation.
Vous pouvez le faire en ligne tout simplement avec:

<ul class="nav navbar-nav">
   <li ng-class="{'active':switch.linkOne}" ng-click="switch = {linkOne: true}"><a href="/">Link One</a></li>
   <li ng-class="{'active':switch.linkTwo}" ng-click="switch = {link-two: true}"><a href="/link-two">Link Two</a></li>
</ul>

Chaque fois que vous cliquez sur un lien, l'objet commutateur est remplacé par un nouvel objet dans lequel seule la propriété d'objet commutateur correcte est vraie. Les propriétés non définies seront évaluées comme fausses et donc les éléments qui en dépendent n'auront pas la classe active assignée.



0

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

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 styling avec css:

.active{ color:red; }

0

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

Vous venez d'ajouter 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 ( ig example.com/# ou simplement example.com) qu'il doit avoir au moins example.com/#/ou juste example.com#/. Mais cela se produit automatiquement avec ngResource et similaires.


C'est juste méchant. La raison d'utiliser Angular est la simplicité.
Tom Stickel

0

Cela a fait l'affaire pour moi:

  var domain = '{{ DOMAIN }}'; // www.example.com or dev.example.com
  var domain_index =  window.location.href.indexOf(domain);
  var long_app_name = window.location.href.slice(domain_index+domain.length+1); 
  // this turns http://www.example.com/whatever/whatever to whatever/whatever
  app_name = long_app_name.slice(0, long_app_name.indexOf('/')); 
  //now you are left off with just the first whatever which is usually your app name

puis vous utilisez jquery (fonctionne également avec angular) pour ajouter la classe active

$('nav a[href*="' + app_name+'"]').closest('li').addClass('active');

et bien sûr le css:

.active{background:red;}

cela fonctionne si vous avez votre html comme ceci:

<ul><li><a href="/ee">ee</a></li><li><a href="/dd">dd</a></li></ul>

cela ajoutera atumatiquement la classe active en utilisant l'url de la page et colorera votre arrière-plan en rouge si vous êtes sur www.somesite.com/ee thaen ee est "l'application" et elle sera active


0

C'est une réponse longue mais j'ai pensé partager mon chemin:

.run(function($rootScope, $state){
 $rootScope.$state = $state;
});

Modèle:

<ul class="nav navbar-nav">
    <li ng-class="{ active: $state.contains('View1') }"><a href="...">View 1</a></li>
    <li ng-class="{ active: $state.contains('View2') }"><a href="...">View 2</a></li>
    <li ng-class="{ active: $state.contains('View3') }"><a href="...">View 3</a></li>
</ul>

Pour ceux qui utilisent ui-router:

<ul class="nav navbar-nav">
        <li ui-sref-active="active"><a href="...">View 1</a></li>
        <li ui-sref-active="active"><a href="...">View 2</a></li>
        <li ui-sref-active="active"><a href="...">View 3</a></li>
</ul>

Pour une correspondance exacte (par exemple, des états imbriqués?), Utilisez $state.name === 'full/path/to/state'ouui-sref-active-eq="active"


0

Voici une autre solution pour tous ceux qui pourraient être intéressés. L'avantage de cela est qu'il a moins de dépendances. Heck, cela fonctionne aussi sans serveur web. C'est donc complètement côté client.

HTML:

<nav class="navbar navbar-inverse" ng-controller="topNavBarCtrl"">
<div class="container-fluid">
    <div class="navbar-header">
        <a class="navbar-brand" href="#"><span class="glyphicon glyphicon-home" aria-hidden="true"></span></a>
    </div>
    <ul class="nav navbar-nav">
        <li ng-click="selectTab()" ng-class="getTabClass()"><a href="#">Home</a></li>
        <li ng-repeat="tab in tabs" ng-click="selectTab(tab)" ng-class="getTabClass(tab)"><a href="#">{{ tab }}</a></li>
    </ul>
</div>

Explication:

Ici, nous générons les liens dynamiquement à partir d'un modèle angularjs en utilisant la directive ng-repeat. La magie opère avec les méthodes selectTab()et getTabClass()définies dans le contrôleur pour cette barre de navigation présentée ci-dessous.

Manette:

angular.module("app.NavigationControllersModule", [])

// Constant named 'activeTab' holding the value 'active'. We will use this to set the class name of the <li> element that is selected.
.constant("activeTab", "active")

.controller("topNavBarCtrl", function($scope, activeTab){
    // Model used for the ng-repeat directive in the template.
    $scope.tabs = ["Page 1", "Page 2", "Page 3"];

    var selectedTab = null;

    // Sets the selectedTab.
    $scope.selectTab = function(newTab){
       selectedTab = newTab;
    };

    // Sets class of the selectedTab to 'active'.
    $scope.getTabClass = function(tab){
       return selectedTab == tab ? activeTab : "";
    };
});

Explication:

selectTab()est appelée en utilisant la ng-clickdirective. Ainsi, lorsque le lien est cliqué, la variableselectedTab est définie sur le nom de ce lien. Dans le code HTML, vous pouvez voir que cette méthode est appelée sans aucun argument pour l'onglet Accueil afin qu'elle soit mise en surbrillance lors du chargement de la page.

La getTabClass()méthode est appelée via ng-classdirective dans le HTML. Cette méthode vérifie si l'onglet dans lequel elle se trouve est identique à la valeur de la selectedTabvariable. Si vrai, il retourne "actif" sinon retourne "" qui est appliqué comme nom de classe par ng-classdirective. Ensuite, tout css que vous avez appliqué à la classe activesera appliqué à l'onglet sélectionné.


Que se passe-t-il si je navigue vers un autre onglet par tout autre moyen?
Miguel Carvajal

Que voulez-vous dire?
kovac du

par exemple un lien dans la page qui vous amène à une autre page qui se trouve dans un autre onglet. Logique?
Miguel Carvajal

Dans ce cas, je pense qu'il vaut mieux utiliser ui-router comme suggéré par Muli Yulzary dans la réponse ci-dessus. ui-router attribue un état à chaque URL. Ainsi, une fois que quelqu'un aura cliqué sur le lien, l'utilisateur sera dirigé vers ce lien et l'état de l'application angulaire sera mis à jour. Ensuite, ui-sref = "active" mettra en surbrillance l'onglet. Voici la documentation pour angular 2: ui-router.github.io/ng2 . De plus, au lieu d'utiliser le look bootstrap normal, UI Bootstrap fait pour une utilisation avec des applications angulaires. UI Bootstrap: angular-ui.github.io/bootstrap
kovac

0

Il vous suffit d'ajouter la activeclasse requise avec le code de couleur requis.

Ex: ng-class="{'active': currentNavSelected}" ng-click="setNav"

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.