angularjs-directive html - Qual è la differenza tra "@" e "=" nell'ambito della direttiva in AngularJS?




this (15)

Se vuoi vedere di più su come funziona con un esempio dal vivo. http://jsfiddle.net/juanmendez/k6chmnch/

var app = angular.module('app', []);
app.controller("myController", function ($scope) {
    $scope.title = "binding";
});
app.directive("jmFind", function () {
    return {
        replace: true,
        restrict: 'C',
        transclude: true,
        scope: {
            title1: "=",
            title2: "@"
        },
        template: "<div><p>{{title1}} {{title2}}</p></div>"
    };
});

Ho letto attentamente la documentazione di AngularJS sull'argomento e poi mi sono occupato di una direttiva. Ecco il fiddle .

E qui ci sono alcuni frammenti rilevanti:

  • Dall'HTML:

    <pane bi-title="title" title="{{title}}">{{text}}</pane>
    
  • Dalla direttiva del riquadro:

    scope: { biTitle: '=', title: '@', bar: '=' },
    

Ci sono molte cose che non capisco:

  • Perché devo usare "{{title}}" con '@' e "title" con '=' ?
  • Posso accedere direttamente allo scope genitore, senza decorare il mio elemento con un attributo?
  • La documentazione dice "Spesso è desiderabile passare dati dall'ambito isolato tramite un'espressione e l'ambito genitore" , ma sembra funzionare bene anche con il bind bidirezionale. Perché la via dell'espressione dovrebbe essere migliore?

Ho trovato un altro violino che mostra anche la soluzione di espressione: http://jsfiddle.net/maxisam/QrCXh/


Ci sono tre modi in cui è possibile aggiungere un ambito alla direttiva:

  1. Ambito genitore : si tratta dell'ereditarietà dell'ambito predefinita.

La direttiva e il suo ambito genitore (controller / direttiva all'interno del quale giace) sono gli stessi. Quindi tutte le modifiche apportate alle variabili dell'ambito all'interno della direttiva si riflettono anche nel controller principale. Non è necessario specificarlo poiché è l'impostazione predefinita.

  1. Ambito secondario : direttiva crea un ambito secondario che eredita dall'ambito padre se si specifica la variabile di ambito della direttiva come vera.

Qui, se si modificano le variabili dell'ambito all'interno della direttiva, essa non si rifletterà nello scope genitore, ma se si modifica la proprietà di una variabile scope, questa viene riflessa nell'oggetto genitore, poiché si modificava effettivamente la variabile scope dell'elemento genitore .

Esempio,

app.directive("myDirective", function(){

    return {
        restrict: "EA",
        scope: true,
        link: function(element, scope, attrs){
            scope.somvar = "new value"; //doesnot reflect in the parent scope
            scope.someObj.someProp = "new value"; //reflects as someObj is of parent, we modified that but did not override.
        }
    };
});
  1. Ambito isolato : viene utilizzato quando si desidera creare l'ambito che non eredita dall'ambito del controller.

Questo accade quando si creano plug-in poiché questo rende la direttiva generica poiché può essere inserita in qualsiasi HTML e non viene influenzata dall'ambito principale.

Ora, se non vuoi alcuna interazione con l'ambito genitore, puoi semplicemente specificare l'ambito come un oggetto vuoto. piace,

scope: {} //this does not interact with the parent scope in any way

Principalmente questo non è il caso in quanto abbiamo bisogno di una certa interazione con l'ambito genitore, quindi vogliamo che alcuni dei valori / cambiamenti siano passati. Per questo motivo, usiamo:

1. "@"   (  Text binding / one-way binding )
2. "="   ( Direct model binding / two-way binding )
3. "&"   ( Behaviour binding / Method binding  )

@ significa che le modifiche dall'ambito del controller si rifletteranno nell'ambito della direttiva ma se si modifica il valore nell'ambito della direttiva, la variabile dell'ambito del controller non verrà influenzata.

@ si aspetta sempre che l'attributo mappato sia un'espressione. Questo è molto importante; perché per far funzionare il prefisso "@", dobbiamo racchiudere il valore dell'attributo all'interno di {{}}.

= è bidirezionale, quindi se si modifica la variabile in ambito direttiva, anche la variabile dell'ambito del controller viene influenzata

& è usato per legare il metodo dell'ambito del controllore in modo che, se necessario, possiamo chiamarlo dalla direttiva

Il vantaggio qui è che il nome della variabile non deve essere lo stesso nell'ambito del controller e dell'ambito della direttiva.

Esempio, l'ambito direttiva ha una variabile "dirVar" che si sincronizza con la variabile "contVar" dell'ambito del controller. Ciò fornisce molta potenza e generalizzazione alla direttiva poiché un controller può sincronizzarsi con la variabile v1 mentre un altro controllore che utilizza la stessa direttiva può chiedere a dirVar di sincronizzarsi con la variabile v2.

Di seguito è riportato l'esempio di utilizzo:

La direttiva e il controller sono:

 var app = angular.module("app", []);
 app.controller("MainCtrl", function( $scope ){
    $scope.name = "Harry";
    $scope.color = "#333333";
    $scope.reverseName = function(){
     $scope.name = $scope.name.split("").reverse().join("");
    };
    $scope.randomColor = function(){
        $scope.color = '#'+Math.floor(Math.random()*16777215).toString(16);
    };
});
app.directive("myDirective", function(){
    return {
        restrict: "EA",
        scope: {
            name: "@",
            color: "=",
            reverse: "&"
        },
        link: function(element, scope, attrs){
           //do something like
           $scope.reverse(); 
          //calling the controllers function
        }
    };
});

E l'html (notare la differnce per @ e =):

<div my-directive
  class="directive"
  name="{{name}}"
  reverse="reverseName()"
  color="color" >
</div>

Ecco un link al blog che lo descrive bene.


Il = significa associazione bidirezionale, quindi un riferimento a una variabile per l'ambito genitore. Ciò significa che quando si modifica la variabile nella direttiva, verrà modificata anche nell'ambito genitore.

@ significa che la variabile verrà copiata (clonata) nella direttiva.

Per quanto ne so, <pane bi-title="{{title}}" title="{{title}}">{{text}}</pane> dovrebbe funzionare anche. bi-title riceverà il valore della variabile scope genitore, che può essere modificato nella direttiva.

Se è necessario modificare più variabili nell'ambito genitore, è possibile eseguire una funzione nell'ambito genitore dall'interno della direttiva (o passare i dati tramite un servizio).


@ prendi come stringa

  • Questo non crea alcun vincolo di sorta. Stai semplicemente ottenendo la parola che hai passato come una stringa

= 2 vie

  • le modifiche apportate dal controller si rifletteranno nel riferimento contenuto nella direttiva e viceversa

& Ciò si comporta in modo leggermente diverso, perché l'oscilloscopio ottiene una funzione che restituisce l'oggetto che è stato passato . Suppongo che fosse necessario per farlo funzionare. Il violino dovrebbe chiarirlo.

  • Dopo aver chiamato questa funzione getter, l'oggetto risultante si comporta come segue:
    • se è stata passata una funzione : allora la funzione viene eseguita nella chiusura genitore (controllore) quando viene chiamata
    • se è stata inoltrata una non funzione : è sufficiente ottenere una copia locale dell'oggetto che non ha associazioni


Questo violino dovrebbe dimostrare come funzionano . Presta particolare attenzione alle funzioni dell'ambito con get... nel nome per sperare di capire meglio cosa intendo riguardo &


Perché devo usare "{{title}}" con "@" e "title" con "="?

Quando si utilizza {{title}}, solo il valore dell'ambito genitore verrà passato alla vista direttiva e valutato. Questo è limitato a un modo, il che significa che il cambiamento non si rifletterà nello scope principale. È possibile utilizzare '=' quando si desidera riflettere anche le modifiche apportate nella direttiva figlio all'ambito padre. Questo è a due vie.

Posso accedere direttamente allo scope genitore, senza decorare il mio elemento con un attributo?

Quando la direttiva ha attributo scope (scope: {}), allora non sarà più possibile accedere direttamente all'ambito genitore. Ma è ancora possibile accedervi tramite scope. $ Parent etc. Se si rimuove scope da direttiva, è possibile accedervi direttamente.

La documentazione dice "Spesso è desiderabile passare dati dall'ambito isolato tramite un'espressione e l'ambito genitore", ma sembra funzionare bene anche con il bind bidirezionale. Perché la via dell'espressione dovrebbe essere migliore?

Dipende dal contesto. Se si desidera chiamare un'espressione o una funzione con dati, si utilizza & e se si desidera condividere i dati, è possibile utilizzare la modalità di biderection utilizzando '='

Puoi trovare le differenze tra i diversi modi di passare i dati alla direttiva al link sottostante:

AngularJS - Scopes isolati - @ vs = vs &

http://www.codeforeach.com/angularjs/angularjs-isolated-scopes-vs-vs


Perché devo usare "{{title}}" con " @ " e "title" con " = "?

@ associa una proprietà scope locale / direttiva al valore valutato dell'attributo DOM . Se si utilizza title=title1 o title="title1" , il valore dell'attributo DOM "title" è semplicemente la stringa title1 . Se si utilizza title="{{title}}" , il valore dell'attributo DOM "title" è il valore interpolato di {{title}} , quindi la stringa sarà qualsiasi proprietà dell'ambito genitore "title" è attualmente impostata su. Dato che i valori degli attributi sono sempre stringhe, quando si utilizza @ viene sempre incluso un valore di stringa per questa proprietà nell'ambito della direttiva.

= associa una proprietà scope locale / direttiva a una proprietà dell'ambito genitore . Quindi con = , si utilizza il nome della proprietà modello / scope genitore come valore dell'attributo DOM. Non puoi usare {{}} s con = .

Con @, puoi fare cose come title="{{title}} and then some" - {{title}} è interpolato, quindi la stringa "e loro alcuni" è concatenata con esso. La stringa concatenata finale è ciò che ottiene la proprietà scope locale / direttiva. (Non puoi farlo con = , solo @ .)

Con @ , dovrai usare attr.$observe('title', function(value) { ... }) se hai bisogno di usare il valore nella tua funzione link (ing). Ad esempio, if(scope.title == "...") non funzionerà come previsto. Nota che questo significa che puoi accedere a questo attributo in asynchronously . Non è necessario utilizzare $ observ () se si utilizza solo il valore in un modello. Ad esempio, template: '<div>{{title}}</div>' .

Con = , non è necessario utilizzare $ observ.

Posso accedere direttamente allo scope genitore, senza decorare il mio elemento con un attributo?

Sì, ma solo se non si utilizza un ambito isolato. Rimuovi questa linea dalla tua direttiva

scope: { ... }

e quindi la tua direttiva non creerà un nuovo ambito. Utilizzerà l'ambito genitore. È quindi possibile accedere direttamente a tutte le proprietà dell'ambito principale.

La documentazione dice "Spesso è desiderabile passare dati dall'ambito isolato tramite un'espressione e l'ambito genitore", ma sembra funzionare bene anche con il bind bidirezionale. Perché la via dell'espressione dovrebbe essere migliore?

Sì, l'associazione bidirezionale consente all'ambito locale / direttiva e all'ambito principale di condividere i dati. "Expression binding" consente alla direttiva di chiamare un'espressione (o funzione) definita da un attributo DOM e inoltre è possibile passare i dati come argomenti all'espressione o alla funzione. Quindi, se non hai bisogno di condividere i dati con il genitore - vuoi solo chiamare una funzione definita nell'ambito genitore - puoi usare la sintassi & .

Guarda anche


Ho creato un piccolo file HTML che contiene codice angolare che dimostra le differenze tra loro:

<!DOCTYPE html>
<html>
  <head>
    <title>Angular</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
  </head>
  <body ng-app="myApp">
    <div ng-controller="myCtrl as VM">
      <a my-dir
        attr1="VM.sayHi('Juan')" <!-- scope: "=" -->
        attr2="VM.sayHi('Juan')" <!-- scope: "@" -->
        attr3="VM.sayHi('Juan')" <!-- scope: "&" -->
      ></a>
    </div>
    <script>
    angular.module("myApp", [])
    .controller("myCtrl", [function(){
      var vm = this;
      vm.sayHi = function(name){
        return ("Hey there, " + name);
      }
    }])
    .directive("myDir", [function(){
      return {
        scope: {
          attr1: "=",
          attr2: "@",
          attr3: "&"
        },
        link: function(scope){
          console.log(scope.attr1);   // =, logs "Hey there, Juan"
          console.log(scope.attr2);   // @, logs "VM.sayHi('Juan')"
          console.log(scope.attr3);   // &, logs "function (a){return h(c,a)}"
          console.log(scope.attr3()); // &, logs "Hey there, Juan"
        }
      }
    }]);
    </script>
  </body>
</html>

@ Assegnazione di stringhe di attributi (solo andata) = Associazione di modelli a due vie e Associazione del metodo di callback


Ci sono molte grandi risposte qui, ma vorrei offrire la mia prospettiva sulle differenze tra @ , = e vincolanti che si sono rivelate utili per me.

Tutti e tre i collegamenti sono modi per trasferire i dati dall'ambito principale all'ambito isolato della direttiva attraverso gli attributi dell'elemento:

  1. @ binding è per passare stringhe. Queste stringhe supportano le espressioni {{}} per i valori interpolati. Per esempio: . L'espressione interpolata viene valutata rispetto all'ambito principale della direttiva.

  2. = il legame è per il bind modello a due vie. Il modello nell'oggetto principale è collegato al modello nell'ambito isolato della direttiva. Le modifiche a un modello influiscono sull'altro e viceversa.

  3. & binding è per passare un metodo nell'ambito della tua direttiva in modo che possa essere chiamato all'interno della tua direttiva. Il metodo è pre-associato all'ambito padre della direttiva e supporta gli argomenti. Ad esempio, se il metodo è hello (nome) nell'oggetto principale, per eseguire il metodo dall'interno della direttiva, è necessario chiamare $ scope.hello ({name: 'world'})

Trovo che sia più facile ricordare queste differenze facendo riferimento ai collegamenti degli scope con una descrizione più breve:

  • @ Assegnazione di stringhe di attributi
  • = Associazione modello a due vie
  • & Binding del metodo di callback

I simboli rendono anche più chiaro ciò che la variabile scope rappresenta all'interno dell'implementazione della tua direttiva:

  • @ stringa
  • = modello
  • & metodo

In ordine di utilità (per me comunque):

  1. =
  2. @
  3. &

@ e = vedi altre risposte.

Una cosa su &
TL; DR;
& ottiene espressione (non solo funziona come negli esempi in altre risposte) da un genitore, e lo imposta come una funzione nella direttiva, che chiama l'espressione. E questa funzione ha la capacità di sostituire qualsiasi variabile (anche il nome della funzione) di espressione, passando un oggetto con le variabili.

ha spiegato
& è un'espressione di riferimento, ovvero se passi qualcosa come <myDirective expr="x==y"></myDirective>
nella direttiva questo expr sarà una funzione, che chiama l'espressione, come:
function expr(){return x == y} .
quindi in html della direttiva <button ng-click="expr()"></button> chiamerà l'espressione. In js della direttiva, solo $scope.expr() chiamerà anche l'espressione.
L'espressione verrà chiamata con $ scope.x e $ scope.y del genitore.
Hai la possibilità di sovrascrivere i parametri!
Se li imposti per chiamata, ad esempio <button ng-click="expr({x:5})"></button>
quindi l'espressione verrà chiamata con il parametro x e il parametro parent y .
È possibile ignorare entrambi.
Ora sai, perché <button ng-click="functionFromParent({x:5})"></button> funziona.
Perché chiama solo l'espressione di genitore (ad esempio <myDirective functionFromParent="function1(x)"></myDirective> ) e sostituisce i possibili valori con i parametri specificati, in questo caso x .
potrebbe essere:
<myDirective functionFromParent="function1(x) + 5"></myDirective>
o
<myDirective functionFromParent="function1(x) + z"></myDirective>
con chiamata bambino:
<button ng-click="functionFromParent({x:5, z: 4})"></button> .
o anche con la sostituzione della funzione:
<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button> .

è solo un'espressione, non importa se è una funzione, o molte funzioni, o solo un confronto. E puoi sostituire qualsiasi variabile di questa espressione.

Esempi:
modello di direttiva vs codice chiamato:
genitore ha definito $ scope.x, $ scope.y:
modello principale: <myDirective expr="x==y"></myDirective>
<button ng-click="expr()"></button> chiama $scope.x==$scope.y
<button ng-click="expr({x: 5})"></button> chiama 5 == $scope.y
<button ng-click="expr({x:5, y:6})"></button> chiama 5 == 6

genitore ha definito $ scope.function1, $ scope.x, $ scope.y:
modello principale: <myDirective expr="function1(x) + y"></myDirective>

<button ng-click="expr()"></button> chiama $scope.function1($scope.x) + $scope.y
<button ng-click="expr({x: 5})"></button> chiama $scope.function1(5) + $scope.y
<button ng-click="expr({x:5, y:6})"></button> chiama $scope.function1(5) + 6
direttiva ha $ scope.myFn come funzione:
<button ng-click="expr({function1: myFn, x:5, y:6})"></button> chiama $scope.myFn(5) + 6


Ho implementato tutte le opzioni possibili in un violino.

Si occupa di tutte le opzioni:

scope:{
    name:'&'
},

scope:{
    name:'='
},

scope:{
    name:'@'
},

scope:{

},

scope:true,

https://jsfiddle.net/rishulmatta/v7xf2ujm


The = way è l' associazione a 2 vie , che ti consente di avere modifiche live all'interno della tua direttiva. Quando qualcuno cambia quella variabile di direttiva, avrai i dati modificati all'interno della direttiva, ma @ way non è bind a due vie . Funziona come il testo . Ti leghi una volta e avrai solo il suo valore.

Per ottenerlo più chiaramente, puoi usare questo fantastico articolo:

Ambito della direttiva AngularJS '@' e '='


Semplicemente possiamo usare: -

  1. @ : - per i valori stringa per l'associazione dati in un modo. in un modo di associazione dati è possibile solo passare il valore di ambito alla direttiva

  2. = : - per il valore dell'oggetto per l'associazione dati bidirezionale. in associazione bidirezionale dei dati è possibile modificare anche il valore dell'ambito in direttiva e anche in html.

  3. & : - per metodi e funzioni.

MODIFICARE

Nella nostra definizione di componente per Angular versione 1.5 E sopra
ci sono quattro diversi tipi di attacchi:

  1. = Associazione dati bidirezionale : - se cambiamo il valore, si aggiorna automaticamente
  2. < binding a senso unico : - quando vogliamo solo leggere un parametro da un ambito genitore e non aggiornarlo.

  3. @ questo è per i parametri stringa

  4. & questo è per Callback nel caso in cui il tuo componente abbia bisogno di produrre qualcosa per il suo genitore


Anche quando l'ambito è locale, come nel tuo esempio, puoi accedere all'ambito genitore attraverso la proprietà $parent . Supponiamo che nel codice sottostante, tale title sia definito nell'ambito genitore. Puoi quindi accedere al titolo come $parent.title :

link : function(scope) { console.log(scope.$parent.title) },
template : "the parent has the title {{$parent.title}}"

Tuttavia nella maggior parte dei casi lo stesso effetto è ottenuto meglio usando gli attributi.

Un esempio di dove ho trovato la notazione "&", che è usata "per passare dati dall'ambito isolato tramite un'espressione e all'ambito genitore", era utile (e un databinding bidirezionale non poteva essere usato) in una direttiva per il rendering di una datastruttura speciale all'interno di una ng-repeat.

<render data = "record" deleteFunction = "dataList.splice($index,1)" ng-repeat = "record in dataList" > </render>

Una parte del rendering era un pulsante di cancellazione e qui era utile collegare una funzione di eliminazione dall'ambito esterno tramite &. All'interno della direttiva di rendering sembra

scope : { data = "=", deleteFunction = "&"},
template : "... <button ng-click = "deleteFunction()"></button>"

L'associazione data = "=" bidirezionale cioè data = "=" non può essere utilizzata poiché la funzione di eliminazione verrebbe eseguita su ogni ciclo $digest , il che non è buono, poiché il record viene immediatamente eliminato e mai reso.


AngularJS e jQuery:

AngularJs e JQuery sono completamente diversi ad ogni livello tranne la funzionalità JQLite e lo vedrai quando inizierai ad imparare le caratteristiche principali di AngularJs (l'ho spiegato in seguito).

AngularJs è un framework lato client che offre la possibilità di creare l'applicazione lato client indipendente. JQuery è una libreria lato client che gioca attorno al DOM.

AngularJs Cool Principle - Se vuoi che alcune modifiche sulla tua interfaccia utente vengano prese in considerazione dal punto di vista del cambiamento dei dati del modello. Cambia i tuoi dati e l'interfaccia utente si renderà nuovamente. Non è necessario giocare intorno a DOM ogni volta, a meno che e fino a quando non sia richiesto e questo dovrebbe anche essere gestito attraverso le direttive angolari.

Per rispondere a questa domanda, voglio condividere la mia esperienza sulla prima applicazione aziendale con AngularJS. Queste sono le caratteristiche più straordinarie che Angular fornisce dove iniziamo a cambiare la nostra mentalità jQuery e otteniamo l'Angolare come una struttura e non come una libreria.

L'associazione dei dati a due vie è sorprendente: avevo una griglia con tutte le funzionalità UPDATE, DELTE, INSERT. Ho un oggetto dati che lega il modello della griglia usando ng-repeat. Hai solo bisogno di scrivere una singola riga di semplice codice JavaScript per eliminare e inserire e il gioco è fatto. la griglia si aggiorna automaticamente quando il modello di griglia cambia istantaneamente. La funzionalità di aggiornamento è in tempo reale, nessun codice per questo. Ti senti fantastico !!!

Le direttive riutilizzabili sono super: scrivi direttive in un unico posto e utilizzale in tutta l'applicazione. OH MIO DIO!!! Ho usato queste direttive per il paging, regex, validazioni, ecc. È davvero fantastico!

Il routing è forte: dipende dalla tua implementazione come vuoi usarlo, ma richiede pochissime righe di codice per instradare la richiesta per specificare HTML e controller (JavaScript)

I controller sono grandi: i controller si prendono cura del proprio codice HTML, ma questa separazione funziona bene per le funzionalità comuni. Se si desidera richiamare la stessa funzione al clic di un pulsante su HTML master, è sufficiente scrivere lo stesso nome di funzione in ciascun controller e scrivere il codice individuale.

Plugin: ci sono molte altre funzioni simili come mostrare una sovrapposizione nella tua app. Non è necessario scrivere codice per questo, basta usare un plug-in overlay disponibile come overlay wc e questo si prenderà automaticamente cura di tutte le richieste XMLHttpRequest (XHR).

Ideale per l' architettura RESTful : l' essere un framework completo rende AngularJS ideale per lavorare con un'architettura RESTful. Chiamare le API REST CRUD è molto più semplice e

Servizi : scrivere codici comuni utilizzando servizi e meno codice nei controller. I sevizi possono essere utilizzati per condividere funzionalità comuni tra i controller.

Estensibilità : Angular ha esteso le direttive HTML utilizzando direttive angolari. Scrivi espressioni in html e valutale in runtime. Crea le tue direttive e i tuoi servizi e usali in un altro progetto senza ulteriori sforzi.





angularjs angularjs-directive angularjs-scope isolated-scope