Seguendo il consiglio di Pavel di utilizzare una direttiva personalizzata, ecco una versione che non richiede l'aggiunta di payload a routeConfig, è super dichiarativa e può essere adattata per reagire a qualsiasi livello del percorso, semplicemente cambiando a quale slice()
di essa stai prestando attenzione .
app.directive('detectActiveTab', function ($location) {
return {
link: function postLink(scope, element, attrs) {
scope.$on("$routeChangeSuccess", function (event, current, previous) {
/*
Designed for full re-usability at any path, any level, by using
data from attrs. Declare like this:
<li class="nav_tab">
<a href="#/home" detect-active-tab="1">HOME</a>
</li>
*/
// This var grabs the tab-level off the attribute, or defaults to 1
var pathLevel = attrs.detectActiveTab || 1,
// This var finds what the path is at the level specified
pathToCheck = $location.path().split('/')[pathLevel] ||
"current $location.path doesn't reach this level",
// This var finds grabs the same level of the href attribute
tabLink = attrs.href.split('/')[pathLevel] ||
"href doesn't include this level";
// Above, we use the logical 'or' operator to provide a default value
// in cases where 'undefined' would otherwise be returned.
// This prevents cases where undefined===undefined,
// possibly causing multiple tabs to be 'active'.
// now compare the two:
if (pathToCheck === tabLink) {
element.addClass("active");
}
else {
element.removeClass("active");
}
});
}
};
});
Stiamo raggiungendo i nostri obiettivi ascoltando l' $routeChangeSuccess
evento, piuttosto che posizionandoli $watch
sul percorso. Lavoro credendo che ciò significhi che la logica dovrebbe funzionare meno spesso, poiché penso che guardi il fuoco su ogni $digest
ciclo.
Invocalo passando il tuo argomento a livello di percorso sulla dichiarazione della direttiva. Questo specifica a quale blocco dell'attuale $ location.path () si desidera abbinare l' href
attributo.
<li class="nav_tab"><a href="#/home" detect-active-tab="1">HOME</a></li>
Quindi, se le tue schede dovessero reagire al livello base del percorso, fai l'argomento '1'. Pertanto, quando location.path () è "/ home", corrisponderà a "# / home" in href
. Se sono presenti schede che dovrebbero reagire al secondo livello, o al terzo o all'undicesimo del percorso, regolare di conseguenza. Questo taglio da 1 o superiore aggirerà il nefasto '#' nell'href, che vivrà all'indice 0.
L'unico requisito è che invochi su un <a>
, poiché l'elemento assume la presenza di un href
attributo, che verrà confrontato con il percorso corrente. Tuttavia, è possibile adattarsi abbastanza facilmente per leggere / scrivere un elemento genitore o figlio, se si preferisce invocare il <li>
o qualcosa del genere. Lo scavo perché puoi riutilizzarlo in molti contesti semplicemente variando l'argomento pathLevel. Se la profondità da cui leggere fosse assunta nella logica, avresti bisogno di più versioni della direttiva da utilizzare con più parti della navigazione.
MODIFICA 18/03/2014: la soluzione non è stata sufficientemente generalizzata e si attiverebbe se si definisse un arg per il valore di "activeTab" restituito undefined
sia rispetto a quello $location.path()
che a quello dell'elemento href
. Perché: undefined === undefined
. Aggiornato per correggere quella condizione.
Mentre ci lavoravo, ho capito che avrebbe dovuto esistere una versione che puoi semplicemente dichiarare su un elemento genitore, con una struttura modello come questa:
<nav id="header_tabs" find-active-tab="1">
<a href="#/home" class="nav_tab">HOME</a>
<a href="#/finance" class="nav_tab">Finance</a>
<a href="#/hr" class="nav_tab">Human Resources</a>
<a href="#/quarterly" class="nav_tab">Quarterly</a>
</nav>
Si noti che questa versione non assomiglia più in remoto a HTML in stile Bootstrap. Ma è più moderno e utilizza meno elementi, quindi sono parziale. Questa versione della direttiva, oltre all'originale, è ora disponibile su Github come modulo drop-in che puoi semplicemente dichiarare come dipendenza. Sarei felice di perderli, se qualcuno li usa davvero.
Inoltre, se vuoi una versione compatibile con bootstrap che includa quella <li>
, puoi andare con il modulo Tabs angular-ui-bootstrap , che penso sia uscito dopo questo post originale e che forse è ancora più dichiarativo di questo. È meno conciso per le cose di base, ma ti offre alcune opzioni aggiuntive, come le schede disabilitate e gli eventi dichiarativi che attivano l'attivazione e la disattivazione.