Respostas:
@
permite que um valor definido no atributo de diretiva seja passado para o escopo isolado da diretiva. O valor pode ser uma string simples value ( myattr="hello"
) ou uma string interpolada AngularJS com expressões incorporadas ( myattr="my_{{helloText}}"
). Pense nisso como uma comunicação "unidirecional" do escopo pai para a diretiva filho. John Lindquist tem uma série de pequenos screencasts explicando cada um deles. O Screencast em @ está aqui: https://egghead.io/lessons/angularjs-isolate-scope-attribute-binding
&
permite que o escopo isolado da diretiva passe valores para o escopo pai para avaliação na expressão definida no atributo Observe que o atributo diretiva é implicitamente uma expressão e não usa a sintaxe da expressão de chave dupla. Este é mais difícil de explicar em texto. Screencast em & está aqui: https://egghead.io/lessons/angularjs-isolate-scope-expression-binding
=
configura uma expressão de ligação bidirecional entre o escopo isolado da diretiva e o escopo pai. Alterações no escopo filho são propagadas para o pai e vice-versa. Pense em = como uma combinação de @ e &. Screencast em = está aqui: https://egghead.io/lessons/angularjs-isolate-scope-two-way-binding
E, finalmente, aqui está um screencast que mostra os três usados juntos em uma única exibição: https://egghead.io/lessons/angularjs-isolate-scope-review
Eu gostaria de explicar os conceitos da perspectiva da herança do protótipo JavaScript. Espero ajudar a entender.
Existem três opções para definir o escopo de uma diretiva:
scope: false
: Padrão angular. O escopo da diretiva é exatamente o escopo pai ( parentScope
).scope: true
: Angular cria um escopo para esta diretiva. O escopo herda prototipicamente de parentScope
.scope: {...}
: escopo isolado é explicado abaixo. Especificar scope: {...}
define um isolatedScope
. Um isolatedScope
não herda propriedades de parentScope
, embora isolatedScope.$parent === parentScope
. É definido através de:
app.directive("myDirective", function() {
return {
scope: {
... // defining scope means that 'no inheritance from parent'.
},
}
})
isolatedScope
não tem acesso direto a parentScope
. Mas às vezes a diretiva precisa se comunicar com o parentScope
. Eles se comunicam através de @
, =
e &
. O tópico sobre o uso de símbolos @
, =
e &
estamos a falar de cenários usandoisolatedScope
.
Geralmente é usado para alguns componentes comuns compartilhados por páginas diferentes, como Modals. Um escopo isolado evita poluir o escopo global e é fácil de compartilhar entre as páginas.
Aqui está uma diretiva básica: http://jsfiddle.net/7t984sf9/5/ . Uma imagem para ilustrar é:
@
: ligação unidirecional@
simplesmente passa a propriedade de parentScope
para isolatedScope
. É chamado one-way binding
, o que significa que você não pode modificar o valor das parentScope
propriedades. Se você estiver familiarizado com a herança do JavaScript, poderá entender facilmente esses dois cenários:
Se a propriedade de ligação for um tipo primitivo, como interpolatedProp
no exemplo: você pode modificar interpolatedProp
, mas parentProp1
não seria alterado. No entanto, se você alterar o valor de parentProp1
, interpolatedProp
será substituído pelo novo valor (quando $ digest angular).
Se a propriedade de ligação for algum objeto, como parentObj
: como o que foi passado isolatedScope
é uma referência, a modificação do valor acionará este erro:
TypeError: Cannot assign to read only property 'x' of {"x":1,"y":2}
=
: ligação bidirecional=
é chamado two-way binding
, o que significa que qualquer modificação em childScope
também atualizará o valor em parentScope
e vice-versa. Esta regra funciona para primitivos e objetos. Se você alterar o tipo de ligação do parentObj
ser =
, você vai achar que você pode modificar o valor de parentObj.x
. Um exemplo típico é ngModel
.
&
: função de ligação&
permite que a diretiva chame alguma parentScope
função e transmita algum valor da diretiva. Por exemplo, verifique JSFiddle: & no escopo da diretiva .
Defina um modelo clicável na diretiva como:
<div ng-click="vm.onCheck({valueFromDirective: vm.value + ' is from the directive'})">
E use a diretiva como:
<div my-checkbox value="vm.myValue" on-check="vm.myFunction(valueFromDirective)"></div>
A variável valueFromDirective
é passada da diretiva para o controlador pai através de {valueFromDirective: ...
.
Referência: Compreendendo Escopos
Não é meu violino, mas http://jsfiddle.net/maxisam/QrCXh/ mostra a diferença. A peça principal é:
scope:{
/* NOTE: Normally I would set my attributes and bindings
to be the same name but I wanted to delineate between
parent and isolated scope. */
isolatedAttributeFoo:'@attributeFoo',
isolatedBindingFoo:'=bindingFoo',
isolatedExpressionFoo:'&'
}
@ : ligação unidirecional
= : ligação bidirecional
& : ligação de função
AngularJS - Escopos isolados - @ vs = vs &
Exemplos curtos com explicação estão disponíveis no link abaixo:
http://www.codeforeach.com/angularjs/angularjs-isolated-scopes-vs-vs
@ - ligação unidirecional
Na diretiva:
scope : { nameValue : "@name" }
Em vista:
<my-widget name="{{nameFromParentScope}}"></my-widget>
= - ligação em dois sentidos
Na diretiva:
scope : { nameValue : "=name" },
link : function(scope) {
scope.name = "Changing the value here will get reflected in parent scope value";
}
Em vista:
<my-widget name="{{nameFromParentScope}}"></my-widget>
& - Chamada de função
Na diretiva:
scope : { nameChange : "&" }
link : function(scope) {
scope.nameChange({newName:"NameFromIsolaltedScope"});
}
Em vista:
<my-widget nameChange="onNameChange(newName)"></my-widget>
Demorei muito tempo para realmente entender isso. A chave para mim foi entender que "@" é para coisas que você deseja avaliar in situ e passar para a diretiva como uma constante em que "=" realmente passa o objeto em si.
Há uma boa postagem de blog que explica isso em: http://blog.ramses.io/technical/AngularJS-the-difference-between-@-&-and-=-when-declaring-directives-using-isolate-scopes