Confuso sobre Angularjs transcluído e isolar escopos e ligações

Eu estou lutando para entender o escopo dos modelos e suas ligações em relação às diretivas que têm escopo limitado.

Eu entendo que restringir o escopo em uma diretiva significa que o controlador. $ Scope e directive.scope não são mais a mesma coisa. No entanto, estou confuso sobre como a colocação de modelos no modelo de diretiva ou no html afeta a vinculação de dados. Sinto que estou sentindo falta de algo muito fundamental e, para seguir em frente, preciso entender isso.

Pegue o seguinte código (violino aqui: http://jsfiddle.net/2ams6/ )

JavaScript

var app = angular.module('app',[]); app.controller('Ctrl',function($scope){ }); app.directive('testel', function(){ return { restrict: 'E', scope: { title: '@' }, transclude: true, template: '
'+ '

Template title: {{title}}

' + '

Template data.title:{{data.title}}

' + '
' } });

HTML

 

Transclude title:{{title}}

Transclude data.title:{{data.title}}

O modelo atualiza apenas {{title}} dentro do modelo e {{data.title}} na transclusão. Por que não {{title}} na transclusão nem {{data.title}} no modelo?

Movendo a input para dentro da transclusão (fiddle aqui: http://jsfiddle.net/eV8q8/1/ ):

 

Transclude title: {{title}}

Transclude data.title: {{data.title}}

agora significa apenas transclude {{data:title}} é atualizado. Por que não o modelo {{title}} ou {{data.title}} , nem transclude {{title}} ?

E finalmente, movendo a input para dentro do template, assim (mexer aqui: http://jsfiddle.net/4ngmf/2/ ):

 template: '
' + '' + '

Template title: {{title}}

' + '

Template data.title: {{data.title}}

' + '
'

Agora, significa que apenas o modelo {{data.title}} é atualizado. Novamente, por que não as outras 3 ligações?

Espero que haja algo óbvio me encarando no rosto e eu estou sentindo falta dele. Se você me pegar para comprar isso, eu te compro uma cerveja, ou dou alguns pontos, ou algo assim. Muito Obrigado.

Seus violinos criam três escopos:

  1. um escopo associado ao controlador Ctrl , por causa do ng-controller
  2. uma diretriz transcluída, devido à transclude: true
  3. uma diretiva isolar escopo, por causa do scope: { ... }

Em fiddle1, antes de digitarmos qualquer coisa na checkbox de texto, temos o seguinte:

insira a descrição da imagem aqui

O escopo 003 é o escopo associado ao controlador. Como ainda não digitamos na checkbox de texto, não há propriedade de data . No escopo isolado 004, vemos que uma propriedade de title foi criada, mas está vazia. Está vazio porque o escopo pai ainda não possui uma propriedade data.title .

Depois de digitar my title na checkbox de texto, agora temos:

insira a descrição da imagem aqui

O escopo do controlador 003 agora tem uma nova propriedade de object de data (é por isso que é amarelo), que tem uma propriedade de title agora definida como my title . Como isolar o title propriedade do escopo é uma binding de dados unidirecional para o valor interpolado de data.title , ele também obtém o valor my title (o valor é colorido em amarelo porque mudou).

O escopo transcludido herda prototipicamente do escopo do controlador, portanto, dentro do HTML transcluído, o angular pode seguir a cadeia de protótipos e encontrar $scope.data.title no escopo pai (mas $scope.title não existe lá).

O escopo isolado tem access apenas às suas próprias propriedades, portanto, apenas o title propriedade.

Em fiddle2, antes de digitar, temos a mesma imagem que em fiddle1.

Depois de digitar my title :

insira a descrição da imagem aqui

Observe onde a nova propriedade data.title apareceu – no escopo transcluído. O escopo isolado ainda está procurando por data.title no escopo do controlador, mas não está presente desta vez, portanto, seu valor de propriedade de title permanece vazio.

Em fiddle3, antes de digitar temos a mesma imagem que em fiddle1.

Depois de digitar my title :

insira a descrição da imagem aqui

Observe onde a nova propriedade data.title apareceu – no escopo isolate. Nenhum dos outros escopos tem access ao escopo isolado, então a string my title não aparecerá em nenhum outro lugar.


Atualização para o Angular v1.2:

Com a mudança eed299a o Angular agora limpa o ponto de transclusão antes da transclusão, então as partes Template title: ... e Template data.title: ... não aparecerão a menos que você modifique o template de tal forma que ng-transclude seja por si só, Como:

 '

Template title: {{title}}

' + '

Template data.title: {{data.title}}

' + '
'

Na atualização abaixo para o Angular v1.3, essa alteração de modelo foi feita.


Atualização para o Angular v1.3 +:

Desde a versão v1.3 da Angular, o escopo transcluído agora é um filho do escopo isolado da diretiva, em vez de um filho do escopo do controlador. Então, no fiddle1, antes de digitarmos alguma coisa:

insira a descrição da imagem aqui

As imagens nesta atualização são desenhadas com a ferramenta de escopo Peri $ , então as imagens são um pouco diferentes. O @ indica que temos uma propriedade de escopo isolate que usa a syntax @ , e o fundo rosa significa que a ferramenta não conseguiu encontrar uma referência de ancestral para o mapeamento (o que é verdade, já que não digitamos nada na checkbox de texto ainda ).

Depois de digitar my title na checkbox de texto, agora temos:

insira a descrição da imagem aqui

As propriedades isoladas que usam @ binding sempre mostrarão o resultado da string interpolada no escopo isolado após o símbolo @ . O escopo Peri $ também foi capaz de encontrar esse valor de string exato em um escopo ancestral, portanto, ele também mostra uma referência a essa propriedade.

No violino 2, antes de digitar temos a mesma imagem que no fiddle1.

Depois de digitar my title :

insira a descrição da imagem aqui

Observe onde a nova propriedade data.title apareceu – no escopo transcluído. O escopo isolado ainda está procurando por data.title no escopo do controlador, mas não está presente desta vez, portanto, seu valor de propriedade de title permanece vazio.

Em fiddle3, antes de digitar temos a mesma imagem que em fiddle1.

Depois de digitar my title :

insira a descrição da imagem aqui

Observe onde a nova propriedade data.title apareceu – no escopo isolate. Mesmo que o escopo transcluído tenha access ao escopo do isolado por meio do relacionamento $parent , ele não procurará por title ou data.title – ele só procurará no escopo do controlador (isto é, seguirá a inheritance prototypal), e o escopo do controlador não tem essas propriedades definidas.

Depois de ler todas as respostas apresentadas, incluindo os fantásticos esquemas de Mark, este é o meu entendimento do escopo e sua inheritance por minha pergunta. Gostaria de receber comentários sobre onde esse diagrama cai, para que eu possa atualizar adequadamente. Espero que simplesmente forneça uma visão diferente do que Marcos apresentou:

Herança de escopo

Bem perguntado, btw! Espero que minha resposta seja tão eloquente ..

A resposta tem a ver com a forma como os elementos transcluídos obtêm seu escopo.

Para resumir, você tem dois escopos:

  1. O escopo do controlador, que tem $scope.data.title . (Implicitamente adicionado pelo seu elemento de input )
  2. O escopo da diretiva, que tem $scope.title .

Quando você altera o $scope.data.title do controlador, o $scope.data.title diretiva também muda.

Você também tem duas seções de HTML, o transcluído e o modelo. O que está acontecendo é que o HTML transcluído está no escopo do controlador e o HTML do modelo está no escopo da diretiva . Portanto, o HTML transcluído não sabe nada sobre title e o escopo do modelo não sabe nada sobre data.title

Isso é exatamente o que a Transclusion foi destinada – para permitir que elementos filho de uma diretiva mantenham seu escopo pai , neste caso o escopo do controlador. Por design, elementos transcluídos não sabem que estão em uma diretiva e, portanto, não têm access ao escopo da diretiva.

Os modelos de diretivas, por outro lado, terão access apenas ao escopo da diretiva.

Eu mudei seu código um pouco para tornar os nomes um pouco mais claros (a mesma funcionalidade, no entanto)

http://jsfiddle.net/yWWVs/2/