Qual é a diferença entre ‘@’ e ‘=’ no escopo da diretiva no AngularJS?

Eu li atentamente a documentação do AngularJS sobre o tópico e, em seguida, procurei uma diretiva. Aqui está o violino .

E aqui estão alguns trechos relevantes:

  • Do HTML:

    {{text}} 
  • Da diretiva do painel:

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

Existem várias coisas que não entendo:

  • Por que preciso usar "{{title}}" com '@' e "title" com '=' ?
  • Também posso acessar o escopo pai diretamente, sem decorar meu elemento com um atributo?
  • A documentação diz “Muitas vezes é desejável passar dados do escopo isolado por meio de uma expressão e para o escopo pai” , mas isso parece funcionar bem com a vinculação bidirecional também. Por que a rota da expressão seria melhor?

Eu encontrei outro violino que mostra a solução de expressão também: http://jsfiddle.net/maxisam/QrCXh/

Por que preciso usar “{{title}}” com ” @ ” e “title” com ” = “?

@ liga uma propriedade de escopo local / diretiva ao valor avaliado do atributo DOM . Se você usar title=title1 ou title="title1" , o valor do atributo DOM “title” é simplesmente a string title1 . Se você usar title="{{title}}" , o valor do atributo DOM “title” é o valor interpolado de {{title}} , portanto, a string será qualquer propriedade de escopo pai “title” atualmente definida como. Como os valores dos atributos são sempre strings, você sempre terminará com um valor de string para essa propriedade no escopo da diretiva ao usar @ .

= liga uma propriedade de escopo local / diretiva a uma propriedade de escopo pai . Portanto, com = , você usa o nome da propriedade do modelo / escopo pai como o valor do atributo DOM. Você não pode usar {{}} s com = .

Com @, você pode fazer coisas como title="{{title}} and then some" – {{title}} são interpoladas, então a string “e algumas delas” é concatenada com ele. A cadeia final concatenada é o que a propriedade do escopo local / diretivo obtém. (Você não pode fazer isso com = , apenas @ .)

Com @ , você precisará usar attr.$observe('title', function(value) { ... }) se você precisar usar o valor em sua function de link (ing). Por exemplo, if(scope.title == "...") não funcionar como você espera. Observe que isso significa que você só pode acessar esse atributo de forma assíncrona . Você não precisa usar $ observe () se estiver usando apenas o valor em um modelo. Por exemplo, template: '

{{title}}

' .

Com = , você não precisa usar $ observe.

Também posso acessar o escopo pai diretamente, sem decorar meu elemento com um atributo?

Sim, mas apenas se você não usar um escopo isolado. Remova esta linha da sua diretiva

scope: { ... }

e, em seguida, sua diretiva não criará um novo escopo. Ele usará o escopo pai. Você pode acessar todas as propriedades do escopo pai diretamente.

A documentação diz “Muitas vezes é desejável passar dados do escopo isolado por meio de uma expressão e para o escopo pai”, mas isso parece funcionar bem com a vinculação bidirecional também. Por que a rota da expressão seria melhor?

Sim, a binding bidirecional permite que o escopo local / diretivo e o escopo pai compartilhem dados. “Expression binding” permite que a diretiva chame uma expressão (ou function) definida por um atributo DOM – e você também pode passar dados como argumentos para a expressão ou function. Então, se você não precisa compartilhar dados com o pai – você só quer chamar uma function definida no escopo pai – você pode usar a syntax.

Veja também

  • O post do blog de escopo isolado de Lukas (covers @, =, &)
  • Explicação do dnc253 de @ e =
  • minha resposta semelhante a um blog sobre escopos – a seção diretivas (na parte inferior, logo antes da seção Resumo) tem uma imagem de um escopo isolado e seu escopo pai – o escopo da diretiva usa @ para uma propriedade e = para outra
  • Qual é a diferença entre & vs @ e = em angularJS?

Há muitas ótimas respostas aqui, mas gostaria de oferecer minha perspectiva sobre as diferenças entre @ , = e & binding que se mostraram úteis para mim.

Todas as três ligações são formas de passar dados de seu escopo pai para o escopo isolado de sua diretiva por meio dos atributos do elemento:

  1. @ binding é para passar strings. Essas cadeias suportam expressões {{}} para valores interpolados. Por exemplo: . A expressão interpolada é avaliada em relação ao escopo pai da diretiva.

  2. = binding é para binding de modelo bidirecional. O modelo no escopo pai é vinculado ao modelo no escopo isolado da diretiva. Mudanças em um modelo afetam o outro e vice-versa.

  3. & binding é para passar um método para o escopo da sua diretiva para que ele possa ser chamado dentro da sua diretiva. O método é pré-vinculado ao escopo pai da diretiva e suporta argumentos. Por exemplo, se o método é olá (nome) no escopo pai, então para executar o método de dentro da sua diretiva, você deve chamar $ scope.hello ({name: ‘world’})

Eu acho que é mais fácil lembrar dessas diferenças referindo-se às ligações de escopo por uma descrição mais curta:

  • @ Ligação de cadeia de atributos
  • = Ligação de modelo bidirecional
  • Ligação ao método de retorno de chamada

Os símbolos também tornam mais claro o que a variável de escopo representa dentro da implementação da sua diretiva:

  • @ string
  • = model
  • & método

Em ordem de utilidade (para mim de qualquer maneira):

  1. =
  2. @
  3. E

O = significa binding bidirecional, portanto, uma referência a uma variável para o escopo pai. Isso significa que, quando você altera a variável na diretiva, ela também será alterada no escopo pai.

@ significa que a variável será copiada (clonada) para a diretiva.

Tanto quanto eu sei, {{text}} deve funcionar também. bi-title receberá o valor da variável do escopo pai, que pode ser alterado na diretiva.

Se você precisar alterar várias variables ​​no escopo pai, poderá executar uma function no escopo pai a partir da diretiva (ou passar dados por meio de um serviço).

Se você gostaria de ver mais como isso funciona com um exemplo ao 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}}

" }; });

@ get as string

  • Isso não cria nenhuma binding. Você está simplesmente recebendo a palavra que você passou como uma string

= Ligação de 2 vias

  • As alterações efectuadas a partir do controlador serão reflectidas na referência da directiva e vice-versa.

& Isso se comporta de maneira um pouco diferente, porque o escopo obtém uma function que retorna o object que foi passado . Estou assumindo que isso era necessário para que funcionasse. O violino deve deixar isso claro.

  • Depois de chamar essa function getter, o object resultante se comporta da seguinte maneira:
    • se uma function foi passada: então a function é executada no fechamento pai (controlador) quando chamado
    • se uma não function foi passada: simplesmente obtenha uma cópia local do object que não possui ligações

Este violino deve demonstrar como eles funcionam . Preste atenção especial às funções de escopo com get... no nome para entender melhor o que quero dizer sobre &

Existem três maneiras de o escopo ser adicionado na diretiva:

  1. Escopo pai : esta é a inheritance de escopo padrão.

A diretiva e seu escopo pai (controlador / diretiva dentro do qual ela se encontra) são os mesmos. Assim, quaisquer alterações feitas nas variables ​​de escopo dentro da diretiva são refletidas no controlador pai também. Você não precisa especificar isso, pois é o padrão.

  1. Escopo filho : diretiva cria um escopo filho que herda do escopo pai se você especificar a variável de escopo da diretiva como verdadeira.

Aqui, se você alterar as variables ​​de escopo dentro da diretiva, ele não será refletido no escopo pai, mas se você alterar a propriedade de uma variável de escopo, isso é refletido no escopo pai, como você realmente modificou a variável de escopo do pai .

Exemplo,

 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. Escopo isolado : é usado quando você deseja criar o escopo que não herda do escopo do controlador.

Isso acontece quando você está criando plugins, pois isso torna a diretiva genérica, já que ela pode ser colocada em qualquer HTML e não é afetada por seu escopo pai.

Agora, se você não quiser nenhuma interação com o escopo pai, poderá simplesmente especificar o escopo como um object vazio. gostar,

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

Principalmente, este não é o caso, pois precisamos de alguma interação com o escopo pai, então queremos que alguns dos valores / mudanças passem. Por esse motivo, usamos:

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

@ significa que as alterações do escopo do controlador serão refletidas no escopo da diretiva, mas se você modificar o valor no escopo da diretiva, a variável de escopo do controlador não será afetada.

@ sempre espera que o atributo mapeado seja uma expressão. Isto é muito importante; porque para fazer o prefixo “@” funcionar, precisamos envolver o valor do atributo dentro de {{}}.

= é bidirecional, portanto, se você alterar a variável no escopo da diretiva, a variável de escopo do controlador também será afetada

& é usado para ligar o método do escopo do controlador, de modo que, se necessário, podemos chamá-lo da diretiva

A vantagem aqui é que o nome da variável não precisa ser o mesmo no escopo do controlador e no escopo da diretiva.

Exemplo, o escopo da diretiva tem uma variável “dirVar” que sincroniza com a variável “contVar” do escopo do controlador. Isso dá muita potência e generalização à diretiva, já que um controlador pode sincronizar com a variável v1, enquanto outro controlador, usando a mesma diretiva, pode pedir ao dirVar para sincronizar com a variável v2.

Abaixo está o exemplo de uso:

A diretiva e o controlador são:

  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 o html (note a diferença para @ e =):

 

Aqui está um link para o blog que descreve bem.

Simplesmente podemos usar: –

  1. @ : – para valores de string para binding de dados unidirecional. de uma maneira, a binding de dados só pode passar o valor do escopo para a diretiva

  2. = : – para o valor do object para binding de dados bidirecional. na binding de dados bidirecional você pode alterar o valor do escopo na diretiva, bem como no html também.

  3. & : – para methods e funções.

EDITAR

Na nossa definição de componente para Angular versão 1.5 e acima
Existem quatro tipos diferentes de ligações:

  1. = Ligação de dados bidirecional : – se alterarmos o valor, ele será atualizado automaticamente
  2. < binding unidirecional : - quando apenas queremos ler um parâmetro de um escopo pai e não atualizá-lo.

  3. @ isto é para os parâmetros de string

  4. & isto é para Callbacks no caso de seu componente precisar gerar algo para seu escopo pai

Eu criei um pequeno arquivo HTML que contém código angular demonstrando as diferenças entre eles:

 < !DOCTYPE html>   Angular        

O caminho = é de 2 vias , o que permite que você tenha alterações ao vivo dentro de sua diretiva. Quando alguém altera essa variável para fora da diretiva, você terá esses dados alterados dentro de sua diretiva, mas o @way não é vinculação de duas vias . Funciona como texto . Você liga uma vez e só terá seu valor.

Para obter mais clareza, você pode usar este ótimo artigo:

Âmbito da Directiva AngularJS ‘@’ e ‘=’

@ propriedade de escopo local é usada para acessar valores de string definidos fora da diretiva.

= Nos casos em que você precisa criar uma binding bidirecional entre o escopo externo e o escopo isolado da diretiva, você pode usar o caractere =.

A propriedade de escopo local permite que o consumidor de uma diretiva passe uma function que a diretiva pode invocar.

Por favor, verifique o link abaixo, que lhe dá uma compreensão clara com exemplos.Eu achei muito útil, então pensei em compartilhá-lo.

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

Eu implementei todas as opções possíveis em um violino.

Ele lida com todas as opções:

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

https://jsfiddle.net/rishulmatta/v7xf2ujm

Mesmo quando o escopo é local, como no seu exemplo, você pode acessar o escopo pai através da propriedade $parent . Assuma no código abaixo, esse title é definido no escopo pai. Você pode então acessar o título como $parent.title :

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

No entanto, na maioria dos casos, o mesmo efeito é melhor obtido usando atributos.

Um exemplo de onde encontrei a notação “&”, que é usada “para passar dados do escopo isolado por meio de uma expressão e para o escopo pai”, útil (e uma binding de dados bidirecional não pôde ser usada) estava em uma diretiva para renderizar uma estrutura de dados especial dentro de um ng-repeat.

   

Uma parte da renderização foi um botão delete e aqui foi útil append uma deletetion do escopo externo via &. Dentro da diretiva de renderização, parece

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

Ligação de data = "=" bidirecional, ou seja, data = "=" não pode ser usada, já que a function delete é executada em todo ciclo $digest , o que não é bom, pois o registro é imediatamente excluído e nunca renderizado.

@ e = veja outras respostas.

Um gotcha sobre &
TL; DR;
& Obtém expressão (não apenas funciona como nos exemplos em outras respostas) de um pai, e define como uma function na diretiva, que chama a expressão. E essa function tem a capacidade de replace qualquer variável (até nome da function) da expressão, passando um object com as variables.

explicado
& é uma referência de expressão, isso significa que se você passar algo como
na directiva esta expr será uma function, que chama a expressão, como:
function expr(){return x == y} .
então, no html da diretiva chamará a expressão. Em js da diretiva apenas $scope.expr() chamará a expressão também.
A expressão será chamada com $ scope.x e $ scope.y do pai.
Você tem a capacidade de replace os parâmetros!
Se você configurá-los por chamada, por exemplo,
então a expressão será chamada com o seu parâmetro x e o parâmetro do pai y .
Você pode replace os dois.
Agora você sabe, porque funciona.
Porque ele apenas chama a expressão de pai (por exemplo, ) e substitui os valores possíveis pelos parâmetros especificados, neste caso, x .
Poderia ser:

ou

com chamada de criança:
.
ou até mesmo com substituição de function:
.

é apenas uma expressão, não importa se é uma function, ou muitas funções, ou apenas comparação. E você pode replace qualquer variável dessa expressão.

Exemplos:
modelo de diretiva vs código chamado:
pai definiu $ scope.x, $ scope.y:
modelo pai:
chama $scope.x==$scope.y
chama 5 == $scope.y
chama 5 == 6

pai definiu $ scope.function1, $ scope.x, $ scope.y:
modelo pai:

chama $scope.function1($scope.x) + $scope.y
chama $scope.function1(5) + $scope.y
chama $scope.function1(5) + 6
A diretiva tem $ scope.myFn como function:
chama $scope.myFn(5) + 6

a principal diferença entre eles é apenas

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

Por que preciso usar “{{title}}” com “@” e “title” com “=”?

Quando você usa {{title}}, somente o valor do escopo pai será passado para a visualização diretiva e avaliado. Isso é limitado a um caminho, o que significa que a mudança não será refletida no escopo pai. Você pode usar ‘=’ quando quiser também refletir as alterações feitas na diretiva child para o escopo pai. Isso é de dois modos.

Também posso acessar o escopo pai diretamente, sem decorar meu elemento com um atributo?

Quando a diretiva possui um atributo scope (escopo: {}), você não poderá mais acessar o escopo pai diretamente. Mas ainda é possível acessá-lo via escopo. $ Pai etc. Se você remover o escopo da diretiva, ele pode ser acessado diretamente.

A documentação diz “Muitas vezes é desejável passar dados do escopo isolado por meio de uma expressão e para o escopo pai”, mas isso parece funcionar bem com a vinculação bidirecional também. Por que a rota da expressão seria melhor?

Depende com base no contexto. Se você quiser chamar uma expressão ou function com dados, você usa & e se você quiser compartilhar dados, você pode usar a maneira bidirecional usando ‘=’

Você pode encontrar as diferenças entre várias maneiras de passar dados para diretiva no link abaixo:

AngularJS – escopos isolados – @ vs = vs &

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

@ Vinculação de cadeia de atributos (unidirecional) = Vinculação de modelo bidirecional e vinculação de método de retorno de chamada

@ liga uma propriedade de escopo local / diretiva ao valor avaliado do atributo DOM. = liga uma propriedade de escopo local / diretiva a uma propriedade de escopo pai. & binding é para passar um método para o escopo da sua diretiva para que ele possa ser chamado dentro da sua diretiva.

@ Vinculação de cadeia de atributos = Ligação de modelo bidirecional e vinculação de método de retorno de chamada