angularjs - tutorial - html angular 1




Quando si scrive una direttiva in AngularJS, come posso decidere se non ho bisogno di un nuovo ambito, un nuovo ambito figlio o un nuovo ambito isolato? (4)

Sto cercando alcune linee guida che è possibile utilizzare per determinare quale tipo di ambito utilizzare quando si scrive una nuova direttiva. Idealmente, mi piacerebbe qualcosa di simile a un diagramma di flusso che mi guidi attraverso una serie di domande e che apra la risposta corretta - nessun nuovo nuovo scope, nuovo scope secondario o nuovo scope isolato - ma probabilmente è chiedere troppo. Ecco la mia attuale serie di linee guida:

Sono consapevole del fatto che l'utilizzo di una direttiva con un ambito isolato su un elemento impone a tutte le altre direttive su quello stesso elemento di utilizzare lo stesso (un) ambito isolato, quindi questo non limita fortemente quando è possibile utilizzare un ambito isolato?

Spero che alcuni del team di Angular-UI (o altri che hanno scritto molte direttive) possano condividere le loro esperienze.

Si prega di non aggiungere una risposta che dice semplicemente "utilizzare un ambito isolato per componenti riutilizzabili".


La mia politica personale ed esperienza:

Isolato: una sabbiera privata

Voglio creare molti metodi e variabili di scope che sono usati SOLO dalla mia direttiva e non sono mai visti o direttamente accessibili dall'utente. Voglio autorizzare i dati sulla portata a mia disposizione. Posso usare la transclusione per consentire all'utente di tornare all'ambito genitore (inalterato) . NON voglio che le mie variabili e i metodi siano accessibili ai bambini esclusi.

Bambino: una sottosezione di contenuti

Voglio creare metodi e variabili dell'oscilloscopio a cui l'utente può accedere, ma non sono pertinenti agli ambiti circostanti (fratelli e genitori) al di fuori del contesto della mia direttiva. Vorrei anche consentire a TUTTI i dati relativi all'ambito genitore di scorrere verso il basso in modo trasparente.

Nessuno: direttive semplici e di sola lettura

Non ho davvero bisogno di fare confusione con i metodi o le variabili dell'ambito. Probabilmente sto facendo qualcosa che non ha a che fare con gli ambiti (come la visualizzazione di semplici plugin jQuery, la convalida, ecc.).

Gli appunti

  • Non dovresti lasciare che ngModel o altre cose influenzino direttamente la tua decisione. Puoi aggirare comportamenti strani facendo cose come ng-model=$parent.myVal (child) o ngModel: '=' (isolare).
  • Isolate + transclude ripristinerà tutto il normale comportamento alle direttive di pari livello e ritorna allo scope genitore, quindi non lasciare che questo influenzi anche il tuo giudizio.
  • Non pasticciare con l'ambito su nessuno perché è come mettere i dati sull'oscilloscopio per la metà inferiore del DOM ma non per la metà superiore che ha senso.
  • Presta attenzione alle priorità direttive (non hai esempi concreti di come questo possa influenzare le cose)
  • Iniettare servizi o utilizzare controller per comunicare tra direttive con qualsiasi tipo di ambito. Puoi anche require: '^ngModel' per cercare gli elementi parent.

Che bella domanda! Mi piacerebbe sapere cosa hanno da dire gli altri, ma ecco le linee guida che uso.

La premessa ad alta quota: lo scope è usato come "colla" che usiamo per comunicare tra il controllore genitore, la direttiva e il modello di direttiva.

Ambito del genitore: scope: false , quindi nessun nuovo scope

Non lo uso molto spesso, ma come ha detto @MarkRajcok, se la direttiva non accede a nessuna variabile di ambito (e ovviamente non ne imposta nessuna!), Per quanto mi riguarda, ciò va benissimo. Ciò è utile anche per le direttive figlio che vengono utilizzate solo nel contesto della direttiva padre (sebbene ci siano sempre eccezioni a questo) e che non abbiano un modello. Fondamentalmente qualsiasi cosa con un modello non appartiene alla condivisione di un ambito, perché si espone in modo intrinseco tale ambito di accesso e manipolazione (ma sono sicuro che ci sono eccezioni a questa regola).

Ad esempio, di recente ho creato una direttiva che disegna un grafico vettoriale (statico) utilizzando una libreria SVG in fase di scrittura. $observe s i due attributi ( width e height ) e li usa nei suoi calcoli, ma non imposta né legge alcuna variabile di ambito e non ha template. Questo è un buon caso per non creare un altro ambito; non ne abbiamo bisogno, quindi perché preoccuparsi?

Ma in un'altra direttiva SVG, tuttavia, ho richiesto un set di dati da utilizzare e inoltre ho dovuto memorizzare un piccolo bit di stato. In questo caso, utilizzare l'ambito genitore sarebbe irresponsabile (di nuovo, in generale). Quindi invece...

Ambito del bambino: scope: true

Le direttive con un ambito figlio sono sensibili al contesto e hanno lo scopo di interagire con l'ambito corrente.

Ovviamente, un vantaggio chiave di questo rispetto a un ambito isolato è che l'utente è libero di utilizzare l'interpolazione su qualsiasi attributo desiderato; ad esempio usando class="item-type-{{item.type}}" su una direttiva con un ambito isolato non funzionerà di default, ma funziona bene su uno con un ambito figlio perché qualsiasi cosa è interpolata può ancora essere trovata per default in l'ambito genitore. Inoltre, la direttiva stessa può tranquillamente valutare attributi ed espressioni nel contesto del proprio ambito di applicazione senza preoccuparsi dell'inquinamento o del danno al genitore.

Ad esempio, un suggerimento è qualcosa che viene appena aggiunto; un ambito isolato non funzionerebbe (di default, vedi sotto) perché ci si aspetta che useremo altre direttive o attributi interpolati qui. Il tooltip è solo un miglioramento. Ma il tooltip ha anche bisogno di impostare alcune cose sullo scope da usare con una sotto-direttiva e / o template e ovviamente per gestire il proprio stato, quindi sarebbe piuttosto brutto usare l'ambito genitore. Lo stiamo inquinando o danneggiandolo, e nessuno dei due è bueno.

Mi trovo a utilizzare gli ambiti figlio più spesso degli ambiti isolati o parent.

Isolare ambito: scope: {}

Questo è per componenti riutilizzabili. :-)

Ma seriamente, penso a "componenti riutilizzabili" come "componenti autosufficienti". L'intento è che debbano essere usati per uno scopo specifico, quindi combinarli con altre direttive o aggiungere intrinsecamente altri attributi interpolati al nodo DOM non ha senso.

Per essere più specifici, qualsiasi cosa necessaria per questa funzionalità standalone viene fornita attraverso attributi specificati valutati nel contesto dell'ambito principale; sono sia stringhe unidirezionali ('@'), espressioni unidirezionali ('&') o associazioni di variabili bidirezionali ('=').

Su componenti autonomi, non ha senso aver bisogno di applicare altre direttive o attributi su di esso perché esiste da solo. Il suo stile è governato da un proprio modello (se necessario) e può contenere il contenuto appropriato (se necessario). È autonomo, quindi lo abbiamo messo in un ambito isolato anche per dire: "Non scherzare con questo, ti sto dando un'API definita attraverso questi pochi attributi".

Una buona pratica è quella di escludere il maggior numero possibile di contenuti basati su template dal link direttivo e dalle funzioni del controller. Questo fornisce un altro punto di configurazione "API": l'utente della direttiva può semplicemente sostituire il modello! La funzionalità è rimasta invariata e le API interne non sono mai state toccate, ma possiamo fare a meno dell'implementazione del DOM e dello stile tanto quanto è necessario. ui / bootstrap è un ottimo esempio di come farlo bene perché Peter & Pawel sono fantastici.

Gli ambiti di isolamento sono ottimi anche per l'uso con la transizione. Prendere schede; non sono solo l'intera funzionalità, ma tutto ciò che è al suo interno può essere valutato liberamente dall'ambito genitore lasciando le schede (e i riquadri) per fare ciò che vogliono. Le schede hanno chiaramente il loro stato , che appartiene all'ambito (per interagire con il modello), ma quello stato non ha nulla a che fare con il contesto in cui è stato utilizzato - è interamente interno a ciò che rende una direttiva tabulazione una direttiva tab. Inoltre, non ha molto senso utilizzare altre direttive con le schede. Sono schede - e abbiamo già questa funzionalità!

Circondali con più funzionalità o estrai più funzionalità, ma la direttiva è ciò che è già.

Detto questo, devo notare che ci sono modi per aggirare alcune delle limitazioni (cioè le caratteristiche) di un ambito isolato, come suggerito da @ProLoser nella sua risposta. Ad esempio, nella sezione dell'ambito secondario, ho menzionato l'interpolazione sugli attributi non direttivi che si interrompono quando si utilizza un ambito isolato (per impostazione predefinita). Ad esempio, l'utente potrebbe semplicemente usare class="item-type-{{$parent.item.type}}" e funzionerebbe ancora una volta. Quindi, se esiste un motivo valido per utilizzare un ambito isolato su un ambito figlio ma sei preoccupato per alcune di queste limitazioni, sappi che puoi aggirare virtualmente tutti se necessario.

Sommario

Le direttive senza nuovo ambito sono di sola lettura; sono completamente fidati (cioè interni all'app) e non toccano jack. Le direttive con un ambito figlio aggiungono funzionalità, ma non sono l'unica funzionalità. Infine, gli ambiti isolati sono per le direttive che costituiscono l'intero obiettivo; sono indipendenti, quindi va bene (e più "corretti") lasciarli andare fuori di testa.

Volevo ottenere i miei pensieri iniziali, ma mentre penso a più cose, aggiornerò questo. Ma santa merda - questa è una lunga risposta SO ...

PS: Totalmente tangenziale, ma dal momento che stiamo parlando di scope, preferisco dire "prototipico" mentre altri preferiscono "prototipale", che sembra essere più preciso, ma si limita a parlare male per niente. :-)


Ho solo pensato di aggiungere la mia attuale comprensione e il modo in cui si relaziona con altri concetti JS.

Predefinito (ad es. Non dichiarato o ambito: falso)

Questo è filosoficamente equivalente all'utilizzo di variabili globali. La tua direttiva può accedere a qualsiasi cosa nel controllore genitore, ma anche a influire su di essa e allo stesso tempo essere influenzata.

scopo:{}

Questo è come un modulo, tutto ciò che vuole usare deve essere passato in modo esplicito. Se OGNI direttiva che si utilizza è un ambito isolato, può essere l'equivalente di rendere OGNI file JS che si scrive il proprio modulo con un sacco di sovraccarico nell'iniettare tutte le dipendenze.

ambito: bambino

Questa è la via di mezzo tra le variabili globali e il passthrough esplicito. È simile alla catena di prototipi di javascript e ti allunga solo una copia dell'ambito principale. Se si crea un ambito isolato e si passa in ogni attributo e funzione dello scope genitore, è funzionalmente equivalente a questo.

La chiave è che QUALSIASI direttiva può essere scritta IN QUALSIASI modo. Le diverse dichiarazioni di ambito sono solo lì per aiutarti a organizzare. Puoi fare di tutto un modulo, o puoi semplicemente usare tutte le variabili globali e stare molto attento. Per facilità di manutenzione è preferibile modulare la logica in parti logicamente coerenti. C'è un equilibrio tra un prato aperto e una casa chiusa. La ragione per cui questo è complicato credo che quando le persone apprendono di questo, pensano che stiano imparando come funzionano le direttive, ma in realtà stanno imparando sull'organizzazione del codice / logica.

Un'altra cosa che mi ha aiutato a capire come funzionano le direttive è l'apprendimento di ngInclude. ngInclude ti aiuta a includere parziali html. Quando ho iniziato a utilizzare le direttive per la prima volta ho scoperto che si poteva usare la sua opzione modello per ridurre il codice, ma in realtà non stavo collegando alcuna logica.

Naturalmente tra le direttive angolari e il lavoro del team angular-ui non ho ancora dovuto creare una mia direttiva che faccia qualcosa di sostanziale, quindi la mia opinione su questo potrebbe essere completamente sbagliata.


Sono d'accordo con Umur. In teoria, gli ambiti isolati sono meravigliosi e "portabili", ma nel costruire la mia app per coinvolgere funzionalità non banali mi sono imbattuto nella necessità di incorporare diverse direttive (alcune nidificate all'interno di altre o l'aggiunta di attributi a esse) per poter scrivere pienamente nel mio proprio HTML, che è lo scopo di una lingua specifica di dominio.

Alla fine, è troppo strano dover passare ogni valore globale o condiviso lungo la catena con più attributi su ogni invocazione DOM di una direttiva (come richiesto con l'ambito isolato). Sembra semplicemente stupido scrivere ripetutamente tutto ciò nel DOM e si sente inefficiente, anche se questi sono oggetti condivisi. Inoltre complica inutilmente le dichiarazioni della direttiva. La soluzione alternativa all'utilizzo di $ parent per "raggiungere" e acquisire i valori dal codice HTML della direttiva sembra una forma molto cattiva.

Anch'io ho finito col cambiare la mia app per avere direttive per lo più child con pochissimi isolati - solo quelli che non hanno bisogno di accedere a QUALSIASI cosa dal genitore diverso da quello che possono essere passati attraverso attributi semplici e non ripetitivi.

Avendo sognato il sogno delle lingue specifiche del dominio per decenni prima che esistesse una cosa del genere, sono entusiasta del fatto che AngularJS fornisca questa opzione e so che, visto che più sviluppatori lavorano in questo settore, vedremo alcune app molto interessanti che sono anche facili per i loro architetti per scrivere, espandere ed eseguire il debug.

- D





angularjs-scope