Compreendendo a opção de transcluir de definição de diretiva?

195

Acho que este é um dos conceitos mais difíceis de entender com a diretiva do angularjs.

O documento de http://docs.angularjs.org/guide/directive diz:

transcluir - compila o conteúdo do elemento e o disponibiliza para a diretiva. Normalmente usado com ngTransclude. A vantagem da transclusão é que a função de ligação recebe uma função de transclusão que é pré-ligada ao escopo correto. Em uma configuração típica, o widget cria um escopo isolado, mas a transclusão não é um filho, mas um irmão do escopo isolado. Isso possibilita que o widget tenha estado privado e que a transclusão seja vinculada ao escopo pai (pré-isolado).

  • verdadeiro - transcluir o conteúdo da diretiva.
  • 'elemento' - transclui todo o elemento, incluindo quaisquer diretivas definidas com prioridade mais baixa.

Diz transcludenormalmente usado com ngTransclude. Mas o exemplo do documento do ngTransclude não usa ngTranscludediretiva de forma alguma.

Gostaria de alguns bons exemplos para me ajudar a entender isso. Por que precisamos disso? O que isso resolve? Como usá-lo?

Freewind
fonte
Para sua informação ... o link está funcionando pelo menos agora
Sandy

Respostas:

519

Considere uma diretiva chamada myDirective em um elemento, e esse elemento contém algum outro conteúdo, digamos:

<div my-directive>
    <button>some button</button>
    <a href="#">and a link</a>
</div>

Se myDirective estiver usando um modelo, você verá que o conteúdo de <div my-directive>será substituído pelo seu modelo de diretiva. Então, tendo:

app.directive('myDirective', function(){
    return{
        template: '<div class="something"> This is my directive content</div>'
    }
});

resultará nesta renderização:

<div class="something"> This is my directive content</div> 

Observe que o conteúdo do seu elemento original <div my-directive> será perdido (ou, melhor dizendo, substituído). Então, diga adeus a esses amigos:

<button>some button</button>
<a href="#">and a link</a>

Então, e se você quiser manter seu <button>...e <a href>...no DOM? Você precisará de algo chamado transclusão. O conceito é muito simples: inclua o conteúdo de um lugar para outro . Portanto, agora sua diretiva será semelhante a esta:

app.directive('myDirective', function(){
    return{
        transclude: true,
        template: '<div class="something"> This is my directive content</div> <ng-transclude></ng-transclude>'
    }
});

Isso renderizaria:

<div class="something"> This is my directive content
    <button>some button</button>
    <a href="#">and a link</a>
</div>. 

Em conclusão, você basicamente usa transclude quando deseja preservar o conteúdo de um elemento ao usar uma diretiva.

Meu exemplo de código está aqui . Você também pode se beneficiar assistindo isso .

odiseo
fonte
12
Parece que eles mudaram um pouco a funcionalidade. Pelo menos na versão> = 1.2.9. O conteúdo do modelo não é adicionado ao conteúdo renderizado. Veja a resposta da @TechExplorer abaixo
Tarjei Romtveit
20
Uma resposta muito, muito boa. Muito acima do normal. Você tem bons exemplos, e seu "este é meu conteúdo diretivo" facilitou a leitura na versão renderizada. Eu não entendo porque o Angular tem que usar terminologia e conceitos complexos e então não inclui exemplos fáceis de entender como o seu. +2
freeall
Alguém sabe se o conteúdo transcluído pode referir-se aos campos de escopo isolados da diretiva? Diz acima que a transclusão é um irmão, não uma criança, do escopo isolado ... então estou assumindo que não pode - mas queria saber se alguém poderia confirmar ou me informar se é possível
Simon Green
@UladzimirHavenchyk obrigado, eles mudaram o vídeo para outro lugar. Corrigi o link em conformidade.
odiseo
4
@odiseo, você poderia escrever TODOS os documentos do Angular em um inglês simples e fácil de entender como este! + muitos 1s.
Dan Hodson,
76

Acho importante mencionar as mudanças no comportamento acima na nova versão do AngularJS. Passei uma hora tentando alcançar os resultados acima com o Angular 1.2.10.

O conteúdo do elemento com ng-transclude não é anexado, mas completamente substituído.

Portanto, no exemplo acima, o que você alcançaria com 'transcluir' seria:

<div class="something">
    <button>some button</button>
    <a href="#">and a link</a>
</div>

e não

<div class="something"> This is my directive content
    <button>some button</button>
    <a href="#">and a link</a>
</div>

Obrigado.

TechExplorer
fonte
Para obter mais informações sobre o comportamento alterado no Angular 1.2, consulte a alteração eed299a .
Mark Rajcok,
37

O que o TechExplorer diz é verdade, mas você pode ter ambos os conteúdos incluindo em seu modelo uma tag de recipiente simples (como div ou span) com o atributo ng-transclude. Isso significa que o código a seguir em seu modelo deve incluir todo o conteúdo

<div class="something"> This is my directive content <div class="something" ng-transclude></div></div>
goulpan
fonte
5
Essa era a informação chave que faltava nas outras respostas
Matheus
4
Esta resposta adiciona muitas informações. ng-transcludeé o atributo que atua como espaço reservado, dentro do qual o conteúdo transcluído será colocado.
BeingSuman,
5

Da Wiki:

“Em ciência da computação, transclusão é a inclusão de parte ou da totalidade de um documento eletrônico em um ou mais documentos por referência”.

Eu gostaria de adicionar outro uso para transclusão, que muda a ordem de execução das funções de compilação e link das diretivas pai e filho. Isso pode ser útil quando você deseja compilar o DOM filho antes do DOM pai, pois o DOM pai talvez dependa do DOM filho. Este artigo é mais aprofundado e esclarece muito bem!

http://www.jvandemo.com/the-nitty-gritty-of-compile-and-link-functions-inside-angularjs-directives-part-2-transclusion/

Samir Alajmovic
fonte
5

A documentação atualizada do AngularJS 1.6.6 agora tem uma explicação melhor.

Transcluir é usado para criar uma diretiva que envolve outros elementos

Às vezes, é desejável ser capaz de passar um modelo inteiro em vez de uma string ou um objeto. Digamos que desejamos criar um componente de "caixa de diálogo". A caixa de diálogo deve ser capaz de envolver qualquer conteúdo arbitrário.

Para fazer isso, precisamos usar a opção transcluir . Consulte o exemplo abaixo.


script.js

angular.module('docsTransclusionExample', [])
.controller('Controller', ['$scope', function($scope) {
  $scope.name = 'Tobias';
}])
.directive('myDialog', function() {
  return {
    restrict: 'E',
    transclude: true,
    scope: {},
    templateUrl: 'my-dialog.html',
    link: function(scope) {
      scope.name = 'Jeff';
    }
  };
});

index.html

<div ng-controller="Controller">
  <my-dialog>Check out the contents, {{name}}!</my-dialog>
</div>

my-dialog.html

<div class="alert" ng-transclude></div>

Saída Compilada

<div ng-controller="Controller" class="ng-scope">
  <my-dialog class="ng-isolate-scope"><div class="alert" ng-transclude="">Check out the contents, Tobias!</div></my-dialog>
</div>

Transclude faz com que o conteúdo de uma diretiva com esta opção tenha acesso ao escopo fora da diretiva em vez de dentro.

Isso é ilustrado no exemplo anterior. Observe que adicionamos uma função de link em script.js que redefine o nome como Jeff. Normalmente, esperaríamos que {{name}} fosse Jeff. No entanto, vemos neste exemplo que a ligação {{name}} ainda é Tobias.

Melhor prática : use apenas transclude: truequando quiser criar uma diretiva que envolve conteúdo arbitrário.

Arthur S
fonte
0

transclude: true significa adicionar todos os elementos que são definidos em sua diretiva com o elemento template de sua diretiva.

if transclude: false esses elementos não são incluídos no html final da diretiva, apenas o modelo da diretiva é processado.

transclude: elemento significa que seu template de diretiva não é usado, apenas elementos definidos em sua diretiva são renderizados como html.

quando você define sua diretiva, ela deve ser restrita a E e quando você a adiciona na página,

<my-directive><elements><my-directive>
<elements> is like <p>gratitude</p>
what i am talking about.
dev verma
fonte