angularjs - this angular js




Qual è la differenza tra "@" e "=" nell'ambito della direttiva in AngularJS? (12)

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/


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


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


@ associa una proprietà scope locale / direttiva al valore valutato dell'attributo DOM. = associa una proprietà scope locale / direttiva a una proprietà dell'ambito genitore. & binding è per passare un metodo nell'ambito della tua direttiva in modo che possa essere chiamato all'interno della tua direttiva.

@ Vincolo stringa attributo = Associazione modello a due vie e Associazione metodo callback


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.


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.


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>

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


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

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


la principale differenza tra loro è giusta

@ Attribute string binding
= Two-way model binding
& Callback method binding

@ 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


La proprietà @ scope locale viene utilizzata per accedere ai valori stringa definiti all'esterno della direttiva.

= Nei casi in cui è necessario creare un legame bidirezionale tra l'ambito esterno e l'ambito di isolamento della direttiva, è possibile utilizzare il carattere =.

La proprietà & scope locale consente al consumatore di una direttiva di passare in una funzione che la direttiva può richiamare.

Si prega di controllare il link qui sotto che ti dà una chiara comprensione con esempi. L'ho trovato davvero molto utile, quindi ho pensato di condividerlo.

http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-2-isolate-scope







isolated-scope