Ustaw styl aktywnej karty za pomocą AngularJS

144

Mam trasy ustawione w AngularJS w ten sposób:

$routeProvider
    .when('/dashboard', {templateUrl:'partials/dashboard', controller:widgetsController})
    .when('/lab', {templateUrl:'partials/lab', controller:widgetsController})

Mam kilka linków na górnym pasku w stylu zakładek. Jak mogę dodać „aktywną” klasę do zakładki w zależności od aktualnego szablonu lub adresu URL?

Siergiej Baszarow
źródło
4
@AminMeyghani Jak to pytanie może być powtórzeniem pytania, które zadano prawie rok później ?
Regent

Odpowiedzi:

274

Sposobem rozwiązania tego problemu bez konieczności polegania na adresach URL jest dodanie atrybutu niestandardowego do każdej części podczas $routeProviderkonfiguracji, na przykład:

$routeProvider.
    when('/dashboard', {
        templateUrl: 'partials/dashboard.html',
        controller: widgetsController,
        activetab: 'dashboard'
    }).
    when('/lab', {
        templateUrl: 'partials/lab.html',
        controller: widgetsController,
        activetab: 'lab'
    });

Odsłoń $routew kontrolerze:

function widgetsController($scope, $route) {
    $scope.$route = $route;
}

Ustaw activeklasę w oparciu o aktualnie aktywną kartę:

<li ng-class="{active: $route.current.activetab == 'dashboard'}"></li>
<li ng-class="{active: $route.current.activetab == 'lab'}"></li>
Rob Juurlink
źródło
3
jest to najlepsze rozwiązanie, jakie do tej pory widziałem, ponieważ obsługuje dynamiczne adresy URL, takie jak / foo /: bar.
martinpaulucci,
3
właściwie nie udało mi się to uruchomić. czy byłbyś w stanie zapewnić plnkr?
PPPaul
9
Tylko jedno: lepiej ustawić $scope.activeTab = $route.current.activetab, aby kod HTML był trochę czystszy.
Christoph,
2
To nie działa w AngularJS 1.0.8. $ route.current jest niezdefiniowana.
Sum
2
Połącz to ze $rootScopesztuczką @ Lucasa poniżej, aby była dostępna we wszystkich zakresach.
colllin
134

Jednym ze sposobów na to byłoby użycie dyrektywy ngClass i usługi $ location. W swoim szablonie możesz:

ng-class="{active:isActive('/dashboard')}"

gdzie isActivebyłaby funkcja w zakresie zdefiniowanym w ten sposób:

myApp.controller('MyCtrl', function($scope, $location) {
    $scope.isActive = function(route) {
        return route === $location.path();
    }
});

Oto kompletny jsFiddle: http://jsfiddle.net/pkozlowski_opensource/KzAfG/

Powtarzanie ng-class="{active:isActive('/dashboard')}"na każdej karcie nawigacji może być żmudne (jeśli masz wiele kart), więc ta logika może być kandydatem do bardzo prostej dyrektywy.

pkozlowski.opensource
źródło
1
Zajęło mi dużo czasu, zanim odkryłem, że „bardzo proste dyrektywy” są w rzeczywistości bardzo łatwe do napisania, więc zamieściłem jedną poniżej. :-) Powinien nadawać się do wielokrotnego użytku w różnych kontekstach, bez niedeklaratywnej konfiguracji.
XML,
1
Patrząc na jsFiddle, jak ustawić bieżącą stronę jako aktywną podczas ładowania strony? Przykład działa tylko wtedy, gdy użytkownik kliknie opcję. Na przykład możesz chcieć, aby nawigacja „strona główna” była podświetlana po wylądowaniu na stronie głównej z linku zewnętrznego.
thathurtabit
Ahh drapałem się trochę po głowie. Dzięki!
masterwok
41

Zgodnie z radą Pawła, aby użyć niestandardowej dyrektywy, oto wersja, która nie wymaga dodawania ładunku do routeConfig, jest super deklaratywna i może być dostosowana do reagowania na dowolny poziom ścieżki, po prostu zmieniając, na którą slice()z nich zwracasz uwagę .

app.directive('detectActiveTab', function ($location) {
    return {
      link: function postLink(scope, element, attrs) {
        scope.$on("$routeChangeSuccess", function (event, current, previous) {
            /*  
                Designed for full re-usability at any path, any level, by using 
                data from attrs. Declare like this: 
                <li class="nav_tab">
                  <a href="#/home" detect-active-tab="1">HOME</a>
                </li> 
            */

            // This var grabs the tab-level off the attribute, or defaults to 1
            var pathLevel = attrs.detectActiveTab || 1,
            // This var finds what the path is at the level specified
                pathToCheck = $location.path().split('/')[pathLevel] || 
                  "current $location.path doesn't reach this level",
            // This var finds grabs the same level of the href attribute
                tabLink = attrs.href.split('/')[pathLevel] || 
                  "href doesn't include this level";
            // Above, we use the logical 'or' operator to provide a default value
            // in cases where 'undefined' would otherwise be returned.
            // This prevents cases where undefined===undefined, 
            // possibly causing multiple tabs to be 'active'.

            // now compare the two:
            if (pathToCheck === tabLink) {
              element.addClass("active");
            }
            else {
              element.removeClass("active");
            }
        });
      }
    };
  });

Osiągamy nasze cele, nasłuchując $routeChangeSuccesswydarzenia, a nie umieszczając $watchna ścieżce. Pracuję w przekonaniu, że to oznacza, że ​​logika powinna działać rzadziej, ponieważ myślę, że patrzy na ogień w każdym $digestcyklu.

Wywołaj go, przekazując argument na poziomie ścieżki w deklaracji dyrektywy. Określa, do jakiego fragmentu bieżącej $ location.path () chcesz dopasować hrefatrybut.

<li class="nav_tab"><a href="#/home" detect-active-tab="1">HOME</a></li>

Tak więc, jeśli twoje karty powinny reagować na podstawowy poziom ścieżki, wprowadź argument „1”. Tak więc, gdy location.path () to „/ home”, będzie pasować do „# / home” w href. Jeśli masz zakładki, które powinny reagować na drugi poziom, trzeci lub jedenasty odcinek ścieżki, dostosuj odpowiednio. To odcięcie od 1 lub wyższego spowoduje pominięcie nikczemnego „#” w href, który będzie miał indeks 0.

Jedynym wymaganiem jest wywołanie na <a>elemencie an , ponieważ element zakłada obecność hrefatrybutu, który będzie porównywać z bieżącą ścieżką. Jednak możesz dość łatwo dostosować się do odczytu / zapisu elementu nadrzędnego lub podrzędnego, jeśli wolisz wywołać <li>coś takiego. Kopię to, ponieważ możesz go ponownie użyć w wielu kontekstach, po prostu zmieniając argument pathLevel. Jeśli w logice przyjęto głębokość odczytu, potrzebnych byłoby wiele wersji dyrektywy do użycia z wieloma częściami nawigacji.


EDYCJA 18.03.14: Rozwiązanie nie zostało dostatecznie uogólnione i aktywowałoby się, gdyby zdefiniowano argument dla wartości „activeTab”, który zwraca undefinedzarówno wartość „activeTab”, jak $location.path()i wartość elementu href. Ponieważ: undefined === undefined. Zaktualizowano, aby naprawić ten stan.

Pracując nad tym, zdałem sobie sprawę, że powinna istnieć wersja, którą możesz po prostu zadeklarować w elemencie nadrzędnym, z taką strukturą szablonu:

<nav id="header_tabs" find-active-tab="1">
    <a href="#/home" class="nav_tab">HOME</a>
    <a href="#/finance" class="nav_tab">Finance</a>
    <a href="#/hr" class="nav_tab">Human Resources</a>
    <a href="#/quarterly" class="nav_tab">Quarterly</a>
</nav>

Zauważ, że ta wersja nie przypomina już zdalnie kodu HTML w stylu Bootstrap. Ale jest bardziej nowoczesny i zawiera mniej elementów, więc mam słabość do tego. Ta wersja dyrektywy oraz oryginał są teraz dostępne na Github jako moduł, który można po prostu zadeklarować jako zależność. Byłbym szczęśliwy mogąc je Bower-ize, gdyby ktokolwiek faktycznie ich używał.

Ponadto, jeśli chcesz mieć wersję kompatybilną z bootstrapem, która zawiera ten <li>, możesz skorzystać z modułu Angular-ui-bootstrap Tabs , który, jak sądzę, pojawił się po tym oryginalnym poście i który jest być może nawet bardziej deklaratywny niż ten. Jest mniej zwięzły w przypadku podstawowych rzeczy, ale zapewnia dodatkowe opcje, takie jak wyłączone karty i deklaratywne zdarzenia, które uruchamiają się podczas aktywacji i dezaktywacji.

XML
źródło
4
Nie mogłem uwierzyć, że nikt tak naprawdę nie odda głosu! Oto moje 2 centy. Chociaż w kodzie jest mały błąd, myślę, że „tabLevel” ma być „activeTab”. A w przypadku stylu Bootstrap możesz chcieć dodać „aktywną” klasę do elementu LI zamiast elementu A. Ale to wymaga tylko niewielkiej zmiany.
David Lin,
1
Masz całkowitą rację co do activeTab, @DavidLin. Edytowano. Ale nie jestem zakochany w strukturze Bootstrap, stąd celowa różnica. W rzeczywistości zaczynam myśleć, że abstrakcje nawigacyjne mogą w ogóle nie należeć uldo elementów, a być może powinny być po prostu kolekcjami kotwic, owiniętymi przez jakiś navlub inny element grupujący. Radzenie sobie z warstwą pośredniczącą lijest dodatkową złożonością bez żadnych korzyści, szczególnie teraz, gdy mamy do navdyspozycji element, który pozwala wyjaśnić, co się dzieje.
XML
To jest proste i genialne. Zaskoczyło mnie, że w Angular nie było już czegoś takiego do sprawdzania trasy, na której się znajdujesz.
Intellix,
1
Aby to działało z bootstrap3, wystarczy zmienić `element.addClass (" active ");` na `element.parent ('li'). AddClass (" active ");` Myślę, że mogłoby być lepiej choć nazwane, coś w rodzaju is-active-tab zamiast active-tab, które wydaje się deklarować, że karta jest aktywna. W przeciwnym razie jest to bardzo ładna dyrektywa. Zobacz tę zmianę w odpowiedzi @domi
boatcoder
Najlepsze rozwiązanie na tej stronie, nie mogę uwierzyć, że ma tak mało głosów pozytywnych.
Karolis,
27

@ rob-juurlink Poprawiłem trochę twoje rozwiązanie:

zamiast każdej trasy wymagającej aktywnej karty; i potrzebując ustawić aktywną kartę w każdym kontrolerze, robię to:

var App = angular.module('App',[]);
App.config(['$routeProvider', function($routeProvider){
  $routeProvider.
  when('/dashboard', {
    templateUrl: 'partials/dashboard.html',
    controller: Ctrl1
  }).
  when('/lab', {
    templateUrl: 'partials/lab.html',
    controller: Ctrl2
  });
}]).run(['$rootScope', '$location', function($rootScope, $location){
   var path = function() { return $location.path();};
   $rootScope.$watch(path, function(newVal, oldVal){
     $rootScope.activetab = newVal;
   });
}]);

A HTML wygląda tak. Activetab to tylko adres URL odnoszący się do tej trasy. To po prostu eliminuje potrzebę dodawania kodu do każdego kontrolera (przeciąganie zależności, takich jak $ route i $ rootScope, jeśli jest to jedyny powód ich użycia)

<ul>
    <li ng-class="{active: activetab=='/dashboard'}">
       <a href="#/dashboard">dashboard</a>
    </li>
    <li ng-class="{active: activetab=='/lab'}">
       <a href="#/lab">lab</a>
    </li>
</ul>
Lucas
źródło
Wielkie dzięki za tę modyfikację. Bardzo dobrze. Czy masz jakieś sugestie dotyczące ustawienia aktywnej karty podczas pierwszego wczytywania strony?
Hairgami_Master
2
zależy od tego, czego chcesz. zazwyczaj byłby to adres URL „/”, który byłby głównym kontrolerem. w ten sposób, gdy użytkownik przejdzie do twojego adresu URL, załaduje ten kontroler i ustawi tę kartę jako aktywną. W powyższym przykładzie nie mam adresu URL „/”, więc jeśli tak jest w Twoim przypadku, po prostu dodaj .otherwise () $ routeProvider. kiedy ('/ dashboard', {templateUrl: 'częściowe / dashboard.html', kontroler: Ctrl1}). kiedy ('/ lab', {templateUrl: 'częściowe / lab.html', kontroler: Ctrl2}). w przeciwnym razie ({redirectTo: '/ dashboard'}); powodzenia!
Lucas
Wielkie dzięki @Lucas. To pomogło. Z jakiegoś powodu musiałem dodać symbol # do mojej głównej trasy - when ('# /', {kontroler: FormsController, templateUrl: 'częściowe / dashboard.html'}).
Hairgami_Master
Wolę ten sposób. Posiadanie rootScope i robienie wszystkiego gdziekolwiek
wrivas
16

Może taka dyrektywa może rozwiązać Twój problem: http://jsfiddle.net/p3ZMR/4/

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>

JS

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 bot return including hashbang
            scope.location = location;
            scope.$watch('location.path()', function(newPath) {
                if (path === newPath) {
                    element.addClass(clazz);
                } else {
                    element.removeClass(clazz);
                }
            });
        }

    };

}]);
kfis
źródło
1
Zwróć uwagę, że musisz użyć $ observ, jeśli href zawiera wyrażenie: docs.angularjs.org/guide/directive#Attributes . Zobacz zaktualizowane skrzypce: jsfiddle.net/p3ZMR/10
Narretz
14

Najprostsze rozwiązanie tutaj:

Jak ustawić aktywną klasę bootstrap navbar w Angular JS?

Który jest:

Użyj ng-controller, aby uruchomić pojedynczy kontroler poza ng-view:

<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 umieść w controllers.js:

function HeaderController($scope, $location) 
{ 
    $scope.isActive = function (viewLocation) { 
        return viewLocation === $location.path();
    };
}
Zymotik
źródło
2
zgodził się, zdecydowanie najłatwiejszy
AngeloS
12

Polecam korzystanie z modułu state.ui, który nie tylko obsługuje wiele i zagnieżdżonych widoków, ale także bardzo ułatwia tego rodzaju pracę (kod poniżej zacytowany):

<ul class="nav">
    <li ng-class="{ active: $state.includes('contacts') }"><a href="#{{$state.href('contacts')}}">Contacts</a></li>
    <li ng-class="{ active: $state.includes('about') }"><a href="#{{$state.href('about')}}">About</a></li>
</ul>

Warte przeczytania.

David Lin
źródło
4

Oto kolejna wersja zmiany LI XMLillies w / domi, która używa ciągu wyszukiwania zamiast poziomu ścieżki. Myślę, że jest to trochę bardziej oczywiste, co dzieje się w moim przypadku użycia.

statsApp.directive('activeTab', function ($location) {
  return {
    link: function postLink(scope, element, attrs) {
      scope.$on("$routeChangeSuccess", function (event, current, previous) {
        if (attrs.href!=undefined) { // this directive is called twice for some reason
          // The activeTab attribute should contain a path search string to match on.
          // I.e. <li><a href="#/nested/section1/partial" activeTab="/section1">First Partial</a></li>
          if ($location.path().indexOf(attrs.activeTab) >= 0) {
            element.parent().addClass("active");//parent to get the <li>
          } else {
            element.parent().removeClass("active");
          }
        }
      });
    }
  };
});

HTML wygląda teraz następująco:

<ul class="nav nav-tabs">
  <li><a href="#/news" active-tab="/news">News</a></li>
  <li><a href="#/some/nested/photos/rawr" active-tab="/photos">Photos</a></li>
  <li><a href="#/contact" active-tab="/contact">Contact</a></li>
</ul>
Dave Rapin
źródło
3

Uważam, że odpowiedź XMLilley jest najlepsza, najbardziej elastyczna i nieinwazyjna.

Jednak miałem małą usterkę.

Do użytku z nawigacją bootstrap, oto jak go zmodyfikowałem:

app.directive('activeTab', function ($location) {
    return {
      link: function postLink(scope, element, attrs) {
        scope.$on("$routeChangeSuccess", function (event, current, previous) {
            /*  designed for full re-usability at any path, any level, by using 
                data from attrs
                declare like this: <li class="nav_tab"><a href="#/home" 
                                   active-tab="1">HOME</a></li> 
            */
            if(attrs.href!=undefined){// this directive is called twice for some reason
                // this var grabs the tab-level off the attribute, or defaults to 1
                var pathLevel = attrs.activeTab || 1,
                // this var finds what the path is at the level specified
                    pathToCheck = $location.path().split('/')[pathLevel],
                // this var finds grabs the same level of the href attribute
                    tabLink = attrs.href.split('/')[pathLevel];
                // now compare the two:
                if (pathToCheck === tabLink) {
                  element.parent().addClass("active");//parent to get the <li>
                }
                else {
                  element.parent().removeClass("active");
                }
            }
        });
      }
    };
  });

Dodałem „if (attrs.href! = Undefined)”, ponieważ ta funkcja jest wywoływana dwukrotnie, przy czym drugi raz powoduje błąd.

Co do html:

<ul class="nav nav-tabs">
   <li class="active" active-tab="1"><a href="#/accueil" active-tab="1">Accueil</a></li>
   <li><a active-tab="1" href="#/news">News</a></li>
   <li><a active-tab="1" href="#/photos" >Photos</a></li>
   <li><a active-tab="1" href="#/contact">Contact</a></li>
</ul>
domi
źródło
nvm, to moja wina, że ​​dzwoniono dwukrotnie. Wydaje mi się, że „if (attrs.href! = Undefined)” nie jest potrzebne.
domi
3

Przykład Bootstrap.

Jeśli używasz wbudowanego routingu Angulars (ngview), możesz użyć tej dyrektywy:

angular.module('myApp').directive('classOnActiveLink', [function() {
    return {
        link: function(scope, element, attrs) {

            var anchorLink = element.children()[0].getAttribute('ng-href') || element.children()[0].getAttribute('href');
            anchorLink = anchorLink.replace(/^#/, '');

            scope.$on("$routeChangeSuccess", function (event, current) {
                if (current.$$route.originalPath == anchorLink) {
                    element.addClass(attrs.classOnActiveLink);
                }
                else {
                    element.removeClass(attrs.classOnActiveLink);
                }
            });

        }
    };
}]);

Zakładając, że Twój znacznik wygląda następująco:

    <ul class="nav navbar-nav">
        <li class-on-active-link="active"><a href="/orders">Orders</a></li>
        <li class-on-active-link="active"><a href="/distributors">Distributors</a></li>
    </ul>

Podoba mi się, że to robię, ponieważ możesz ustawić nazwę klasy, którą chcesz w swoim atrybucie.

Michael Falck Wedelgård
źródło
2

Możesz także po prostu wstrzyknąć lokalizację do zakresu i użyć jej do odliczenia stylu nawigacji:

function IndexController( $scope, $rootScope, $location ) {
  $rootScope.location = $location;
  ...
}

Następnie użyj go w ng-class:

<li ng-class="{active: location.path() == '/search'}">
  <a href="/search">Search><a/>
</li>
Der Hochstapler
źródło
czy nie powinno to być $ root.location.path () w znaczniku?
Irshu
@Irshu: To mogłoby być czystsze, ale powyższe podejście zadziałało również dla mnie.
Der Hochstapler
2

alternatywnym sposobem jest użycie ui-sref-active

Dyrektywa działająca wraz z ui-sref, która dodaje klasy do elementu, gdy stan powiązanej dyrektywy ui-sref jest aktywna, i usuwa je, gdy jest nieaktywna. Podstawowym przypadkiem użycia jest uproszczenie specjalnego wyglądu menu nawigacyjnych opartych na interfejsie ui-sref, ponieważ przycisk menu stanu „aktywnego” wygląda inaczej, odróżniając go od nieaktywnych elementów menu.

Stosowanie:

ui-sref-active = 'class1 class2 class3' - klasy "class1", "class2" i "class3" są dodawane do elementu dyrektywy, gdy powiązany stan ui-sref jest aktywny, i usuwane, gdy jest nieaktywny.

Przykład:
biorąc pod uwagę następujący szablon,

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

gdy stan aplikacji to „app.user” i zawiera parametr stanu „user” o wartości „bilbobaggins”, wynikowy kod HTML pojawi się jako

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

Nazwa klasy jest interpolowana jeden raz podczas łączenia dyrektyw (wszelkie dalsze zmiany wartości interpolowanej są ignorowane). Wiele klas można określić w formacie oddzielonym spacjami.

Użyj dyrektywy ui-sref-opts, aby przekazać opcje do $ state.go (). Przykład:

<a ui-sref="home" ui-sref-opts="{reload: true}">Home</a>
George Botros
źródło
Dzięki. Jest to bardzo przydatne podczas pracy w frameworku jonowym!
Avijit Gupta,
1

Zgadzam się z postem Roba dotyczącym posiadania niestandardowego atrybutu w kontrolerze. Najwyraźniej nie mam wystarczającej liczby przedstawicieli, aby komentować. Oto żądany plik jsfiddle:

przykładowy html

<div ng-controller="MyCtrl">
    <ul>
        <li ng-repeat="link in links" ng-class="{active: $route.current.activeNav == link.type}"> <a href="{{link.uri}}">{{link.name}}</a>

        </li>
    </ul>
</div>

przykładowy plik app.js

angular.module('MyApp', []).config(['$routeProvider', function ($routeProvider) {
    $routeProvider.when('/a', {
        activeNav: 'a'
    })
        .when('/a/:id', {
        activeNav: 'a'
    })
        .when('/b', {
        activeNav: 'b'
    })
        .when('/c', {
        activeNav: 'c'
    });
}])
    .controller('MyCtrl', function ($scope, $route) {
    $scope.$route = $route;
    $scope.links = [{
        uri: '#/a',
        name: 'A',
        type: 'a'
    }, {
        uri: '#/b',
        name: 'B',
        type: 'b'
    }, {
        uri: '#/c',
        name: 'C',
        type: 'c'
    }, {
        uri: '#/a/detail',
        name: 'A Detail',
        type: 'a'
    }];
});

http://jsfiddle.net/HrdR6/

jasontwong
źródło
Podoba mi się podejście do listy linków oparte na danych. Niektórzy mogą zdecydować się na przeniesienie zestawu linków do usługi / fabryki.
Grant Lindsay
1
'use strict';

angular.module('cloudApp')
  .controller('MenuController', function ($scope, $location, CloudAuth) {
    $scope.menu = [
      {
        'title': 'Dashboard',
        'iconClass': 'fa fa-dashboard',
        'link': '/dashboard',
        'active': true
      },
      {
        'title': 'Devices',
        'iconClass': 'fa fa-star',
        'link': '/devices'
      },
      {
        'title': 'Settings',
        'iconClass': 'fa fa-gears',
        'link': '/settings'
      }
    ];
    $location.path('/dashboard');
    $scope.isLoggedIn = CloudAuth.isLoggedIn;
    $scope.isAdmin = CloudAuth.isAdmin;
    $scope.isActive = function(route) {
      return route === $location.path();
    };
  });

I użyj poniższego szablonu:

<li role="presentation" ng-class="{active:isActive(menuItem.link)}" ng-repeat="menuItem in menu"><a href="{{menuItem.link}}"><i class="{{menuItem.iconClass}}"></i>&nbsp;&nbsp;{{menuItem.title}}</a></li>
Yeshodhan Kulkarni
źródło
0

Potrzebowałem rozwiązania, które nie wymaga zmian w kontrolerach, ponieważ dla niektórych stron renderujemy tylko szablony i w ogóle nie ma kontrolera. Dzięki wcześniejszym komentatorom, którzy zasugerowali skorzystanie $routeChangeSuccess, wymyśliłem coś takiego:

# Directive
angular.module('myapp.directives')
.directive 'ActiveTab', ($route) ->
  restrict: 'A'

  link: (scope, element, attrs) ->
    klass = "active"

    if $route.current.activeTab? and attrs.flActiveLink is $route.current.activeTab
      element.addClass(klass)

    scope.$on '$routeChangeSuccess', (event, current) ->
      if current.activeTab? and attrs.flActiveLink is current.activeTab
        element.addClass(klass)
      else
        element.removeClass(klass)

# Routing
$routeProvider
.when "/page",
  templateUrl: "page.html"
  activeTab: "page"
.when "/other_page",
  templateUrl: "other_page.html"
  controller: "OtherPageCtrl"
  activeTab: "other_page"

# View (.jade)
a(ng-href='/page', active-tab='page') Page
a(ng-href='/other_page', active-tab='other_page') Other page

Nie zależy od adresów URL, dzięki czemu jest naprawdę łatwy do skonfigurowania dla dowolnych podstron itp.

szimek
źródło
0

Nie pamiętam, gdzie znalazłem tę metodę, ale jest dość prosta i działa dobrze.

HTML:

<nav role="navigation">
    <ul>
        <li ui-sref-active="selected" class="inactive"><a ui-sref="tab-01">Tab 01</a></li> 
        <li ui-sref-active="selected" class="inactive"><a ui-sref="tab-02">Tab 02</a></li>
    </ul>
</nav>

CSS:

  .selected {
    background-color: $white;
    color: $light-blue;
    text-decoration: none;
    border-color: $light-grey;
  } 
cfranklin
źródło
0

Jeśli używasz ngRoute (do routingu), Twoja aplikacja będzie miała poniższą konfigurację,

angular
  .module('appApp', [
    'ngRoute'
 ])
config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl',
        controllerAs: 'main'
      })
      .when('/about', {
        templateUrl: 'views/about.html',
        controller: 'AboutCtrl',
        controllerAs: 'about'
      })
}
});

Teraz wystarczy dodać kontroler w tej konfiguracji, tak jak poniżej,

angular
      .module('appApp', [
        'ngRoute'
     ])
    config(function ($routeProvider) {
        $routeProvider
          .when('/', {
            templateUrl: 'views/main.html',
            controller: 'MainCtrl',
            activetab: 'main'
          })
          .when('/about', {
            templateUrl: 'views/about.html',
            controller: 'AboutCtrl',
            activetab: 'about'
          })
    }
    })
  .controller('navController', function ($scope, $route) {
    $scope.$route = $route;
  });

Jak wspomniałeś o aktywnej karcie w swojej konfiguracji, teraz wystarczy dodać aktywną klasę do swojego tagu <li>lub <a>. Lubić,

ng-class="{active: $route.current.activetab == 'about'}"

Oznacza to, że za każdym razem, gdy użytkownik kliknie stronę o stronie, automatycznie zidentyfikuje bieżącą kartę i zastosuje aktywną klasę css.

Mam nadzieję, że to pomoże!

imbond
źródło
-3

Przyszedłem tutaj po rozwiązanie ... chociaż powyższe rozwiązania działają dobrze, ale okazało się, że są trochę skomplikowane, niepotrzebne. Dla osób, które wciąż szukają łatwego i zgrabnego rozwiązania, doskonale wykona zadanie.

<section ng-init="tab=1">
                <ul class="nav nav-tabs">
                    <li ng-class="{active: tab == 1}"><a ng-click="tab=1" href="#showitem">View Inventory</a></li>
                    <li ng-class="{active: tab == 2}"><a ng-click="tab=2" href="#additem">Add new item</a></li>
                    <li ng-class="{active: tab == 3}"><a ng-click="tab=3" href="#solditem">Sold item</a></li>
                </ul>
            </section>
MGA
źródło