javascript - routeractive - routerlink angular active




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

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

Home | About | Contact

Como faço para definir 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

https://code.i-harness.com


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

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

HTML de exemplo:

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

Apenas para adicionar meus dois centavos no debate eu fiz um módulo angular puro (não jquery), e ele também irá trabalhar com hash urls contendo dados. ( i.g. #/this/is/path?this=is&some=data )

Você acabou de adicionar o módulo como uma dependência e auto-active para 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 é 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 diretiva)

** Também é importante notar que isso não funciona para hashes vazios ( i.g. example.com/# ou apenas example.com ) ele precisa ter pelo menos example.com/#/ ou apenas example.com#/ . Mas isso acontece automaticamente com ngResource e afins.


Aqui está outra solução para qualquer pessoa que possa estar interessada. A vantagem disso é que tem menos dependências. Heck, funciona sem um servidor web também. Então é 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 os links dinamicamente a partir de um modelo angular 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 apresentados 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() método selectTab() é chamado usando ng-click diretiva ng-click . Portanto, quando o link é clicado, a variável selectedTab é definida como o nome desse link. No HTML, você pode ver que esse método é chamado sem nenhum argumento para a guia Início, para que ele seja destacado quando a página for carregada.

O método getTabClass() é chamado pela diretiva ng-class no HTML. Este método verifica se a guia em que está é igual ao valor da variável selectedTab . Se verdadeiro, retorna "ativo" senão retorna "" que é aplicado como o nome da classe pela diretiva ng-class . Então, qualquer css aplicado à turma active será aplicado à guia selecionada.


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

Em primeiro lugar, este problema pode ser resolvido de várias formas. Este caminho pode não ser o mais elegante, mas funciona com perfeição.

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 seu manipulador é acionado, você obtém a chave da página e usa essa chave para localizar os elementos que precisam estar "ATIVOS" para essa página e aplica a classe ATIVA.

Tenha em mente que você precisa de uma maneira de tornar todos os elementos "IN ACTIVE". 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 para inativos, seria considerado uma abordagem ingênua, potencialmente você obteria um melhor desempenho usando a rota anterior para tornar apenas itens ativos inativos, ou você poderia alterar o seletor de jquery para selecionar apenas itens ativos a serem desativados. Usar o jquery para selecionar todos os itens ativos é provavelmente a melhor solução, pois garante que tudo seja limpo para a rota atual no caso de quaisquer erros css que possam estar presentes na rota anterior.

O que significaria alterar esta linha de código:

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

para este

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

Aqui está um código de amostra:

Dado um bootstrap navbar 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 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>

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>

Eu acho todas essas respostas um pouco mais complicadas para mim, desculpe. Então eu criei uma pequena diretiva que deve funcionar em uma base por navbar:

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>

Eu uso a diretiva ng-class 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 assim:

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

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 (trabalha com o 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 o seu html assim:

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

isso irá adicionar atemicamente a classe ativa usando o URL da página e colorir seu plano de fundo para vermelho se o seu em www.somesite.com/ee thaen ee for o 'app' e ele estará ativo


Isso foi respondido por muito tempo, mas eu pensei em dividir 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 o 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 a correspondência exata (por exemplo, estados aninhados?) Use $state.name === 'full/path/to/state' ou ui-sref-active-eq="active"


Se você preferir não usar http://mgcrea.github.io/angular-strap/ então esta diretiva deve fazer o truque !. Esta é uma modificação do https://.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


Se você usa o ui-router , o exemplo a seguir deve satisfazer suas necessidades com base no comentário do @ DanPantry sobre a 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 docs para mais informações sobre ele.


Uma maneira muito elegante é usar o ng-controller para rodar um único controlador 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 em controllers.js:

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

Use um objeto como uma variável de switch.
Você pode fazer isso inline simplesmente 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 switch é substituído por um novo objeto, no qual apenas a propriedade correta do objeto switch é verdadeira. As propriedades indefinidas serão avaliadas como falsas e, portanto, os elementos que dependem delas não terão a classe ativa designada.


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 em sua página após o bootstrap.js:
    <script src="lib/angular-strap.js"></script>

  3. Adicione as diretivas 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>


Você pode realmente usar angular-ui-utils diretiva de ui-route angular-ui-utils :

<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, talvez também esteja interessado em ui-router para gerenciar visualizações parciais / aninhadas.


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>

Apenas você terá que adicionar a activeclasse necessária com o código de cores necessário.

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







navbar