¿Cuál es la diferencia entre ‘@’ y ‘=’ en el scope de la directiva en AngularJS?

He leído detenidamente la documentación de AngularJS sobre el tema y luego jugueteé con una directiva. Aquí está el violín .

Y aquí hay algunos fragmentos relevantes:

  • Del HTML:

    {{text}} 
  • De la directiva del panel:

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

Hay varias cosas que no entiendo:

  • ¿Por qué tengo que usar "{{title}}" con '@' y "title" con '=' ?
  • ¿Puedo acceder también directamente al ámbito principal sin decorar mi elemento con un atributo?
  • La documentación dice “A menudo es deseable pasar datos del scope aislado a través de una expresión y al scope principal” , pero parece funcionar bien con el enlace bidireccional también. ¿Por qué la ruta de expresión sería mejor?

Encontré otro violín que también muestra la solución de expresión: http://jsfiddle.net/maxisam/QrCXh/

¿Por qué tengo que usar “{{título}}” con ‘ @ ‘ y “título” con ‘ = ‘?

@ vincula una propiedad de ámbito local / directiva al valor evaluado del atributo DOM . Si usa title=title1 o title="title1" , el valor del atributo “título” DOM ​​es simplemente el título de la title1 . Si usa title="{{title}}" , el valor del atributo DOM “title” es el valor interpolado de {{title}} , por lo tanto, la cadena será cualquier propiedad de ámbito principal en la que esté actualmente “title”. Como los valores de los atributos siempre son cadenas, siempre se obtendrá un valor de cadena para esta propiedad en el ámbito de la directiva cuando se usa @ .

= vincula una propiedad de ámbito local / directivo a una propiedad de ámbito principal . Entonces, con = , usa el nombre de la propiedad padre del modelo / scope como el valor del atributo DOM. No puedes usar {{}} s con = .

Con @, puede hacer cosas como title="{{title}} and then some" se interpola title="{{title}} and then some" – {{title}}, luego la cadena “y them some” se concatena con ella. La cadena concatenada final es lo que obtiene la propiedad del scope local / directivo. (No puedes hacer esto con = , solo @ .)

Con @ , necesitará usar attr.$observe('title', function(value) { ... }) si necesita usar el valor en su función de enlace (ing). Por ejemplo, if(scope.title == "...") no funcionará como esperaba. Tenga en cuenta que esto significa que solo puede acceder a este atributo de forma asincrónica . No necesita usar $ observe () si solo está utilizando el valor en una plantilla. Por ejemplo, template: '

{{title}}

' .

Con = , no necesita usar $ observe.

¿Puedo acceder también directamente al ámbito principal sin decorar mi elemento con un atributo?

Sí, pero solo si no usa un scope aislado. Elimine esta línea de su directiva

scope: { ... }

y luego su directiva no creará un nuevo scope. Utilizará el scope principal. A continuación, puede acceder a todas las propiedades del ámbito primario directamente.

La documentación dice “A menudo es deseable pasar datos del scope aislado a través de una expresión y al scope principal”, pero parece funcionar bien con el enlace bidireccional también. ¿Por qué la ruta de expresión sería mejor?

Sí, la vinculación bidireccional permite que el scope local / directiva y el scope principal compartan datos. El “enlace de expresiones” permite que la directiva invoque una expresión (o función) definida por un atributo DOM, y también puede pasar datos como argumentos a la expresión o función. Por lo tanto, si no necesita compartir datos con el padre, solo desea llamar a una función definida en el scope principal, puede usar la syntax & .

Ver también

  • El blog de scope aislado de Lukas (cubre @, =, &)
  • La explicación de dnc253 de @ y =
  • mi respuesta tipo blog sobre ámbitos: la sección de directivas (camino al pie, justo antes de la sección Resumen) tiene una imagen de un scope aislado y su ámbito principal: el scope de la directiva usa @ para una propiedad y = para otra
  • Cuál es la diferencia entre & vs @ y = en angularJS

Aquí hay muchas respuestas excelentes, pero me gustaría ofrecer mi perspectiva sobre las diferencias entre @ , = y & binding que resultaron útiles para mí.

Los tres enlaces son formas de pasar datos de su ámbito principal al ámbito aislado de su directiva a través de los atributos del elemento:

  1. @ binding es para pasar cadenas. Estas cadenas admiten expresiones {{}} para valores interpolados. Por ejemplo: . La expresión interpolada se evalúa contra el scope primario de la directiva.

  2. = vinculante es para enlace de modelo bidireccional. El modelo en el scope principal está vinculado al modelo en el scope aislado de la directiva. Los cambios en un modelo afectan al otro y viceversa.

  3. & binding es para pasar un método al scope de su directiva para que pueda ser llamado dentro de su directiva. El método está vinculado previamente al scope principal de la directiva y admite argumentos. Por ejemplo, si el método es hello (nombre) en el ámbito principal, entonces para ejecutar el método desde el interior de su directiva, debe llamar a $ scope.hello ({name: ‘world’})

Encuentro que es más fácil recordar estas diferencias al hacer referencia a los enlaces del scope mediante una descripción más breve:

  • @ Atributo de cadena de atributo
  • = Enlace de modelo bidireccional
  • & enlace de método de callback

Los símbolos también aclaran lo que representa la variable de scope dentro de la implementación de su directiva:

  • @ cadena
  • = modelo
  • & método

En orden de utilidad (para mí de todos modos):

  1. =
  2. @
  3. &

The = significa enlace bidireccional, por lo que una referencia a una variable para el scope principal. Esto significa que cuando cambie la variable en la directiva, también se cambiará en el scope principal.

@ significa que la variable se copiará (clonará) en la directiva.

Por lo que sé, {{text}} debería funcionar también. bi-title recibirá el valor de la variable del ámbito principal, que se puede cambiar en la directiva.

Si necesita cambiar varias variables en el ámbito primario, podría ejecutar una función en el ámbito principal desde dentro de la directiva (o pasar datos a través de un servicio).

Si desea ver más cómo funciona esto con un ejemplo en 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: "

{{title1}} {{title2}}

" }; });

@ obtener como cadena

  • Esto no crea ningún enlace en absoluto. Simplemente está recibiendo la palabra que pasó como una cadena

= 2 vías

  • los cambios realizados desde el controlador se reflejarán en la referencia de la directiva, y viceversa

& Esto se comporta de forma un poco diferente, porque el scope obtiene una función que devuelve el objeto que se pasó . Supongo que esto fue necesario para que funcione. El violín debería aclarar esto.

  • Después de llamar a esta función getter, el objeto resultante se comporta de la siguiente manera:
    • si se pasó una función : entonces la función se ejecuta en el cierre principal (controlador) cuando se llama
    • si se pasó una no función : simplemente obtenga una copia local del objeto que no tiene enlaces

Este violín debería demostrar cómo funcionan . Preste especial atención a las funciones del scope con get... en el nombre para poder entender mejor lo que quiero decir sobre &

Hay tres formas en que se puede agregar el scope en la directiva:

  1. Ámbito principal : esta es la herencia de scope predeterminada.

La directiva y su ámbito principal (controlador / directiva dentro de la cual se encuentra) son los mismos. Por lo tanto, cualquier cambio realizado en las variables de ámbito dentro de la directiva se refleja también en el controlador principal. No necesita especificar esto ya que es el predeterminado.

  1. Ámbito hijo : la directiva crea un ámbito hijo que hereda del ámbito primario si especifica la variable de ámbito de la directiva como verdadera.

Aquí, si cambia las variables de ámbito dentro de la directiva, no se reflejará en el ámbito primario, pero si cambia la propiedad de una variable de ámbito, eso se refleja en el ámbito principal, ya que realmente modificó la variable de ámbito del elemento primario .

Ejemplo,

 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. Alcance aislado : se usa cuando desea crear el scope que no hereda del scope del controlador.

Esto sucede cuando se crean complementos, ya que esto hace que la directiva sea genérica, ya que puede colocarse en cualquier HTML y no se ve afectada por su scope principal.

Ahora, si no desea ninguna interacción con el scope principal, entonces puede simplemente especificar el scope como un objeto vacío. me gusta,

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

En general, este no es el caso, ya que necesitamos cierta interacción con el scope principal, por lo que queremos que algunos de los valores / cambios pasen. Por esta razón, utilizamos:

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

@ significa que los cambios del ámbito del controlador se reflejarán en el scope de la directiva, pero si modifica el valor en el ámbito de la directiva, la variable de ámbito del controlador no se verá afectada.

@ siempre espera que el atributo mapeado sea una expresión. Esto es muy importante; porque para hacer que el prefijo “@” funcione, debemos ajustar el valor del atributo dentro de {{}}.

= es bidireccional, por lo que si cambia la variable en el scope de la directiva, la variable de scope del controlador también se verá afectada

& se utiliza para vincular el método del scope del controlador de modo que, si es necesario, podemos llamarlo desde la directiva

La ventaja aquí es que el nombre de la variable no necesita ser el mismo en el ámbito del controlador y el scope de la directiva.

Ejemplo, el scope de la directiva tiene una variable “dirVar” que se sincroniza con la variable “contVar” del scope del controlador. Esto le da mucha potencia y generalización a la directiva ya que un controlador puede sincronizar con la variable v1 mientras que otro controlador que usa la misma directiva puede pedirle a dirVar que se sincronice con la variable v2.

A continuación se muestra el ejemplo de uso:

La directiva y el controlador son:

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

Y el html (tenga en cuenta la diferencia para @ y =):

 

Aquí hay un enlace al blog que lo describe muy bien.

Simplemente podemos usar:

  1. @ : – para valores de cadena para un enlace de datos de una manera. en el enlace de datos de una manera solo puede pasar el valor de scope a la directiva

  2. = : – para el valor del objeto para el enlace de datos bidireccional. en el enlace de datos bidireccional puede cambiar el valor del scope en la directiva y también en html.

  3. & : – para métodos y funciones.

EDITAR

En nuestra definición de componente para la versión angular 1.5 y superior
hay cuatro tipos diferentes de enlaces:

  1. = Enlace de datos bidireccional : si cambiamos el valor, se actualiza automáticamente
  2. < vinculación unidireccional : cuando solo queremos leer un parámetro desde un ámbito principal y no actualizarlo.

  3. @ esto es para los parámetros de cadena

  4. & esto es para rellamadas en caso de que su componente necesite producir algo en su scope principal

Creé un pequeño archivo HTML que contiene un código angular que demuestra las diferencias entre ellos:

 < !DOCTYPE html>   Angular        

La = forma es de enlace bidireccional , que le permite tener cambios en vivo dentro de su directiva. Cuando alguien cambia esa variable fuera de la directiva, tendrá esos datos modificados dentro de su directiva, pero @ way no es bidireccional. Funciona como texto . Usted se une una vez, y tendrá solo su valor.

Para entenderlo más claramente, puedes usar este excelente artículo:

Ámbito de la Directiva AngularJS ‘@’ y ‘=’

@ propiedad de ámbito local se utiliza para acceder a los valores de cadena que se definen fuera de la directiva.

= En los casos en que necesite crear un enlace bidireccional entre el scope externo y el scope aislado de la directiva, puede usar el carácter =.

y la propiedad de scope local permite al consumidor de una directiva pasar una función que la directiva puede invocar.

Por favor revise el enlace a continuación, que le da una comprensión clara con ejemplos. Lo encontré realmente muy útil, así que pensé en compartirlo.

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

Implementé todas las opciones posibles en un violín.

Se trata de todas las opciones:

 scope:{ name:'&' }, scope:{ name:'=' }, scope:{ name:'@' }, scope:{ }, scope:true, 

https://jsfiddle.net/rishulmatta/v7xf2ujm

Incluso cuando el scope es local, como en su ejemplo, puede acceder al scope principal a través de la propiedad $parent . Suponga en el código a continuación, ese title se define en el scope principal. A continuación, puede acceder al título como $parent.title :

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

Sin embargo, en la mayoría de los casos, el mismo efecto se obtiene mejor utilizando atributos.

Un ejemplo de dónde encontré la notación “&”, que se usa para “pasar datos del ámbito aislado a través de una expresión y al scope principal”, es útil (y no se pudo usar un enlace de datos bidireccional) en una directiva. para representar una estructura de datos especial dentro de una repetición ng.

   

Una parte del renderizado fue un botón para eliminar y aquí fue útil adjuntar una función de eliminación del scope externo a través de &. Dentro de la directiva de renderización se ve como

 scope : { data = "=", deleteFunction = "&"}, template : "... " 

No se puede utilizar la vinculación de data = "=" bidireccional, es decir, data = "=" ya que la función de eliminación se ejecutaría en cada $digest ciclo de $digest , lo que no es bueno, ya que el registro se elimina inmediatamente y nunca se procesa.

@ y = ver otras respuestas.

One gotcha about &
TL; DR;
& obtiene expresión (no solo funciona como en ejemplos en otras respuestas) de un padre, y lo establece como una función en la directiva, que llama a la expresión. Y esta función tiene la capacidad de reemplazar cualquier variable (incluso el nombre de la función) de la expresión, pasando un objeto con las variables.

explicado
& es una referencia de expresión, eso significa que si pasa algo como
en la directiva este expr será una función que llama a la expresión, como:
function expr(){return x == y} .
entonces en el html de la directiva se llamará a la expresión. En js de la directiva solo $scope.expr() llamará a la expresión también.
La expresión se llamará con $ scope.x y $ scope.y del padre.
¡Usted tiene la capacidad de anular los parámetros!
Si los configura mediante llamada, por ejemplo,
luego se llamará a la expresión con su parámetro x y el parámetro y padres y .
Puede anular ambos.
Ahora ya sabes, por qué funciona .
Porque simplemente llama a la expresión padre (por ejemplo, ) y reemplaza los valores posibles con los parámetros especificados, en este caso x .
podría ser:

o

con llamada de niño:
.
o incluso con reemplazo de función:
.

es solo una expresión, no importa si es una función, o muchas funciones, o simplemente una comparación. Y puedes reemplazar cualquier variable de esta expresión.

Ejemplos:
plantilla directiva vs código llamado:
el padre ha definido $ scope.x, $ scope.y:
plantilla principal:
llama a $scope.x==$scope.y
llamadas 5 == $scope.y
llamadas 5 == 6

el padre ha definido $ scope.function1, $ scope.x, $ scope.y:
plantilla principal:

llama a $scope.function1($scope.x) + $scope.y
llama a $scope.function1(5) + $scope.y
llama a $scope.function1(5) + 6
La directiva tiene $ scope.myFn como función:
llama a $scope.myFn(5) + 6

la principal diferencia entre ellos es solo

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

¿Por qué tengo que usar “{{título}}” con ‘@’ y “título” con ‘=’?

Cuando use {{title}}, solo el valor del scope principal se pasará a la vista directiva y se evaluará. Esto se limita a una sola dirección, lo que significa que el cambio no se reflejará en el scope principal. Puede usar ‘=’ cuando desee reflejar también los cambios realizados en la directiva infantil al scope principal. Esto es de dos formas.

¿Puedo acceder también directamente al ámbito principal sin decorar mi elemento con un atributo?

Cuando la directiva tiene un atributo de ámbito (ámbito: {}), ya no podrá acceder directamente al ámbito primario. Pero aún es posible acceder a través de scope. $ Parent, etc. Si elimina el scope de la directiva, se puede acceder directamente.

La documentación dice “A menudo es deseable pasar datos del scope aislado a través de una expresión y al scope principal”, pero parece funcionar bien con el enlace bidireccional también. ¿Por qué la ruta de expresión sería mejor?

Depende del contexto Si desea llamar a una expresión o función con datos, usa & y si desea compartir datos, puede usar la forma biderectional usando ‘=’

Puede encontrar las diferencias entre múltiples formas de pasar datos a la directiva en el siguiente enlace:

AngularJS – Scopes aislados – @ vs = vs &

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

@ Atributo de cadena de atributo (unidireccional) = Encuadernación de modelo bidireccional y enlace de método de callback

@ vincula una propiedad de ámbito local / directiva al valor evaluado del atributo DOM. = vincula una propiedad de ámbito local / directivo a una propiedad de ámbito principal. & binding es para pasar un método al scope de su directiva para que pueda ser llamado dentro de su directiva.

@ Atributo de enlace de cadena = Encuadernación de modelo de dos vías y enlace de método de callback