directivas - ¿Cuál es la diferencia entre ''@'' y ''='' en el ámbito de la directiva en AngularJS?
ng angular (17)
¿Por qué tengo que usar "{{title}}" con '' @ '' y "title" con '' = ''?
@ enlaza una propiedad de ámbito local / directiva al valor evaluado del atributo DOM . Si usa title=title1
o title="title1"
, el valor del atributo DOM "title" es simplemente la cadena title1
. Si usa title="{{title}}"
, el valor del atributo DOM "title" es el valor interpolado de {{title}}
, por lo tanto, la cadena será la propiedad de alcance principal "title" actualmente establecida. Dado que los valores de atributo son siempre cadenas, siempre terminará con un valor de cadena para esta propiedad en el ámbito de la directiva cuando use @ .
= une una propiedad de ámbito local / directiva a una propiedad de ámbito principal . Así que con = , usted usa el nombre de la propiedad del modelo / ámbito principal como el valor del atributo DOM. No puedes usar {{}}
s con = .
Con @, puedes hacer cosas como title="{{title}} and then some"
se interpola un title="{{title}} and then some"
- {{title}}, luego la cadena "and them some" se concatena con él. La cadena concatenada final es lo que obtiene la propiedad de ámbito local / directiva. (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 espera. Tenga en cuenta que esto significa que solo puede acceder a este atributo de asynchronously . No necesita usar $ observe () si solo está usando el valor en una plantilla. Por ejemplo, template: ''<div>{{title}}</div>''
.
Con = , no necesitas usar $ observar.
¿También puedo acceder directamente al ámbito principal, sin decorar mi elemento con un atributo?
Sí, pero solo si no utiliza un alcance aislado. Elimina esta línea de tu directiva
scope: { ... }
y entonces su directiva no creará un nuevo alcance. Utilizará el ámbito padre. A continuación, puede acceder directamente a todas las propiedades del ámbito principal.
La documentación dice: "A menudo es deseable pasar datos del ámbito aislado a través de una expresión y al ámbito principal", pero parece que también funciona bien con el enlace bidireccional. ¿Por qué sería mejor la ruta de expresión?
Sí, el enlace bidireccional permite que el ámbito local / directivo y el ámbito primario compartan datos. "Enlace de expresión" permite a la directiva llamar a 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 ámbito principal, puede usar la sintaxis & .
Ver también
- Publicación de blog de alcance aislado de Lukas (covers @, =, &)
- La explicación de dnc253 de @ y =
- Mi respuesta tipo blog sobre los ámbitos: la sección de directivas (en la parte inferior, justo antes de la sección Resumen) tiene una imagen de un ámbito aislado y su ámbito primario: el ámbito de la directiva usa @ para una propiedad y = para otra
- ¿Cuál es la diferencia entre & vs @ y = en angularJS
He leído cuidadosamente la documentación de AngularJS sobre el tema, y luego jugué con una directiva. Aquí está el fiddle .
Y aquí hay algunos fragmentos relevantes:
Desde el HTML:
<pane bi-title="title" title="{{title}}">{{text}}</pane>
Desde la directiva del panel:
scope: { biTitle: ''='', title: ''@'', bar: ''='' },
Hay varias cosas que no entiendo
- ¿Por qué tengo que usar
"{{title}}"
con''@''
y"title"
con''=''
? - ¿También puedo acceder directamente al ámbito principal, sin decorar mi elemento con un atributo?
- La documentación dice: "A menudo es deseable pasar datos del ámbito aislado a través de una expresión y al ámbito principal" , pero parece que también funciona bien con el enlace bidireccional. ¿Por qué sería mejor la ruta de expresión?
Encontré otro violín que también muestra la solución de expresión: http://jsfiddle.net/maxisam/QrCXh/
¿Por qué tengo que usar "{{title}}" con ''@'' y "title" con ''=''?
Cuando usa {{título}}, solo el valor del ámbito principal se pasará a la vista de directiva y se evaluará. Esto se limita a una forma, lo que significa que el cambio no se reflejará en el ámbito principal. Puede usar ''='' cuando desee reflejar los cambios realizados en la directiva secundaria al ámbito principal también. Esto es de dos maneras.
¿También puedo acceder directamente al ámbito principal, sin decorar mi elemento con un atributo?
Cuando la directiva tiene un atributo de ámbito (alcance: {}), ya no podrá acceder directamente al ámbito principal. Pero aún es posible acceder a él a través de scope. $ Parent, etc. Si elimina el alcance de la directiva, puede acceder a él directamente.
La documentación dice: "A menudo es deseable pasar datos del ámbito aislado a través de una expresión y al ámbito principal", pero parece que también funciona bien con el enlace bidireccional. ¿Por qué sería mejor la ruta de expresión?
Depende en función del contexto. Si desea llamar a una expresión o función con datos, use & y si quiere compartir datos, puede usar la forma biderectional usando ''=''
Puede encontrar las diferencias entre varias 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
@ Enlace de cadena de atributo (una vía) = Enlace de modelo bidireccional y enlace de método de devolución de llamada
@ enlaza una propiedad de ámbito local / directiva al valor evaluado del atributo DOM. = une una propiedad de ámbito local / directiva a una propiedad de ámbito principal. & binding es para pasar un método al ámbito de su directiva para que pueda ser llamado dentro de su directiva.
@ Enlace de cadena de atributo = Enlace de modelo bidireccional y enlace de método de devolución de llamada
Aquí hay muchas respuestas geniales, pero me gustaría ofrecer mi perspectiva sobre las diferencias entre @
, =
y &
binding que me resultaron útiles.
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:
@ vinculante es para pasar cadenas. Estas cadenas admiten
{{}}
expresiones para valores interpolados. Por ejemplo: . La expresión interpolada se evalúa contra el alcance principal de la directiva.= enlace es para enlace de modelo de dos vías. El modelo en el ámbito principal está vinculado al modelo en el ámbito aislado de la directiva. Los cambios en un modelo afectan al otro, y viceversa.
& binding es para pasar un método al ámbito de su directiva para que pueda ser llamado dentro de su directiva. El método está previamente vinculado al ámbito principal de la directiva y admite argumentos. Por ejemplo, si el método es hola (nombre) en el ámbito principal, para ejecutar el método desde su directiva, debe llamar a $ scope.hello ({name: ''world''})
Encuentro que es más fácil recordar estas diferencias al referirse a los enlaces de alcance mediante una descripción más corta:
-
@
Enlace de cadena de atributo -
=
Enlace de modelo de dos vías -
&
enlace de método de devolución de llamada
Los símbolos también aclaran qué representa la variable de alcance dentro de la implementación de su directiva:
-
@
cadena -
=
modelo -
&
método
En orden de utilidad (para mí de todos modos):
- =
- @
- Y
Creé un pequeño archivo HTML que contiene código angular que demuestra las diferencias entre ellos:
<!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>
El =
significa vinculación bidireccional, por lo que es una referencia a una variable para el ámbito principal. Esto significa que, cuando cambie la variable en la directiva, también se cambiará en el ámbito principal.
@
significa que la variable se copiará (clonará) en la directiva.
Por lo que sé, <pane bi-title="{{title}}" title="{{title}}">{{text}}</pane>
debería funcionar. 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 principal, puede ejecutar una función en el ámbito principal desde dentro de la directiva (o pasar datos a través de un servicio).
Hay tres maneras en que se puede agregar el alcance en la directiva:
- Ámbito principal : esta es la herencia del ámbito predeterminado.
El alcance de la directiva y su principal (controlador / directiva en el que se encuentra) es el mismo. Por lo tanto, cualquier cambio realizado en las variables de alcance dentro de la directiva también se refleja en el controlador principal. No es necesario especificar esto, ya que es el valor predeterminado.
- Ámbito secundario: la directiva crea un ámbito secundario que se hereda del ámbito principal si especifica la variable de ámbito de la directiva como verdadera.
Aquí, si cambia las variables de alcance dentro de la directiva, no se reflejará en el alcance principal, pero si cambia la propiedad de una variable de alcance, eso se refleja en el alcance principal, ya que en realidad modificó la variable de alcance de la variable principal. .
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.
}
};
});
- Ámbito aislado : se utiliza cuando desea crear el ámbito que no se hereda del ámbito del controlador.
Esto sucede cuando crea complementos, ya que esto hace que la directiva sea genérica, ya que se puede colocar en cualquier HTML y no se ve afectada por su alcance principal.
Ahora, si no desea ninguna interacción con el ámbito principal, puede especificar el ámbito 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 ámbito principal, por lo que queremos que algunos de los valores / cambios se transfieran. 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 alcance del controlador se reflejarán en el ámbito de la directiva, pero si modifica el valor en el alcance de la directiva, la variable del alcance 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 ámbito de la directiva, la variable de alcance del controlador también se verá afectada
& se utiliza para enlazar el método de alcance 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 en el ámbito de la directiva.
Por ejemplo, el ámbito de la directiva tiene una variable "dirVar" que se sincroniza con la variable "contVar" del ámbito del controlador. Esto le da mucha potencia y generalización a la directiva ya que un controlador puede sincronizarse con la variable v1 mientras que otro controlador que usa la misma directiva puede pedirle a dirVar que 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 (note la diferencia para @ y =):
<div my-directive
class="directive"
name="{{name}}"
reverse="reverseName()"
color="color" >
</div>
Aquí hay un link al blog que lo describe muy bien.
Implementé todas las opciones posibles en un violín.
Se ocupa de todas las opciones:
scope:{
name:''&''
},
scope:{
name:''=''
},
scope:{
name:''@''
},
scope:{
},
scope:true,
Incluso cuando el alcance es local, como en su ejemplo, puede acceder al alcance principal a través de la propiedad $parent
. Supongamos que en el código siguiente, ese title
se define en el ámbito 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 alcance aislado a través de una expresión y al alcance principal", fue útil (y no se pudo usar un enlace de datos bidireccional) en una directiva para renderizar una estructura de datos especial dentro de una repetición ng.
<render data = "record" deleteFunction = "dataList.splice($index,1)" ng-repeat = "record in dataList" > </render>
Una parte de la representación fue un botón de eliminación y aquí fue útil adjuntar una función de eliminación desde el ámbito externo a través de &. Dentro de la directiva de render parece
scope : { data = "=", deleteFunction = "&"},
template : "... <button ng-click = "deleteFunction()"></button>"
El enlace de data = "="
bidireccional, es decir, los data = "="
no se pueden usar, ya que la función de eliminación se ejecutaría en cada ciclo de $digest
, lo que no es bueno, ya que el registro se elimina inmediatamente y nunca se procesa.
La forma = es enlace de 2 vías , que le permite tener cambios en vivo dentro de su directiva. Cuando alguien cambia esa variable fuera de la directiva, tendrá los datos modificados dentro de su directiva, pero @ way no es vinculante de dos maneras . Funciona como texto . Se unen una vez, y solo tendrá su valor.
Para obtener más claramente, puede utilizar este gran artículo:
Ámbito de aplicación de la directiva AngularJS ''@'' y ''=''
La principal diferencia entre ellos es solo
@ Attribute string binding
= Two-way model binding
& Callback method binding
Si desea ver más sobre 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: "<div><p>{{title1}} {{title2}}</p></div>"
};
});
Simplemente podemos usar: -
@ : - para valores de cadena para enlace de datos de una vía. de una manera, el enlace de datos solo puede pasar el valor del alcance a la directiva
= : - para valor de objeto para enlace de datos de dos vías. En el enlace de datos bidireccional puede cambiar el valor del alcance en la directiva, así como también en html.
& : - para metodos y funciones.
EDITAR
En nuestra definición de componente para la versión angular 1.5 y superior
Hay cuatro tipos diferentes de enlaces:
-
=
Enlace de datos bidireccional : - si cambiamos el valor, se actualizará automáticamente <
enlace de una forma : - cuando solo queremos leer un parámetro de un ámbito primario y no actualizarlo.@
Esto es para Parámetros de Cadena&
esto es para devoluciones de llamada en caso de que su componente necesite generar algo para su ámbito principal
@
obtener como cadena
- Esto no crea ningún tipo de enlaces. Simplemente estás recibiendo la palabra que pasaste como una cadena
=
2 vías
- Los cambios realizados desde el controlador se reflejarán en la referencia contenida en la directiva, y viceversa.
&
Esto se comporta de forma un poco diferente, porque el ámbito obtiene una función que devuelve el objeto que se pasó . Supongo que esto fue necesario para que funcione. El violín debe dejar esto claro.
- 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 debe demostrar cómo funcionan . Preste especial atención a las funciones de alcance con get...
en el nombre para, con suerte, comprender mejor a qué me refiero con &
@
y =
ver otras respuestas.
Uno tiene ganas de &
TL; DR;
&
obtiene la expresión (no solo la función como en los ejemplos en otras respuestas) de un padre, y la 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, al pasar un objeto con las variables.
explicado
&
es una referencia de expresión, eso significa que si pasas algo como <myDirective expr="x==y"></myDirective>
en la directiva, esta expr
será una función, que llama a la expresión, como:
function expr(){return x == y}
.
por lo tanto, en la directiva html <button ng-click="expr()"></button>
llamará la expresión. En js de la directiva, solo $scope.expr()
llamará la expresión también.
La expresión se llamará con $ scope.x y $ scope.y del padre.
Tienes la capacidad de anular los parámetros!
Si los configura por llamada, por ejemplo, <button ng-click="expr({x:5})"></button>
entonces se llamará a la expresión con su parámetro x
y el parámetro del padre y
.
Puede anular ambos.
Ahora sabes, por qué <button ng-click="functionFromParent({x:5})"></button>
funciona.
Porque solo llama a la expresión padre (por ejemplo, <myDirective functionFromParent="function1(x)"></myDirective>
) y reemplaza los valores posibles con sus parámetros especificados, en este caso x
.
podría ser:
<myDirective functionFromParent="function1(x) + 5"></myDirective>
o
<myDirective functionFromParent="function1(x) + z"></myDirective>
con llamada infantil:
<button ng-click="functionFromParent({x:5, z: 4})"></button>
.
o incluso con la función de reemplazo:
<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button>
.
es solo una expresión, no importa si es una función, o muchas funciones, o solo comparación. Y puedes reemplazar cualquier variable de esta expresión.
Ejemplos:
plantilla directiva vs código llamado:
padre ha definido $ scope.x, $ scope.y:
plantilla principal: <myDirective expr="x==y"></myDirective>
<button ng-click="expr()"></button>
llama a $scope.x==$scope.y
<button ng-click="expr({x: 5})"></button>
llama 5 == $scope.y
<button ng-click="expr({x:5, y:6})"></button>
llamadas 5 == 6
padre ha definido $ scope.function1, $ scope.x, $ scope.y:
plantilla principal: <myDirective expr="function1(x) + y"></myDirective>
<button ng-click="expr()"></button>
llama a $scope.function1($scope.x) + $scope.y
<button ng-click="expr({x: 5})"></button>
llama a $scope.function1(5) + $scope.y
<button ng-click="expr({x:5, y:6})"></button>
llama a $scope.function1(5) + 6
La directiva tiene $ scope.myFn como función:
<button ng-click="expr({function1: myFn, x:5, y:6})"></button>
llama a $scope.myFn(5) + 6
La propiedad @ local scope se usa para acceder a valores de cadena que están definidos fuera de la directiva.
= En los casos en que necesite crear un enlace bidireccional entre el ámbito externo y el ámbito de aislamiento de la directiva, puede usar el carácter =.
La propiedad & local scope permite al consumidor de una directiva pasar a una función que la directiva puede invocar.
Por favor, consulte el siguiente enlace que le proporciona una comprensión clara con ejemplos. Me pareció muy útil, así que pensé en compartirlo.
http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-2-isolate-scope