Jak ustawić aktywną klasę paska startowego paska nawigacyjnego za pomocą Angular JS?


306

Jeśli mam pasek nawigacyjny w bootstrapie z przedmiotami

Home | About | Contact

Jak ustawić aktywną klasę dla każdej pozycji menu, gdy są one aktywne? To znaczy, jak mogę ustawić, class="active"kiedy trasa kątowa jest na

  1. #/ dla domu
  2. #/about na stronie z informacjami
  3. #/contact na stronie kontaktowej


10
Jest to podobne, ale nie jest to „kątowy sposób” podświetlania przycisków nawigacyjnych.
user1876508,


Jeśli używasz routingu Angular , pamiętaj, że idealna odpowiedź została ukryta poniżej: stackoverflow.com/a/43822400/474189 .
Duncan Jones

Odpowiedzi:


598

Bardzo eleganckim sposobem jest użycie kontrolera ng do uruchomienia pojedynczego kontrolera poza widokiem 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>

i dołącz do kontrolerów.js:

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

10
Ponieważ jestem nowy w tej kwestii, byłbym wdzięczny, gdyby mógł Pan podać przykład, w jaki sposób umieścić to w dyrektywie nagłówkowej.
mono68,

41
Sugeruję użycie return $location.path().indexOf(viewLocation) == 0;zamiast tego, abyś mógł również złapać strony z parametrami
Sven Hecht

7
Wykonuje to zadanie, ale nie jest to trudne elegant- nazwa trasy np. /dogsMusi zostać zduplikowana w wezwaniu doisActive('/dogs')
wal

7
Jeśli korzystasz z routera interfejsu użytkownika, możesz skorzystać z ui-sref-active/ui-sref-active-eqdyrektyw, tj. ui-sref-active-eq='active'lub ui-sref-active='active'by osiągnąć te same wyniki
Dan Pantry

10
@SvenHecht Problem z tą logiką polega na tym, że link do strony głównej (/) pasowałby do każdej innej ścieżki.
mwotton

51

Właśnie napisałem dyrektywę, aby to obsłużyć, więc możesz po prostu dodać atrybut bs-active-linkdo <ul>elementu nadrzędnego , a za każdym razem, gdy zmieni się trasa, znajdzie pasujące łącze i doda activeklasę do odpowiedniego<li> .

Możesz zobaczyć to w akcji tutaj: http://jsfiddle.net/8mcedv3b/

Przykładowy 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
podoba mi się to lepiej niż zaakceptowana odpowiedź, ponieważ nie ma powielania danych konfiguracyjnych, tj. same trasy pozostają w jednym miejscu i to po prostu działa ..
Aaron Anodide

1
pracował dla mnie przy użyciu scope. $ watch ("$ routeChangeSuccess", function () {.... zamiast scope. $ on ("$ routeChangeSuccess", function () {....
aemad

Musiałem dostosować to trochę do własnych celów, ale świetna odpowiedź! Łatwo to zrozumieć.
Tony Anziano

38

Możesz rzucić okiem na AngularStrap , dyrektywa navbar wydaje się być tym, czego szukasz:

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');
          }

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

Aby skorzystać z tej dyrektywy:

  1. Pobierz AngularStrap z http://mgcrea.github.io/angular-strap/

  2. Dołącz skrypt na swojej stronie po bootstrap.js:
    <script src="lib/angular-strap.js"></script>

  3. Dodaj dyrektywy do swojego modułu:
    angular.module('myApp', ['$strap.directives'])

  4. Dodaj dyrektywę do paska nawigacyjnego:
    <div class="navbar" bs-navbar>

  5. Dodaj wyrażenia regularne do każdego elementu nawigacji:
    <li data-match-route="/about"><a href="#/about">About</a></li>


1
Dzięki. To pomogło mi naprawić własną dyrektywę (brakowało mi wglądu w to scope.$watch)
Ngure Nyaga

Dlaczego elementzmienna jest przekazywana do selektora jquery? $('...', element)
Lucio

@Lucio metoda przyjmuje 2 argumenty - jQuery (selektor, kontekst) - drugim argumentem jest przekazanie kontekstu selektora, nadrzędnego elementu DOM lub innego samego obiektu jQuery - czytaj więcej tutaj
CoderTR

Działa to dla mnie idealnie - musiałem jednak dokonać jednej zmiany, zgodnie z mgcrea.github.io/angular-strap dyrektywa, którą należy dodać do modułu, mgcrea.ngStrapnie jest$strap.directives
Vixxd

33

Oto proste podejście, które działa dobrze w 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>

W twoim kontrolerze AngularJS:

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

2
Niezłe podejście. Trochę go zmodyfikowałem - użyłem dyrektywy ng-class (ng-class = {active: isActive ('/ View1')}) i zaktualizowałem funkcję isActive, aby zwracała true / false zamiast samej nazwy klasy.
patelsan

Skopiowałem wszystko jak w twoim przykładzie i dla mnie $ location.path () nie działało ... zmieniłem na $ location.url () i działało!
Paulo Oliveira,

14

Jeśli pracujesz z routerem Angular, dyrektywa RouterLinkActive może być używana bardzo elegancko:

<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
Myślę, że powinna to być zaakceptowana odpowiedź (przynajmniej dla kątowej 2+), dlaczego implementacja coś jest już zaimplementowana? Ale w przypadku Bootstrap 3.3 activeklasa powinna być w <li>(możesz ustawić routerLinkActive z routLink lub jego rodzicem)
PhoneixS

3
Uwaga: jeśli używasz /jako strony głównej, routerLinkActiveweźmie pod uwagę, że aktywna dla dowolnego adresu URL zaczynającym się /np /foo/, /foo/baritp dopasować dokładnie, czego potrzebujesz routerLinkActive="active" [routerLinkActiveOptions]="{exact:true}".
Duncan Jones,

8

Przede wszystkim problem ten można rozwiązać na wiele sposobów. Ten sposób może nie być najbardziej elegancki, ale na pewno działa.

Oto proste rozwiązanie, które powinieneś być w stanie dodać do każdego projektu. Możesz po prostu dodać „pageKey” lub inną właściwość podczas konfigurowania trasy, której możesz użyć do wyłączenia. Dodatkowo można zaimplementować detektor w metodzie $ routeChangeSuccess obiektu $ route, aby nasłuchiwać pomyślnego zakończenia zmiany trasy.

Kiedy twój handler odpala, dostajesz klawisz strony i użyj go, aby zlokalizować elementy, które muszą być „AKTYWNE” dla tej strony, i zastosuj klasę ACTIVE.

Pamiętaj, że potrzebujesz sposobu, aby WSZYSTKIE elementy były „AKTYWNE”. Jak widać, używam klasy .pageKey na moich elementach nawigacyjnych, aby je wszystkie wyłączyć, i używam .pageKey_ {PAGEKEY}, aby je indywidualnie włączyć. Przełączenie ich wszystkich w nieaktywne byłoby uważane za naiwne podejście, potencjalnie można uzyskać lepszą wydajność, korzystając z poprzedniej trasy, aby unieruchomić tylko aktywne elementy, lub można zmienić selektor jquery, aby wybrać tylko aktywne elementy, które mają być nieaktywne. Użycie jquery do zaznaczenia wszystkich aktywnych elementów jest prawdopodobnie najlepszym rozwiązaniem, ponieważ zapewnia, że ​​wszystko zostanie wyczyszczone dla bieżącej trasy w przypadku błędów css, które mogły występować na poprzedniej trasie.

Co oznaczałoby zmianę tego wiersza kodu:

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

do tego

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

Oto przykładowy kod:

Biorąc pod uwagę pasek startowy

<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>

I moduł kątowy i kontroler, takie jak:

<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>

Musisz przewinąć w prawo, aby zobaczyć wartości pageKey na trasach, to jest klucz do całego tego rozwiązania.
Mark At Ramp51

16
Może to działać, ale jest to sprzeczne z ogólną radą dla aplikacji Angular.js: w Angular powinieneś powstrzymać się od bałagania w DOM przy użyciu jQuery; jeśli musisz dotknąć DOM, napisz dyrektywę.
Paulo Scardine

jest to idealne rozwiązanie, jeśli przeszkadza ci manipulacja domem, po prostu dodaj dyrektywę na .navbar, dodaj zdarzenie $ broadcast w routeechangesuccess, $ rootScope. $ broadcast ('routeChanged', current.pageKey); a następnie przechwyć to na swojej dyrektywie i
dokonaj

7

Rzeczywiście można użyć -UI-utils kątową ' ui-routedyrektywę:

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

lub:

Kontroler nagłówka

/**
 * 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.'
      }
    ];
  });

Strona indeksu

<!-- 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>

Jeśli używasz interfejsu użytkownika, możesz również interesować się interfejsem użytkownika do zarządzania widokami częściowymi / zagnieżdżonymi.


Podejście do trasy ui jest bardzo kuszące, ale jak dotąd nie udało mi się sprawić, by działało ono w projekcie generowanym przez generator kątowy Yeomana.
gabuzo

@gabuzo: Czy zainstalowałeś angular-ui-utils za pomocą altany?
Lèse majesté

6

Niestety, wszystkie te odpowiedzi są dla mnie zbyt skomplikowane. Stworzyłem więc małą dyrektywę, która powinna działać dla poszczególnych pasków nawigacyjnych:

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');
            });
        }
    };
});

Stosowanie:

<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>

Twoja metoda działa tylko po kliknięciu łącza na pasku nawigacyjnym. Jeśli zaczniesz od adresu URL, który jest „Foo”, „Strona główna” będzie początkowo nadal wybierana. np. uruchomienie na localhost: 9000 / # / contact powoduje, że Home pojawia się wybrany na pasku nawigacyjnym.
Adam Plocher

5

Aby to osiągnąć, używam dyrektywy klasy ng z $ location.

<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>

Wymaga, aby pasek nawigacyjny znajdował się w głównym kontrolerze z dostępem do usługi lokalizacji $ w następujący sposób:

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

4

Możesz to osiągnąć za pomocą warunkowego wyrażenia kątowego, takiego jak:

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

Biorąc to pod uwagę, uważam dyrektywę kątową za bardziej „właściwą” metodę, nawet jeśli outsourcing wielu z tej mini-logiki może nieco zanieczyścić bazę kodu.

Podczas projektowania używam warunkowej stylizacji GUI od czasu do czasu, ponieważ jest to trochę szybsze niż tworzenie dyrektyw. Nie mogę ci powiedzieć o instancji, w której faktycznie długo pozostawały w bazie kodu. W końcu albo przekształcę to w dyrektywę, albo znajdę lepszy sposób na rozwiązanie problemu.


4

Jeśli używasz interfejsu użytkownika routera , poniższy przykład powinien zaspokoić Twoje potrzeby w oparciu o komentarz @ DanPantry do zaakceptowanej odpowiedzi bez dodawania kodu po stronie kontrolera:

<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>

Możesz sprawdzić dokumenty, aby uzyskać więcej informacji na ten temat.


doskonały! na pewno najczystsze rozwiązanie
Aryeh Beitz

po prostu najlepsze rozwiązanie. kto nie korzysta ui.router!
dewd

3

Jeśli wolisz nie używać AngularStrap, ta dyrektywa powinna załatwić sprawę ! To jest modyfikacja 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>

Uwaga: powyższe klasy HTML zakładają, że używasz Bootstrap 3.x


3

Oto moje zdanie na ten temat. Trochę kombinacji odpowiedzi znalezionych w tym poście. Miałem nieco inny przypadek, więc moje rozwiązanie polega na podzieleniu menu na własny szablon do użycia w definicji dyrektywy Ojbect, a następnie dodaniu paska nawigacyjnego do strony, na której go potrzebowałem. Zasadniczo miałem stronę logowania, do której nie chciałem dołączać swojego menu, więc użyłem ngInclude i wstawiłem tę dyrektywę po zalogowaniu:

DYREKTYWA:

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;

        }
    }
 }
});

SZABLON DYREKTYWNY (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, KTÓRY ZAWIERA DYREKTYWĘ

<comp-navbar/>

Mam nadzieję że to pomoże


1
Funkcję można skrócić do tylko $ scope.isActive = function (viewLocation) {return viewLocation === $ location.path (); };
WP McNeill

2

Rozszerzając odpowiedź myl, potrzebowałem tego do obsługi takiej struktury.

-indeks

-events <-aktywna
--- lista
zdarzeń
--- edycja zdarzeń --- mapa zdarzeń <-kliknięcie

-places
--- lista
-miejsc
--- edycja-miejsc --- mapa-miejsc

więc zamiast dopasowywania musiałem użyć indexOf, aby zweryfikować łącza potomne sformatowane pod kątem spełnienia warunku. Tak więc w przypadku „wydarzeń”:

<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

To proste rozwiązanie

<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

W połączeniu z odpowiedzią AngularStrap @ Oliviera zaimplementowałem również odpowiedź Kevinknelsona z: https://github.com/twbs/bootstrap/issues/9013 .

Natywnie pasek nawigacyjny Bootstrap3 nie został zaprojektowany dla aplikacji jednostronicowej (np. Angular), a zatem menu na małym ekranie nie zwijało się po kliknięciu.


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>

To nie działa - nie dodaje bieżącej klasy do DOM
TheBlackBenzKid

1

Dzięki @Pylinux . Użyłem jego techniki, a także zmodyfikowałem ją, aby obsługiwała „jeden” poziom menu rozwijanego (sub ul / li), ponieważ tego właśnie potrzebowałem. Zobacz to w akcji w linku skrzypce poniżej.

Zaktualizowano Fiddle na podstawie odpowiedzi pylinuksa - http://jsfiddle.net/abhatia/en4qxw6g/

Dokonałem następujących trzech zmian, aby obsłużyć menu rozwijane o jeden poziom:
1. Dodałem wartość klasy dd (menu rozwijane) dla elementu „a” pod li, który musi mieć listę podrzędną.

         <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. Zaktualizowano Javascript, aby dodać następującą nową logikę.

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


3. Zaktualizowano CSS, aby dodać:

a.active {background-color:red;}

Mam nadzieję, że będzie to pomocne dla kogoś, kto chce wdrożyć menu rozwijane na jednym poziomie.


1

Użyj obiektu jako zmiennej przełączającej.
Możesz to zrobić po prostu za pomocą:

<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>

Za każdym razem, gdy klikniesz łącze, obiekt przełączający jest zastępowany nowym obiektem, w którym tylko poprawna właściwość obiektu przełączającego jest prawdziwa. Niezdefiniowane właściwości zostaną ocenione jako fałszywe, więc elementy zależne od nich nie będą miały przypisanej klasy aktywnej.



0

Sugeruję użycie dyrektywy dotyczącej linku. Oto skrzypce.

Ale jeszcze nie jest idealny. Uważaj na hashbangi;)

Oto javascript dla dyrektywy:

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);
          }
        });
      }
    };
  }]);

a oto, jak miałby być użyty w 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>

następnie stylizacja za pomocą css:

.active{ color:red; }

0

Aby dodać dwa centy do debaty, stworzyłem czysty moduł kątowy (bez jquery), i będzie on również działał z adresami skrótu zawierającymi dane. ( ig #/this/is/path?this=is&some=data )

Po prostu dodajesz moduł jako zależność i auto-activedo jednego z przodków menu. Lubię to:

<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>

Moduł wygląda następująco:

(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);
            }
        }
    }]);
}());

* (Oczywiście możesz po prostu użyć części dotyczącej dyrektywy)

** Warto również zauważyć, że nie działa to dla pustych skrótów ( ig example.com/# lub po prostu example.com), musi mieć przynajmniej example.com/#/lub po prostu example.com#/. Ale dzieje się to automatycznie z ngResource i podobnymi.


To jest po prostu paskudne. Powodem użycia Angulara jest prostota.
Tom Stickel,

0

To załatwiło sprawę:

  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

następnie używasz jquery (działa również z angular), aby dodać klasę aktywną

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

i oczywiście css:

.active{background:red;}

działa to, jeśli masz swój HTML:

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

to atumatycznie doda klasę aktywną za pomocą adresu URL strony i pokoloruje tło na czerwono, jeśli jesteś na stronie www.somesite.com/ee thaen ee to „aplikacja” i będzie ona aktywna


0

To jest długo odpowiedź, ale pomyślałem, że podzielę się swoją drogą:

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

Szablon:

<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>

Dla osób używających 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>

Aby dopasować dokładnie (np. Stany zagnieżdżone?) Użyj $state.name === 'full/path/to/state'lubui-sref-active-eq="active"


0

Oto inne rozwiązanie dla każdego, kto może być zainteresowany. Zaletą tego jest to, że ma mniej zależności. Cholera, działa również bez serwera WWW. Więc to całkowicie po stronie klienta.

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>

Wyjaśnienie:

Tutaj generujemy linki dynamicznie z modelu angularjs przy użyciu dyrektywy ng-repeat. Magia dzieje się z metodami selectTab()i getTabClass()zdefiniowany w sterowniku dla tego paska nawigacyjnego przedstawionej poniżej.

Kontroler:

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 : "";
    };
});

Wyjaśnienie:

selectTab()Metoda jest wywoływana przy użyciu ng-clickdyrektywy. Tak więc po kliknięciu łącza zmienna selectedTabjest ustawiana na nazwę tego łącza. W kodzie HTML widać, że ta metoda jest wywoływana bez żadnego argumentu na karcie Narzędzia główne, dzięki czemu zostanie podświetlona podczas ładowania strony.

getTabClass()Metoda jest wywoływana przez ng-classdyrektywę w HTML. Ta metoda sprawdza, czy zakładka, w której się znajduje, jest taka sama jak wartość selectedTabzmiennej. Jeśli true, zwraca „aktywne”, w przeciwnym razie zwraca „”, które jest stosowane jako nazwa klasy przezng-class dyrektywę. Następnie css zastosowany do klasy activezostanie zastosowany do wybranej karty.


Co się dzieje, że przechodzę do innej karty w jakikolwiek inny sposób?
Miguel Carvajal

Co masz na myśli?
kovac

na przykład link na stronie, który prowadzi do innej strony, która znajduje się na innej karcie. Ma sens?
Miguel Carvajal

W takim przypadku myślę, że lepiej użyć interfejsu użytkownika routera, jak sugeruje Muli Yulzary w odpowiedzi powyżej. ui-router przypisuje stan do każdego adresu URL. Tak więc, gdy ktoś kliknie link, użytkownik zostanie przekierowany do tego łącza, a stan aplikacji kątowej zostanie zaktualizowany. Następnie ui-sref = "active" podświetli zakładkę. Oto dokumentacja kątowa 2: ui-router.github.io/ng2 . Ponadto zamiast zwykłego bootstrapu spójrz na Bootstrap interfejsu użytkownika wykonany dla aplikacji Angular. Bootstrap interfejsu użytkownika: angular-ui.github.io/bootstrap
kovac

0

Musisz tylko dodać wymaganą activeklasę z wymaganym kodem koloru.

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.