Como definir a classe ativa bootstrap navbar com o Angular JS?


306

Se eu tiver uma barra de navegação no bootstrap com os itens

Home | About | Contact

Como defino a classe ativa para cada item de menu quando eles estão ativos? Ou seja, como posso definir class="active"quando a rota angular está em

  1. #/ para casa
  2. #/about para a página sobre
  3. #/contact para a página de contato


10
Isso é semelhante, mas não é uma "maneira angular" de destacar os botões de navegação.
user1876508

Possível duplicado de Set estilo aba ativa com AngularJS
Amit G

Se você estiver usando o roteamento angular , observe que a resposta perfeita está oculta abaixo: stackoverflow.com/a/43822400/474189 .
Duncan Jones

Respostas:


598

Uma maneira muito elegante é usar o ng-controller para executar um único controller fora da 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>

e inclua no controllers.js:

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

10
Como eu sou novo nisso, eu apreciaria se você pudesse fornecer um exemplo de como colocar isso em uma diretiva de cabeçalho, por favor.
mono68

41
Sugiro usar return $location.path().indexOf(viewLocation) == 0;em vez de modo que você pode pegar páginas com parâmetros bem
Sven Hecht

7
Isso faz o trabalho, mas dificilmente elegant- o nome da rota, por exemplo, /dogsprecisa ser duplicado na chamada paraisActive('/dogs')
wal

7
Se você estiver usando o roteador da interface do usuário, poderá usar as ui-sref-active/ui-sref-active-eqdiretivas, por exemplo. ui-sref-active-eq='active'ou ui-sref-active='active'para alcançar os mesmos resultados
Dan Pantry

10
@SvenHecht A preocupação com essa lógica é que um link da página inicial (/) corresponda a todos os outros caminhos.
Mwotton

51

Acabei de escrever uma diretiva para lidar com isso, para que você possa simplesmente adicionar o atributo bs-active-linkao <ul>elemento pai e, sempre que a rota for alterada, ele encontrará o link correspondente e adicionará a activeclasse ao correspondente <li>.

Você pode vê-lo em ação aqui: http://jsfiddle.net/8mcedv3b/

Exemplo de 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
i como este melhor do que a resposta aceita porque não há duplicação de dados de configuração, ou seja, as rotas próprios permanecem em um só lugar e isso só funciona ..
Aaron Anodide

1
funcionou para mim usando o scope. $ watch ("$ routeChangeSuccess", function () {.... em vez de scope. $ on ("$ routeChangeSuccess", function () {....
aemad

Tive que ajustar isso um pouco para meus próprios propósitos, mas resposta incrível! Fácil o suficiente para entender.
Tony anziano

38

Você pode dar uma olhada no AngularStrap , a diretiva navbar parece ser o que você está procurando:

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

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

Para usar esta diretiva:

  1. Faça o download do AngularStrap em http://mgcrea.github.io/angular-strap/

  2. Inclua o script na sua página após o bootstrap.js:
    <script src="lib/angular-strap.js"></script>

  3. Adicione as diretrizes ao seu módulo:
    angular.module('myApp', ['$strap.directives'])

  4. Adicione a diretiva à sua barra de navegação:
    <div class="navbar" bs-navbar>

  5. Adicione expressões regulares em cada item de navegação:
    <li data-match-route="/about"><a href="#/about">About</a></li>


1
Obrigado. Isso me ajudou a corrigir minha própria directiva (o insight faltando para mim foi o scope.$watch)
Ngure Nyaga

Por que a elementvariável é passada para o seletor jquery? $('...', element)
Lucio

@Lucio, o método leva 2 argumentos - jQuery (seletor, contexto) - o segundo argumento é passar o contexto do seletor, o elemento DOM pai ou outro objeto jQuery - leia mais aqui
CoderTR

Isso funciona perfeitamente para mim - eu tinha que fazer uma alteração no entanto, por mgcrea.github.io/angular-strap a directiva para adicionar ao seu módulo é mgcrea.ngStrapnão$strap.directives
Vixxd

33

Aqui está uma abordagem simples que funciona bem com o 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>

Dentro do seu controlador AngularJS:

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

2
Boa abordagem. Eu o modifiquei um pouco - usei a diretiva da classe ng (ng-class = {active: isActive ('/ View1')}) e atualizei a função isActive para retornar verdadeiro / falso em vez do nome da classe.
patelsan

Copiei tudo como o seu exemplo e, para mim, $ location.path () não funcionou ... mudei para $ location.url () e funcionou!
Paulo Oliveira

14

Se você estiver trabalhando com roteador Angular, a diretiva RouterLinkActive pode ser usada de maneira muito elegante:

<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
Eu acho que essa deve ser a resposta aceita (pelo menos angular 2 +), por que implementar algo já está implementado? Mas para Bootstrap 3,3 a activeclasse deve estar no <li>(você pode colocar o routerLinkActive com o routerLink ou seu pai)
PhoneixS

3
Nota: se você usar /como sua página inicial, routerLinkActiveconsiderará ativo para qualquer URL que comece com /, por exemplo /foo/, /foo/baretc. Para corresponder exatamente, você precisa routerLinkActive="active" [routerLinkActiveOptions]="{exact:true}".
Duncan Jones

8

Em primeiro lugar, esse problema pode ser resolvido de várias maneiras. Dessa forma, pode não ser o mais elegante, mas certamente funciona.

Aqui está uma solução simples que você deve poder adicionar a qualquer projeto. Você pode simplesmente adicionar uma "pageKey" ou alguma outra propriedade ao configurar sua rota que pode ser usada para desativar. Além disso, você pode implementar um ouvinte no método $ routeChangeSuccess do objeto $ route para ouvir a conclusão bem-sucedida de uma alteração de rota.

Quando o manipulador é acionado, você obtém a chave da página e usa essa chave para localizar elementos que precisam ser "ATIVOS" para esta página e aplica a classe ACTIVE.

Lembre-se de que você precisa de uma maneira de tornar TODOS os elementos "ATIVOS". Como você pode ver, estou usando a classe .pageKey nos meus itens de navegação para desativá-los, e estou usando o .pageKey_ {PAGEKEY} para ativá-los individualmente. Mudar todos eles para inativos seria considerado uma abordagem ingênua; potencialmente, você obteria melhor desempenho usando a rota anterior para desativar apenas os itens ativos ou alterar o seletor de jquery para selecionar apenas os itens ativos a serem desativados. Usar o jquery para selecionar todos os itens ativos é provavelmente a melhor solução, pois garante que tudo esteja limpo para a rota atual no caso de qualquer erro de CSS que possa estar presente na rota anterior.

O que significaria alterar essa linha de código:

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

para este

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

Aqui está um exemplo de código:

Dada uma barra de navegação de auto-inicialização 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>

E um módulo angular e um controlador como o seguinte:

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

Você precisa rolar para a direita para ver os valores pageKey nas rotas, essa é a chave para toda a solução.
usar o seguinte código

16
Isso pode funcionar, mas é contra o conselho geral dos aplicativos Angular.js: no Angular, você deve evitar mexer com o DOM usando o jQuery; se você precisar tocar no DOM, escreva uma diretiva.
Paulo Scardine

isso é perfeito, se a manipulação do dom o incomoda, basta adicionar uma diretiva no .navbar, adicionar um evento $ broadcast no routechangesuccess, $ rootScope. $ broadcast ('routeChanged', current.pageKey); e depois capturá-lo no seu directiva e fazer as manipulações DOM lá
Irshu

7

Você pode realmente usar angular ui-utils ' ui-routedirectiva:

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

ou:

Controlador de cabeçalho

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

Página de índice

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

Se você estiver usando ui-utils, também poderá estar interessado no ui-router para gerenciar visualizações parciais / aninhadas.


A abordagem da interface do usuário é muito sedutora, mas até agora não consegui fazê-la funcionar no projeto gerado pelo gerador angular da Yeoman.
gabuzo 17/09/14

@gabuzo: Você instalou angular-ui-utils via bower?
Lèse majesté

6

Acho todas essas respostas um pouco mais complicadas para mim, desculpe. Então, eu criei uma pequena diretiva que deve funcionar com base na barra de navegação:

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

Uso:

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

Seu método funciona somente depois que você clica em um link na barra de navegação. Se você iniciar em um URL que seja "Foo", "Inicial" será selecionado ainda. por exemplo, iniciar no localhost: 9000 / # / contact faz com que a página inicial apareça selecionada na barra de navegação.
Adam Plocher

5

Eu uso a diretiva de classe ng com $ location para alcançá-lo.

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

Requer que a barra de navegação esteja dentro de um Controlador principal com acesso ao serviço $ location como este:

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

4

Você pode conseguir isso com uma condicional em uma expressão angular, como:

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

Dito isto, acho que uma diretiva angular é a maneira mais "adequada" de fazê-lo, embora a terceirização de grande parte dessa minilógica possa poluir um pouco sua base de código.

Uso condicionais para estilizar a GUI de vez em quando durante o desenvolvimento, porque é um pouco mais rápido que a criação de diretivas. Não pude contar uma instância em que eles realmente permaneceram na base de código por muito tempo. No final, eu a transformo em uma diretiva ou encontro uma maneira melhor de resolver o problema.


4

Se você usa o ui-router , o exemplo a seguir deve satisfazer suas necessidades com base no comentário do @ DanPantry na resposta aceita sem adicionar nenhum código do lado do controlador:

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

Você pode verificar os documentos para obter mais informações.


perfeito! certamente a solução mais limpa
Aryeh Beitz

simplesmente a melhor solução. quem não usa ui.router!
dewd

3

Se você preferir não usar o AngularStrap , esta diretiva deve funcionar! Esta é uma modificação 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>

Nota: As classes HTML acima assumem que você está usando o Bootstrap 3.x


3

Aqui está minha opinião sobre isso. Um pouco de uma combinação de respostas encontradas neste post. Como eu tinha um caso um pouco diferente, minha solução envolve separar o menu em seu próprio modelo para ser usado no Objetivo de Definição de Diretiva e adicionar minha barra de navegação à página em que eu precisava. Basicamente, eu tinha uma página de login na qual não queria incluir meu menu; portanto, usei ngInclude e insiro essa diretiva ao efetuar o login:

DIRETIVA:

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;

        }
    }
 }
});

MODELO DIRETO (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 QUE INCLUI A DIRETIVA

<comp-navbar/>

Espero que isto ajude


1
A função pode ser reduzida para apenas $ scope.isActive = function (viewLocation) {return viewLocation === $ location.path (); };
WP McNeill

2

Estendendo minha resposta, eu precisava disso para lidar com uma estrutura como esta.

-índice

-events <-ativo
--- lista de
eventos
--- edição de eventos --- mapa de eventos <-clicado

-places
--- lista
-de
-lugar --- edição-de -lugar --- mapa-de-lugar

então, em vez de fazer a correspondência, eu tive que usar o indexOf para validar links filhos formatados para corresponder à condição. Assim, para 'eventos':

<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

Esta é uma solução simples

<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

Em conjunto com a resposta AngularStrap do @ Olivier, também implementei a resposta do kevinknelson em: https://github.com/twbs/bootstrap/issues/9013 .

Nativamente, a barra de navegação do Bootstrap3 não foi projetada para um aplicativo de página única (por exemplo, Angular) e, portanto, o menu quando em uma tela pequena não estava desmoronando ao clicar.


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>

Isso não funciona - não adiciona a classe atual ao DOM
TheBlackBenzKid

1

Graças a @Pylinux . Eu usei a técnica dele e também a modifiquei para dar suporte a "um" nível do menu suspenso (sub ul / li), pois era disso que eu precisava. Veja-o em ação no link do violino abaixo.

Fiddle atualizado com base na resposta do pylinux - http://jsfiddle.net/abhatia/en4qxw6g/

Fiz as três alterações a seguir, para oferecer suporte a um nível no menu suspenso:
1. Adicionado um valor de classe dd (menu suspenso) para o elemento "a" em li, que precisa ter uma lista de 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 atualizado para adicionar a nova lógica a seguir.

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


3. CSS atualizado para adicionar o seguinte:

a.active {background-color:red;}

Esperamos que isso seja útil para quem procura implementar o menu suspenso de nível único.


1

Use um objeto como uma variável de opção.
Você pode fazer isso de forma simples com:

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

Cada vez que você clica em um link, o objeto do comutador é substituído por um novo objeto em que apenas a propriedade correta do objeto do comutador é verdadeira. As propriedades indefinidas serão avaliadas como falsas e, portanto, os elementos que dependem delas não terão a classe ativa atribuída.



0

Sugiro usar uma diretiva em um link. Aqui está o violino.

Mas ainda não é perfeito. Cuidado com os hashbangs;)

Aqui está o javascript para diretiva:

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

e aqui está como ele seria usado em 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>

depois estilizando com css:

.active{ color:red; }

0

Apenas para adicionar meus dois centavos no debate, criei um módulo angular puro (sem jquery) e ele também funcionará com URLs de hash contendo dados. ( ig #/this/is/path?this=is&some=data )

Você acabou de adicionar o módulo como uma dependência e auto-activea um dos ancestrais do menu. Como isso:

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

E o módulo fica assim:

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

* (Você pode, é claro, apenas usar a parte da diretiva)

** Também vale a pena notar que isso não funciona para hashes vazios ( ig example.com/# ou apenas example.com) que ele precisa ter pelo menos example.com/#/ou apenas example.com#/. Mas isso acontece automaticamente com o ngResource e similares.


Isso é desagradável. A razão para usar o Angular é a simplicidade.
quer

0

Isso fez o truque para mim:

  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

então você usa jquery (funciona com angular também) para adicionar classe ativa

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

e, claro, o css:

.active{background:red;}

isso funciona se você tiver seu html assim:

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

isso adiciona atumaticamente a classe ativa usando o URL da página e cor o fundo como vermelho se você estiver em www.somesite.com/ee thaen ee é o 'aplicativo' e estará ativo


0

Isso é respondido há muito tempo, mas pensei em compartilhar meu caminho:

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

Modelo:

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

Para aqueles que usam 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>

Para correspondência exata (por exemplo, estados aninhados?), Use $state.name === 'full/path/to/state'ouui-sref-active-eq="active"


0

Aqui está outra solução para quem possa estar interessado. A vantagem disso é que ele tem menos dependências. Heck, ele funciona sem um servidor web também. Portanto, é completamente do lado do cliente.

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>

Explicação:

Aqui estamos gerando as ligações dinamicamente a partir de um modelo AngularJS usando a diretiva ng-repeat. A mágica acontece com os métodos selectTab()e getTabClass()definidos no controlador para esta barra de navegação apresentada abaixo.

Controlador:

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

Explicação:

selectTab()O método é chamado usando ng-clickdiretiva. Então, quando o link é clicado, a variávelselectedTab é definida como o nome desse link. No HTML, você pode ver que esse método é chamado sem nenhum argumento para a guia Página inicial, para que seja destacado quando a página for carregada.

O getTabClass()método é chamado via ng-classdiretiva no HTML. Este método verifica se a guia em que está é igual ao valor da selectedTabvariável. Se verdadeiro, ele retorna "active" else else "", que é aplicado como o nome da classe pela ng-classdiretiva. Então, qualquer que seja o css que você aplicou à classe activeserá aplicado à guia selecionada.


O que acontece é que eu navego para outra guia por qualquer outro meio?
Miguel Carvajal

O que você quer dizer?
kovac 16/10

por exemplo, um link na página que leva você a outra página que está dentro de outra guia. Faz sentido?
Miguel Carvajal

Nesse caso, acho melhor usar o ui-router, conforme sugerido por Muli Yulzary na resposta acima. O ui-router atribui um estado a cada URL. Assim, quando alguém clicar no link, o usuário será roteado para esse link e o estado do aplicativo angular será atualizado. Então ui-sref = "active" destacará a guia. Aqui está a documentação do angular 2: ui-router.github.io/ng2 . Além disso, em vez de usar o bootstrap normal, observe o UI Bootstrap feito para uso com aplicativos Angular. Bootstrap da interface do usuário: angular-ui.github.io/bootstrap
kovac 16/10

0

Você precisará adicionar a activeclasse necessária com o código de cores necessário.

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.