Bagaimana cara menyorot item menu saat ini?

205

Apakah AngularJS membantu dengan cara menetapkan activekelas pada tautan untuk halaman saat ini?

Saya membayangkan ada beberapa cara ajaib yang dilakukan, tetapi sepertinya saya tidak dapat menemukannya.

Menu saya terlihat seperti:

 <ul>
   <li><a class="active" href="/tasks">Tasks</a>
   <li><a href="/actions">Tasks</a>
 </ul>

dan saya memiliki pengontrol untuk masing-masing di rute saya: TasksControllerdan ActionsController.

Tetapi saya tidak dapat menemukan cara untuk mengikat kelas "aktif" pada atautan ke pengontrol.

Ada petunjuk?

Andriy Drozdyuk
sumber

Jawaban:

265

pada tampilan

<a ng-class="getClass('/tasks')" href="/tasks">Tasks</a>

pada pengontrol

$scope.getClass = function (path) {
  return ($location.path().substr(0, path.length) === path) ? 'active' : '';
}

Dengan ini tautan tugas akan memiliki kelas aktif di url apa pun yang dimulai dengan '/ tugas' (mis. '/ Tugas / 1 / laporan')

Renan Tomal Fernandes
sumber
4
Ini akan berakhir dengan mencocokkan "/" dan "/ apa pun" atau jika Anda memiliki beberapa item menu dengan url yang serupa, seperti "/ test", "/ test / this", "/ test / this / path" jika Anda berada di / test, ini akan menyoroti semua opsi itu.
Ben Lesh
3
Saya telah mengubah ini menjadi if ($ location.path () == path) dan, y path adalah "/ bla" dll
Tim
113
Saya lebih suka notasi ngClass="{active: isActive('/tasks')}, di mana isActive()akan mengembalikan boolean karena decouples controller dan markup / styling.
Ed Hinchliffe
6
Kalau-kalau ada yang bertanya-tanya tentang kode untuk tidak menggandakan jika path adalah "/", ini dia (maaf untuk format): $ scope.getClass = function (path) {if ($ location.path (). substr (0, path.length) == path) {if (path == "/" && $ location.path () == "/") {return "active"; } lain jika (path == "/") {return ""; } return "active"} else {return ""}}
1
EdHinchliffe sudah menunjukkan bahwa ini menggabungkan markup dan logika. Ini juga mengarah pada duplikasi jalan dan karenanya rawan untuk menyalin & menempel kesalahan. Saya telah menemukan bahwa pendekatan direktif oleh @ kfis, meskipun lebih banyak baris, lebih dapat digunakan kembali dan membuat pembersih markup.
A. Murray
86

Saya sarankan menggunakan arahan pada tautan.

Tapi ini belum sempurna. Hati-hati dengan hashbangs;)

Berikut adalah javascript untuk direktif:

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

dan inilah bagaimana ini akan digunakan dalam 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>

setelah itu styling dengan css:

.active { color: red; }
kfis
sumber
Saya tidak yakin apa yang Anda maksud dengan "hati-hati dengan hashbangs". Sepertinya itu akan selalu berhasil. Bisakah Anda memberikan contoh tandingan?
Andriy Drozdyuk
7
Jika Anda mencoba menggunakan Bootstrap dan perlu mengatur berdasarkan hash dari a href dalam li, kemudian gunakan var path = $(element).children("a")[0].hash.substring(1);. Ini akan bekerja untuk gaya seperti<li active-link="active"><a href="#/dashboard">Dashboard</a></li>
Dave
2
Saya akan berubah scope.$watch('location.path()', function(newPath) {untuk scope.$on('$locationChangeStart', function(){.
sanfilippopablo
2
Jika Anda menggunakan ng-href, ubah saja: var path = attrs.href; ke var path = attrs.href||attrs.ngHref;
William Neely
Jika Anda menggunakan Bootstrap dan perlu mengaktifkan kelas aktif <li>, Anda dapat mengubah element.addClass(clazz);keelement.parent().addClass(clazz);
JamesRLamar
47

Inilah pendekatan sederhana yang bekerja dengan baik dengan Angular.

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

Di dalam pengontrol AngularJS Anda:

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

Utas ini memiliki sejumlah jawaban serupa lainnya.

Bagaimana cara mengatur kelas aktif bootstrap navbar dengan Angular JS?

Ender2050
sumber
1
Hapus variabel karena tidak perlu. Kembalikan hasil perbandingan. return viewLocation === $location.path()
afarazit
33

Hanya untuk menambahkan dua sen saya dalam perdebatan saya telah membuat modul sudut murni (tanpa jQuery), dan itu juga akan bekerja dengan hash url yang berisi data. (mis. #/this/is/path?this=is&some=data)

Anda cukup menambahkan modul sebagai dependensi dan auto-activeke salah satu leluhur menu. Seperti ini:

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

Dan modulnya terlihat seperti ini:

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

(Tentu saja Anda bisa menggunakan bagian arahan)

Perlu juga diperhatikan bahwa ini tidak bekerja untuk hash kosong (misalnya example.com/#atau hanya example.com) yang harus dimiliki setidaknya example.com/#/atau adil example.com#/. Tetapi ini terjadi secara otomatis dengan ngResource dan sejenisnya.

Dan ini biola: http://jsfiddle.net/gy2an/8/

Pylinux
sumber
1
Solusi hebat, namun tidak bekerja pada pemuatan laman awal, hanya pada locationChange saat aplikasi aktif. Saya memperbarui cuplikan Anda untuk mengatasinya.
Jerry
@ Jarek: Terima kasih! Telah menerapkan perubahan Anda. Saya belum punya masalah dengan ini secara pribadi, tetapi solusi Anda sepertinya solusi stabil yang bagus bagi mereka yang harus mengalami masalah ini.
Pylinux
2
Saya sekarang telah membuat repo Github untuk permintaan tarik jika ada orang lain yang punya ide bagus: github.com/Karl-Gustav/autoActive
Pylinux
Saya baru saja memperbaiki beberapa bug yang akan terjadi jika Anda menggunakan ng-href .. Ini ditemukan di sini: github.com/Karl-Gustav/autoActive/pull/3
Blake Niemyjski
Alangkah baiknya jika skrip ini memungkinkan Anda untuk menentukan jalur sehingga Anda dapat mengaktifkannya elemen lain.
Blake Niemyjski
22

Dalam kasus saya, saya menyelesaikan masalah ini dengan membuat pengontrol sederhana yang bertanggung jawab untuk navigasi

angular.module('DemoApp')
  .controller('NavigationCtrl', ['$scope', '$location', function ($scope, $location) {
    $scope.isCurrentPath = function (path) {
      return $location.path() == path;
    };
  }]);

Dan dengan hanya menambahkan kelas-ng ke elemen seperti:

<ul class="nav" ng-controller="NavigationCtrl">
  <li ng-class="{ active: isCurrentPath('/') }"><a href="#/">Home</a></li>
  <li ng-class="{ active: isCurrentPath('/about') }"><a href="#/about">About</a></li>
  <li ng-class="{ active: isCurrentPath('/contact') }"><a href="#/contact">Contact</a></li>
</ul>
Djamel
sumber
14

Untuk pengguna Router AngularUI :

<a ui-sref-active="active" ui-sref="app">

Dan itu akan menempatkan activekelas pada objek yang dipilih.

frankie4fingers
sumber
2
Ini adalah arahan ui-router dan tidak berfungsi jika Anda menggunakan router bawaan, alias ngRoute. Yang mengatakan, ui-router luar biasa.
moljac024
Setuju, saya lupa menyebutkan awalnya bahwa itu hanya solusi ui-router.
frankie4fingers
13

Ada ng-classarahan, yang mengikat variabel dan kelas css. Itu juga menerima objek (className vs pasangan nilai bool).

Berikut ini contohnya, http://plnkr.co/edit/SWZAqj

Omong kosong
sumber
Terima kasih, tetapi ini tidak akan bekerja dengan jalur seperti:, /test1/blahblahatau akankah itu?
Andriy Drozdyuk
Jadi, apakah Anda mengatakan bahwa active: activePath=='/test1'secara otomatis mengembalikan "aktif" adalah jalan dimulai dengan string yang diberikan? Apakah ini semacam operator atau regex yang telah ditentukan?
Andriy Drozdyuk
Maaf, saya tidak berpikir saya mengerti kebutuhan Anda dengan benar. Inilah tebakan baru saya, Anda ingin sorot tautan 'test1' DAN tautan 'test1 / blahblah' disorot ketika rute adalah 'test1 / blahblah'. "Apakah saya benar? Jika ini persyaratannya, Anda benar bahwa solusi saya tidak kerja
Tosh
3
Berikut ini adalah plnkr yang diperbarui: plnkr.co/edit/JI5DtK (yang memenuhi persyaratan yang ditebak) untuk hanya menunjukkan solusi alternatif.
Tosh
Saya melihat apa yang Anda lakukan di sana. Tapi saya bukan penggemar ==cek berulang di html.
Andriy Drozdyuk
13

The jawaban dari @ Renan-Tomal-fernandes baik, tetapi membutuhkan beberapa perbaikan untuk bekerja dengan benar. Seperti itu, selalu mendeteksi tautan ke beranda (/) sebagai dipicu, bahkan jika Anda berada di bagian lain.

Jadi saya memperbaikinya sedikit, ini kodenya. Saya bekerja dengan Bootstrap sehingga bagian yang aktif ada di <li>elemen, bukan di bagian <a>.

Pengendali

$scope.getClass = function(path) {
    var cur_path = $location.path().substr(0, path.length);
    if (cur_path == path) {
        if($location.path().substr(0).length > 1 && path.length == 1 )
            return "";
        else
            return "active";
    } else {
        return "";
    }
}

Templat

<div class="nav-collapse collapse">
  <ul class="nav">
    <li ng-class="getClass('/')"><a href="#/">Home</a></li>
    <li ng-class="getClass('/contents/')"><a href="#/contests/">Contents</a></li>
    <li ng-class="getClass('/data/')"><a href="#/data/">Your data</a></li>
  </ul>
</div>
holographix
sumber
10

Berikut adalah solusi yang saya buat setelah membaca beberapa saran bagus di atas. Dalam situasi khusus saya, saya mencoba menggunakan komponen tab Bootstrap sebagai menu saya, tetapi tidak ingin menggunakan versi Angular-UI ini karena saya ingin tab bertindak sebagai menu, di mana setiap tab dapat bookmark, alih-alih tab yang bertindak sebagai navigasi untuk satu halaman. (Lihat http://angular-ui.github.io/bootstrap/#/tabs jika Anda tertarik dengan tampilan tab bootstrap versi Angular-UI).

Saya benar-benar menyukai jawaban kfis tentang membuat arahan Anda sendiri untuk menangani hal ini, namun tampaknya rumit untuk memiliki arahan yang perlu ditempatkan pada setiap tautan. Jadi saya telah membuat direktif Angular saya yang ditempatkan sebagai gantinya satu kali pada ul. Kalau-kalau ada orang lain yang mencoba melakukan hal yang sama, saya pikir saya akan mempostingnya di sini, meskipun seperti yang saya katakan, banyak solusi di atas juga berfungsi. Ini adalah solusi yang sedikit lebih kompleks sejauh javascript berjalan, tetapi ini menciptakan komponen yang dapat digunakan kembali dengan markup minimal.

Berikut adalah javascript untuk direktif dan penyedia rute untuk ng:view:

var app = angular.module('plunker', ['ui.bootstrap']).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.
        when('/One', {templateUrl: 'one.html'}).
        when('/Two', {templateUrl: 'two.html'}).
        when('/Three', {templateUrl: 'three.html'}).
        otherwise({redirectTo: '/One'});
  }]).
  directive('navTabs', ['$location', function(location) {
    return {
        restrict: 'A',
        link: function(scope, element) {
            var $ul = $(element);
            $ul.addClass("nav nav-tabs");

            var $tabs = $ul.children();
            var tabMap = {};
            $tabs.each(function() {
              var $li = $(this);
              //Substring 1 to remove the # at the beginning (because location.path() below does not return the #)
              tabMap[$li.find('a').attr('href').substring(1)] = $li;
            });

            scope.location = location;
            scope.$watch('location.path()', function(newPath) {
                $tabs.removeClass("active");
                tabMap[newPath].addClass("active");
            });
        }

    };

 }]);

Kemudian di html Anda, Anda cukup:

<ul nav-tabs>
  <li><a href="#/One">One</a></li>
  <li><a href="#/Two">Two</a></li>
  <li><a href="#/Three">Three</a></li>
</ul>
<ng:view><!-- Content will appear here --></ng:view>

Inilah penyedotnya: http://plnkr.co/edit/xwGtGqrT7kWoCKnGDHYN?p=preview .

corinnaerin
sumber
9

Anda dapat menerapkan ini dengan sangat sederhana, berikut ini sebuah contoh:

<div ng-controller="MenuCtrl">
  <ul class="menu">
    <li ng-class="menuClass('home')"><a href="#home">Page1</a></li>
    <li ng-class="menuClass('about')"><a href="#about">Page2</a></li>
  </ul>

</div>

Dan Pengontrol Anda harus seperti ini:

app.controller("MenuCtrl", function($scope, $location) {
  $scope.menuClass = function(page) {
    var current = $location.path().substring(1);
    return page === current ? "active" : "";
  };
});
Ejaz
sumber
4

Saya memiliki masalah yang sama dengan menu yang terletak di luar lingkup pengontrol. Tidak yakin apakah ini solusi terbaik atau yang disarankan, tetapi inilah yang berhasil bagi saya. Saya telah menambahkan yang berikut ini ke konfigurasi aplikasi saya:

var app = angular.module('myApp');

app.run(function($rootScope, $location){
  $rootScope.menuActive = function(url, exactMatch){
    if (exactMatch){
      return $location.path() == url;
    }
    else {
      return $location.path().indexOf(url) == 0;
    }
  }
});

Kemudian dalam tampilan saya punya:

<li><a href="/" ng-class="{true: 'active'}[menuActive('/', true)]">Home</a></li>
<li><a href="/register" ng-class="{true: 'active'}[menuActive('/register')]">
<li>...</li>
mrt
sumber
Um ... ini sepertinya lebih rumit dari jawaban yang diterima. Bisakah Anda menggambarkan keunggulan ini lebih dari itu?
Andriy Drozdyuk
1
Anda akan membutuhkannya dalam skenario ketika menu Anda berada di luar tampilan-ng. View controller tidak akan memiliki akses ke apa pun yang ada di luar jadi saya telah menggunakan $ rootScope untuk mengaktifkan komunikasi. Jika menu Anda ada di dalam tampilan-ng maka tidak ada manfaatnya bagi Anda untuk menggunakan solusi ini.
mrt
4

Menggunakan Angular Versi 6 dengan Bootstrap 4.1

Saya bisa menyelesaikannya seperti yang terlihat di bawah ini.

Pada contoh di bawah ini, ketika URL melihat '/ kontak', bootstrap aktif kemudian ditambahkan ke tag html. Ketika URL berubah itu kemudian dihapus.

<ul>
<li class="nav-item" routerLink="/contact" routerLinkActive="active">
    <a class="nav-link" href="/contact">Contact</a>
</li>
</ul>

Arahan ini memungkinkan Anda menambahkan kelas CSS ke elemen ketika rute tautan menjadi aktif.

Baca lebih lanjut di situs web Angular

Jeacovy Gayle
sumber
3

Menggunakan arahan (karena kita melakukan manipulasi DOM di sini), berikut ini mungkin yang paling dekat dengan melakukan hal-hal dengan "sudut":

$scope.timeFilters = [
  {'value':3600,'label':'1 hour'},
  {'value':10800,'label':'3 hours'},
  {'value':21600,'label':'6 hours'},
  {'value':43200,'label':'12 hours'},
  {'value':86400,'label':'24 hours'},
  {'value':604800,'label':'1 week'}
]

angular.module('whatever', []).directive('filter',function(){
return{
    restrict: 'A',
    template: '<li ng-repeat="time in timeFilters" class="filterItem"><a ng-click="changeTimeFilter(time)">{{time.label}}</a></li>',
    link: function linkFn(scope, lElement, attrs){

        var menuContext = attrs.filter;

        scope.changeTimeFilter = function(newTime){
          scope.selectedtimefilter = newTime;

        }

        lElement.bind('click', function(cevent){
            var currentSelection = angular.element(cevent.srcElement).parent();
            var previousSelection = scope[menuContext];

            if(previousSelection !== currentSelection){
                if(previousSelection){
                    angular.element(previousSelection).removeClass('active')
                }
                scope[menuContext] = currentSelection;

                scope.$apply(function(){
                    currentSelection.addClass('active');
                })
            }
        })
    }
}
})

Maka HTML Anda akan terlihat seperti:

<ul class="dropdown-menu" filter="times"></ul>
Wesley Hales
sumber
Menarik. Namun menu-itemsepertinya mubazir di setiap baris. Mungkin melampirkan atribut ke ulelemen (misalnya <ul menu>) akan lebih baik, tapi saya tidak yakin apakah itu mungkin.
Andriy Drozdyuk
Baru saja diperbarui dengan versi yang lebih baru - daripada daftar unordered statis, saya sekarang menggunakan menu dropdown Boostrap sebagai daftar pilih.
Wesley Hales
Ini sepertinya sudut idiomatik yang paling disukai. Tampaknya cocok dengan saran yang diberikan di stackoverflow.com/questions/14994391/… , dan itu menghindari menduplikasi jalur dalam tampilan, di href dan di kelas ng.
fundead
2

Saya melakukannya seperti ini:

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

myApp.directive('trackActive', function($location) {
    function link(scope, element, attrs){
        scope.$watch(function() {
            return $location.path();
        }, function(){
            var links = element.find('a');
            links.removeClass('active');
            angular.forEach(links, function(value){
                var a = angular.element(value);
                if (a.attr('href') == '#' + $location.path() ){
                    a.addClass('active');
                }
            });
        });
    }
    return {link: link};
});

Ini memungkinkan Anda memiliki tautan di bagian yang memiliki arahan track-aktif:

<nav track-active>
     <a href="#/">Page 1</a>
     <a href="#/page2">Page 2</a>
     <a href="#/page3">Page 3</a>
</nav>

Pendekatan ini tampaknya jauh lebih bersih daripada yang lain, bagi saya.

Juga, jika Anda menggunakan jQuery, Anda bisa membuatnya lebih rapi karena jQlite hanya memiliki dukungan pemilih dasar. Versi yang jauh lebih bersih dengan jquery yang disertakan sebelum angular termasuk akan terlihat seperti ini:

myApp.directive('trackActive', function($location) {
    function link(scope, element, attrs){
        scope.$watch(function() {
            return $location.path();
        }, function(){
            element.find('a').removeClass('active').find('[href="#'+$location.path()+'"]').addClass('active');
        });
    }
    return {link: link};
});

Ini jsFiddle

konsumer
sumber
2

Solusi saya untuk masalah ini, gunakan route.current di template sudut.

Karena Anda memiliki /tasksrute untuk disorot di menu Anda, Anda dapat menambahkan properti Anda sendiri menuItemke rute yang dinyatakan oleh modul Anda:

$routeProvider.
  when('/tasks', {
    menuItem: 'TASKS',
    templateUrl: 'my-templates/tasks.html',
    controller: 'TasksController'
  );

Kemudian dalam template tasks.htmlAnda, Anda dapat menggunakan ng-classarahan berikut :

<a href="app.html#/tasks" 
    ng-class="{active : route.current.menuItem === 'TASKS'}">Tasks</a>

Menurut pendapat saya, ini jauh lebih bersih daripada semua solusi yang diusulkan.

François Maturel
sumber
1

Berikut ini adalah ekstensi pada arahan kfis yang saya lakukan untuk memungkinkan berbagai tingkat pencocokan jalur. Pada dasarnya saya menemukan kebutuhan untuk mencocokkan jalur URL hingga kedalaman tertentu, karena pencocokan tepat tidak memungkinkan untuk pengalihan bersarang dan pengalihan status default. Semoga ini membantu.

    .directive('selectedLink', ['$location', function(location) {
    return {
        restrict: 'A',
        scope:{
            selectedLink : '='
            },
        link: function(scope, element, attrs, controller) {
            var level = scope.selectedLink;
            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) {
                var i=0;
                p = path.split('/');
                n = newPath.split('/');
                for( i ; i < p.length; i++) { 
                    if( p[i] == 'undefined' || n[i] == 'undefined' || (p[i] != n[i]) ) break;
                    }

                if ( (i-1) >= level) {
                    element.addClass("selected");
                    } 
                else {
                    element.removeClass("selected");
                    }
                });
            }

        };
    }]);

Dan inilah cara saya menggunakan tautannya

<nav>
    <a href="#/info/project/list"  selected-link="2">Project</a>
    <a href="#/info/company/list" selected-link="2">Company</a>
    <a href="#/info/person/list"  selected-link="2">Person</a>
</nav>

Arahan ini akan cocok dengan level kedalaman yang ditentukan dalam nilai atribut untuk arahan. Hanya berarti dapat digunakan di tempat lain berkali-kali.

pkbyron
sumber
1

Berikut ini adalah arahan lain untuk menyoroti tautan aktif.

Fitur utama:

  • Berfungsi baik dengan href yang berisi ekspresi sudut dinamis
  • Kompatibel dengan navigasi hash-bang
  • Kompatibel dengan Bootstrap di mana kelas aktif harus diterapkan pada orang tua, bukan tautan itu sendiri
  • Mengizinkan tautan aktif jika jalur bersarang aktif
  • Mengizinkan tautan dinonaktifkan jika tidak aktif

Kode:

.directive('activeLink', ['$location', 
function($location) {
    return {
        restrict: 'A',
        link: function(scope, elem, attrs) {
            var path = attrs.activeLink ? 'activeLink' : 'href';
            var target = angular.isDefined(attrs.activeLinkParent) ? elem.parent() : elem;
            var disabled = angular.isDefined(attrs.activeLinkDisabled) ? true : false;
            var nested = angular.isDefined(attrs.activeLinkNested) ? true : false;

            function inPath(needle, haystack) {
                var current = (haystack == needle);
                if (nested) {
                    current |= (haystack.indexOf(needle + '/') == 0);
                }

                return current;
            }

            function toggleClass(linkPath, locationPath) {
                // remove hash prefix and trailing slashes
                linkPath = linkPath ? linkPath.replace(/^#!/, '').replace(/\/+$/, '') : '';
                locationPath = locationPath.replace(/\/+$/, '');

                if (linkPath && inPath(linkPath, locationPath)) {
                    target.addClass('active');
                    if (disabled) {
                        target.removeClass('disabled');
                    }
                } else {
                    target.removeClass('active');
                    if (disabled) {
                        target.addClass('disabled');
                    }
                }
            }

            // watch if attribute value changes / evaluated
            attrs.$observe(path, function(linkPath) {
                toggleClass(linkPath, $location.path());
            });

            // watch if location changes
            scope.$watch(
                function() {
                    return $location.path(); 
                }, 
                function(newPath) {
                    toggleClass(attrs[path], newPath);
                }
            );
        }
    };
}
]);

Pemakaian:

Contoh sederhana dengan ekspresi sudut, katakanlah $ scope.var = 2 , maka tautan akan aktif jika lokasi / url / 2 :

<a href="#!/url/{{var}}" active-link>

Contoh bootstrap, induk li akan mendapatkan kelas aktif:

<li>
    <a href="#!/url" active-link active-link-parent>
</li>

Contoh dengan url bersarang, tautan akan aktif jika url bersarang aktif (yaitu / url / 1 , / url / 2 , url / 1/2 / ... )

<a href="#!/url" active-link active-link-nested>

Contoh kompleks, tautan menunjuk ke satu url ( / url1 ) tetapi akan aktif jika yang lain dipilih ( / url2 ):

<a href="#!/url1" active-link="#!/url2" active-link-nested>

Contoh dengan tautan yang dinonaktifkan, jika tidak aktif, kelasnya akan 'dinonaktifkan' :

<a href="#!/url" active-link active-link-disabled>

Semua atribut tautan aktif * dapat digunakan dalam kombinasi apa pun, sehingga kondisi yang sangat rumit dapat diterapkan.

Eugene Fidelin
sumber
1

Jika Anda menginginkan tautan untuk arahan dalam bungkus daripada memilih masing-masing tautan (membuatnya lebih mudah untuk melihat cakupan di Batarang), ini juga berfungsi dengan baik:

  angular.module("app").directive("navigation", [
    "$location", function($location) {
      return {
        restrict: 'A',
        scope: {},
        link: function(scope, element) {
          var classSelected, navLinks;

          scope.location = $location;

          classSelected = 'selected';

          navLinks = element.find('a');

          scope.$watch('location.path()', function(newPath) {
            var el;
            el = navLinks.filter('[href="' + newPath + '"]');

            navLinks.not(el).closest('li').removeClass(classSelected);
            return el.closest('li').addClass(classSelected);
          });
        }
      };
    }
  ]);

Markup akan menjadi:

    <nav role="navigation" data-navigation>
        <ul>
            <li><a href="/messages">Messages</a></li>
            <li><a href="/help">Help</a></li>
            <li><a href="/details">Details</a></li>
        </ul>
    </nav>

Saya juga harus menyebutkan bahwa saya menggunakan jQuery 'full-fat' dalam contoh ini, tetapi Anda dapat dengan mudah mengubah apa yang telah saya lakukan dengan pemfilteran dan sebagainya.

markyzm
sumber
1

Ini dua sen saya, ini berfungsi dengan baik.

CATATAN: Ini tidak cocok dengan halaman anak-anak (yang saya butuhkan).

Melihat:

<a ng-class="{active: isCurrentLocation('/my-path')}"  href="/my-path" >
  Some link
</a>

Pengendali:

// make sure you inject $location as a dependency

$scope.isCurrentLocation = function(path){
    return path === $location.path()
}
Justus Romijn
sumber
1

Menurut jawaban @kfis, ini adalah komentar, dan rekomendasi saya, arahan akhir seperti di bawah ini:

.directive('activeLink', ['$location', function (location) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs, controller) {
        var clazz = attrs.activeLink;        
        var path = attrs.href||attrs.ngHref;
        path = path.substring(1); //hack because path does not return including hashbang
        scope.location = location;
        scope.$watch('window.location.href', function () {
          var newPath = (window.location.pathname + window.location.search).substr(1);
          if (path === newPath) {
            element.addClass(clazz);
          } else {
            element.removeClass(clazz);
          }
        });
      }
    };
  }]);

dan inilah bagaimana ini akan digunakan dalam 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>

setelah itu styling dengan css:

.active { color: red; }
John_J
sumber
1

Bagi mereka yang menggunakan ui-router, jawaban saya agak mirip dengan Ender2050, tapi saya lebih suka melakukan ini melalui pengujian nama negara:

$scope.isActive = function (stateName) {
  var active = (stateName === $state.current.name);
  return active;
};

HTML yang sesuai:

<ul class="nav nav-sidebar">
    <li ng-class="{ active: isActive('app.home') }"><a ui-sref="app.home">Dashboard</a></li>
    <li ng-class="{ active: isActive('app.tiles') }"><a ui-sref="app.tiles">Tiles</a></li>
</ul>
GONeale
sumber
1

Tidak ada saran direktif di atas yang berguna bagi saya. Jika Anda memiliki navbar bootstrap seperti ini

<ul class="nav navbar-nav">
    <li><a ng-href="#/">Home</a></li>
    <li><a ng-href="#/about">About</a></li>
  ...
</ul>

(yang bisa menjadi $ yo angularstartup) maka Anda ingin menambahkan .activeke daftar kelas elemen induk <li> , bukan elemen itu sendiri; yaitu <li class="active">..</li>. Jadi saya menulis ini:

.directive('setParentActive', ['$location', function($location) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs, controller) {
      var classActive = attrs.setParentActive || 'active',
          path = attrs.ngHref.replace('#', '');
      scope.location = $location;
      scope.$watch('location.path()', function(newPath) {
        if (path == newPath) {
          element.parent().addClass(classActive);
        } else {
          element.parent().removeClass(classActive);
        }
      })
    }
  }
}])

penggunaan set-parent-active; .activedefault jadi tidak perlu diatur

<li><a ng-href="#/about" set-parent-active>About</a></li>

dan <li>elemen induk akan menjadi .activeketika tautan aktif. Untuk menggunakan .activekelas alternatif seperti .highlight, cukup

<li><a ng-href="#/about" set-parent-active="highlight">About</a></li>
davidkonrad
sumber
Saya telah mencoba scope. $ On ("$ routeChangeSuccess", function (event, current, sebelumnya) {applyActiveClass ();}); tetapi itu hanya berfungsi ketika tautan diklik dan bukan 'pada pemuatan laman' (mengklik tombol segarkan). menonton lokasi telah bekerja untuk saya
sawe
0

Yang paling penting bagi saya adalah tidak mengubah sama sekali kode default bootstrap. Ini dia pengontrol menu saya yang mencari opsi menu dan kemudian menambahkan perilaku yang kita inginkan.

file: header.js
function HeaderCtrl ($scope, $http, $location) {
  $scope.menuLinkList = [];
  defineFunctions($scope);
  addOnClickEventsToMenuOptions($scope, $location);
}

function defineFunctions ($scope) {
  $scope.menuOptionOnClickFunction = function () {
    for ( var index in $scope.menuLinkList) {
      var link = $scope.menuLinkList[index];
      if (this.hash === link.hash) {
        link.parentElement.className = 'active';
      } else {
        link.parentElement.className = '';
      }
    }
  };
}

function addOnClickEventsToMenuOptions ($scope, $location) {
  var liList = angular.element.find('li');
  for ( var index in liList) {
    var liElement = liList[index];
    var link = liElement.firstChild;
    link.onclick = $scope.menuOptionOnClickFunction;
    $scope.menuLinkList.push(link);
    var path = link.hash.replace("#", "");
    if ($location.path() === path) {
      link.parentElement.className = 'active';
    }
  }
}

     <script src="resources/js/app/header.js"></script>
 <div class="navbar navbar-fixed-top" ng:controller="HeaderCtrl">
    <div class="navbar-inner">
      <div class="container-fluid">
        <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
          <span class="icon-bar"></span> <span class="icon-bar"></span> 
<span     class="icon-bar"></span>
        </button>
        <a class="brand" href="#"> <img src="resources/img/fom-logo.png"
          style="width: 80px; height: auto;">
        </a>
        <div class="nav-collapse collapse">
          <ul class="nav">
            <li><a href="#/platforms">PLATFORMS</a></li>
            <li><a href="#/functionaltests">FUNCTIONAL TESTS</a></li>
          </ul> 
        </div>
      </div>
    </div>
  </div>
pengguna2599258
sumber
0

punya masalah yang sama. Ini solusinya :

.directive('whenActive',
  [
    '$location',
    ($location)->
      scope: true,
      link: (scope, element, attr)->
        scope.$on '$routeChangeSuccess', 
          () ->
            loc = "#"+$location.path()
            href = element.attr('href')
            state = href.indexOf(loc)
            substate = -1

            if href.length > 3
              substate = loc.indexOf(href)
            if loc.length is 2
              state = -1

            #console.log "Is Loc: "+loc+" in Href: "+href+" = "+state+" and Substate = "+substate

            if state isnt -1 or substate isnt -1
              element.addClass 'selected'
              element.parent().addClass 'current-menu-item'
            else if href is '#' and loc is '#/'
              element.addClass 'selected'
              element.parent().addClass 'current-menu-item'
            else
              element.removeClass 'selected'
              element.parent().removeClass 'current-menu-item'
  ])
Batalkan verifikasi
sumber
0

Saya baru saja menulis arahan untuk ini.

Pemakaian:

<ul class="nav navbar-nav">
  <li active><a href="#/link1">Link 1</a></li>
  <li active><a href="#/link2">Link 2</a></li>
</ul>

Penerapan:

angular.module('appName')
  .directive('active', function ($location, $timeout) {
    return {
      restrict: 'A',
      link: function (scope, element, attrs) {
        // Whenever the user navigates to a different page...
        scope.$on('$routeChangeSuccess', function () {
          // Defer for other directives to load first; this is important
          // so that in case other directives are used that this directive
          // depends on, such as ng-href, the href is evaluated before
          // it's checked here.
          $timeout(function () {
            // Find link inside li element
            var $link = element.children('a').first();

            // Get current location
            var currentPath = $location.path();

            // Get location the link is pointing to
            var linkPath = $link.attr('href').split('#').pop();

            // If they are the same, it means the user is currently
            // on the same page the link would point to, so it should
            // be marked as such
            if (currentPath === linkPath) {
              $(element).addClass('active');
            } else {
              // If they're not the same, a li element that is currently
              // marked as active needs to be "un-marked"
              element.removeClass('active');
            }
          });
        });
      }
    };
  });

Tes:

'use strict';

describe('Directive: active', function () {

  // load the directive's module
  beforeEach(module('appName'));

  var element,
      scope,
      location,
      compile,
      rootScope,
      timeout;

  beforeEach(inject(function ($rootScope, $location, $compile, $timeout) {
    scope = $rootScope.$new();
    location = $location;
    compile = $compile;
    rootScope = $rootScope;
    timeout = $timeout;
  }));

  describe('with an active link', function () {
    beforeEach(function () {
      // Trigger location change
      location.path('/foo');
    });

    describe('href', function () {
      beforeEach(function () {
        // Create and compile element with directive; note that the link
        // is the same as the current location after the location change.
        element = angular.element('<li active><a href="#/foo">Foo</a></li>');
        element = compile(element)(scope);

        // Broadcast location change; the directive waits for this signal
        rootScope.$broadcast('$routeChangeSuccess');

        // Flush timeout so we don't have to write asynchronous tests.
        // The directive defers any action using a timeout so that other
        // directives it might depend on, such as ng-href, are evaluated
        // beforehand.
        timeout.flush();
      });

      it('adds the class "active" to the li', function () {
        expect(element.hasClass('active')).toBeTruthy();
      });
    });

    describe('ng-href', function () {
      beforeEach(function () {
        // Create and compile element with directive; note that the link
        // is the same as the current location after the location change;
        // however this time with an ng-href instead of an href.
        element = angular.element('<li active><a ng-href="#/foo">Foo</a></li>');
        element = compile(element)(scope);

        // Broadcast location change; the directive waits for this signal
        rootScope.$broadcast('$routeChangeSuccess');

        // Flush timeout so we don't have to write asynchronous tests.
        // The directive defers any action using a timeout so that other
        // directives it might depend on, such as ng-href, are evaluated
        // beforehand.
        timeout.flush();
      });

      it('also works with ng-href', function () {
        expect(element.hasClass('active')).toBeTruthy();
      });
    });
  });

  describe('with an inactive link', function () {
    beforeEach(function () {
      // Trigger location change
      location.path('/bar');

      // Create and compile element with directive; note that the link
      // is the NOT same as the current location after the location change.
      element = angular.element('<li active><a href="#/foo">Foo</a></li>');
      element = compile(element)(scope);

      // Broadcast location change; the directive waits for this signal
      rootScope.$broadcast('$routeChangeSuccess');

      // Flush timeout so we don't have to write asynchronous tests.
      // The directive defers any action using a timeout so that other
      // directives it might depend on, such as ng-href, are evaluated
      // beforehand.
      timeout.flush();
    });

    it('does not add the class "active" to the li', function () {
      expect(element.hasClass('active')).not.toBeTruthy();
    });
  });

  describe('with a formerly active link', function () {
    beforeEach(function () {
      // Trigger location change
      location.path('/bar');

      // Create and compile element with directive; note that the link
      // is the same as the current location after the location change.
      // Also not that the li element already has the class "active".
      // This is to make sure that a link that is active right now will
      // not be active anymore when the user navigates somewhere else.
      element = angular.element('<li class="active" active><a href="#/foo">Foo</a></li>');
      element = compile(element)(scope);

      // Broadcast location change; the directive waits for this signal
      rootScope.$broadcast('$routeChangeSuccess');

      // Flush timeout so we don't have to write asynchronous tests.
      // The directive defers any action using a timeout so that other
      // directives it might depend on, such as ng-href, are evaluated
      // beforehand.
      timeout.flush();
    });

    it('removes the "active" class from the li', function () {
      expect(element.hasClass('active')).not.toBeTruthy();
    });
  });
});
weltschmerz
sumber
0

Rute:

$routeProvider.when('/Account/', { templateUrl: '/Home/Account', controller: 'HomeController' });

Menu html:

<li id="liInicio" ng-class="{'active':url=='account'}">

Pengontrol:

angular.module('Home').controller('HomeController', function ($scope, $http, $location) {
    $scope.url = $location.url().replace(/\//g, "").toLowerCase();
...

Masalah yang saya temukan di sini adalah bahwa item menu hanya aktif ketika halaman penuh dimuat. Ketika tampilan parsial dimuat menu tidak berubah. Ada yang tahu mengapa itu terjadi?

Tn. D MX
sumber
0
$scope.getClass = function (path) {
return String(($location.absUrl().split('?')[0]).indexOf(path)) > -1 ? 'active' : ''
}


<li class="listing-head" ng-class="getClass('/v/bookings')"><a href="/v/bookings">MY BOOKING</a></li>
<li class="listing-head" ng-class="getClass('/v/fleets')"><a href="/v/fleets">MY FLEET</a></li>
<li class="listing-head" ng-class="getClass('/v/adddriver')"><a href="/v/adddriver">ADD DRIVER</a></li>
<li class="listing-head" ng-class="getClass('/v/bookings')"><a href="/v/invoice">INVOICE</a></li>
<li class="listing-head" ng-class="getClass('/v/profile')"><a href="/v/profile">MY PROFILE</a></li>
<li class="listing-head"><a href="/v/logout">LOG OUT</a></li>
Ashish Gupta
sumber
0

Saya menemukan solusi termudah. hanya untuk membandingkan indexOf dalam HTML

var myApp = angular.module('myApp', []);

myApp.run(function($rootScope) {
    $rootScope.$on("$locationChangeStart", function(event, next, current) { 
         $rootScope.isCurrentPath = $location.path();  
    });
});



<li class="{{isCurrentPath.indexOf('help')>-1 ? 'active' : '' }}">
<a href="/#/help/">
          Help
        </a>
</li>
NishantVerma.Me
sumber