¿Comprender la opción transcluir de definición de directiva?

195

Creo que este es uno de los conceptos más difíciles de entender con la directiva de angularjs.

El documento de http://docs.angularjs.org/guide/directive dice:

transcluir : compila el contenido del elemento y lo pone a disposición de la directiva. Normalmente se usa con ngTransclude. La ventaja de la transclusión es que la función de enlace recibe una función de transclusión que está vinculada previamente al alcance correcto. En una configuración típica, el widget crea un ámbito de aislamiento, pero la transclusión no es un elemento secundario, sino un hermano del ámbito de aislamiento. Esto hace posible que el widget tenga un estado privado y que la transclusión esté vinculada al ámbito primario (preaislado).

  • verdadero: transcluye el contenido de la directiva.
  • 'elemento': transcluye todo el elemento, incluidas las directivas definidas con menor prioridad.

Dice transcludetípicamente utilizado con ngTransclude. Pero la muestra del documento de ngTransclude no usa la ngTranscludedirectiva en absoluto.

Quisiera algunos buenos ejemplos para ayudarme a entender esto. ¿Por qué lo necesitamos? ¿Qué resuelve? ¿Cómo usarlo?

Viento libre
fuente
FYI ... el enlace funciona al menos ahora
Sandy

Respuestas:

518

Considere una directiva llamada myDirective en un elemento, y ese elemento encierra algún otro contenido, digamos:

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

Si myDirective está usando una plantilla, verá que el contenido de <div my-directive>será reemplazado por su plantilla directiva. Entonces teniendo:

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

resultará en este render:

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

Tenga en cuenta que el contenido de su elemento original <div my-directive> se perderá (o mejor dicho, se reemplazará). Entonces, diga adiós a estos amigos:

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

Entonces, ¿qué pasa si quieres mantener tu <button>...y <a href>...en el DOM? Necesitarás algo llamado transclusión. El concepto es bastante simple: incluye el contenido de un lugar a otro . Así que ahora su directiva se verá así:

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

Esto representaría:

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

En conclusión, básicamente usa transclude cuando desea preservar el contenido de un elemento cuando usa una directiva.

Mi código de ejemplo está aquí . También podría beneficiarse al ver esto .

odiseo
fuente
12
Parece que han cambiado un poco la funcionalidad. Al menos en la versión> = 1.2.9. El contenido de la plantilla no se agrega al contenido representado. Ver la respuesta de @ TechExplorer a continuación
Tarjei Romtveit
20
Una muy, muy buena respuesta. Muy por encima de lo normal. Tiene buenos ejemplos, y su "este es mi contenido directivo" lo hizo muy fácil de leer en la versión renderizada. No entiendo por qué Angular tiene que usar terminología y conceptos complejos y luego no incluye ejemplos fáciles de entender como el suyo. +2
freeall
¿Alguien sabe si el contenido transcluido puede referirse a los campos de alcance aislado de la directiva? Dice anteriormente que la transclusión es un hermano, no un niño, del alcance aislado ... así que supongo que no puede, pero me preguntaba si alguien podría confirmar o avisarme si es posible
Simon Green
@UladzimirHavenchyk gracias, trasladaron el video a otro lugar. Arreglé el enlace en consecuencia.
odiseo
44
@odiseo, ¿podrías escribir TODOS los documentos de Angular en inglés simple y fácil de entender como este! + muchos 1's.
Dan Hodson
76

Creo que es importante mencionar los cambios en el comportamiento anterior en la nueva versión de AngularJS. Pasé una hora tratando de lograr los resultados anteriores con Angular 1.2.10.

El contenido del elemento con ng-transclude no se agrega sino que se reemplaza por completo.

Entonces, en el ejemplo anterior, lo que lograrías con 'transcluir' sería:

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

y no

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

Gracias.

TechExplorer
fuente
Para obtener más información sobre el cambio de comportamiento en Angular 1.2, vea change eed299a .
Mark Rajcok
37

Lo que dice TechExplorer es cierto, pero puede tener ambos contenidos al incluir en su plantilla una etiqueta de contenedor simple (como div o span) con el atributo ng-transclude. Esto significa que el siguiente código en su plantilla debe incluir todo el contenido

<div class="something"> This is my directive content <div class="something" ng-transclude></div></div>
goulpan
fuente
55
Esa fue la información clave que faltaba en las otras respuestas
Matheus
44
Esta respuesta agrega mucha información. ng-transcludees el atributo que actúa como marcador de posición, dentro del cual se colocará el contenido transcluido.
BeingSuman
5

De Wiki:

"En informática, la transclusión es la inclusión de parte o la totalidad de un documento electrónico en uno o más documentos por referencia".

Me gustaría agregar otro uso para la transclusión, y es que cambia el orden de ejecución de las funciones de compilación y enlace de las directivas padre e hijo. Esto puede ser útil cuando desea compilar el DOM secundario antes que el DOM primario ya que el DOM primario quizás depende del DOM secundario. ¡Este artículo va más en profundidad y lo aclara muy bien!

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

Samir Alajmovic
fuente
5

La documentación actualizada de AngularJS 1.6.6 ahora tiene una mejor explicación.

Transclude se utiliza para crear una directiva que envuelve otros elementos

A veces es deseable poder pasar una plantilla completa en lugar de una cadena o un objeto. Digamos que queremos crear un componente de "cuadro de diálogo". El cuadro de diálogo debe poder envolver cualquier contenido arbitrario.

Para hacer esto, necesitamos usar la opción de transcluir . Consulte el ejemplo a continuación.


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>

Salida 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 hace que el contenido de una directiva con esta opción tenga acceso al alcance fuera de la directiva en lugar de dentro.

Esto se ilustra en el ejemplo anterior. Tenga en cuenta que hemos agregado una función de enlace en script.js que redefine el nombre como Jeff. Normalmente, esperaríamos que {{name}} fuera Jeff. Sin embargo, vemos en este ejemplo que el enlace {{name}} sigue siendo Tobias.

Práctica recomendada : solo úsela transclude: truecuando desee crear una directiva que envuelva contenido arbitrario.

Arthur S
fuente
0

transcluir: verdadero significa agregar todos los elementos definidos en su directiva con el elemento de plantilla de su directiva.

if transclude: false, estos elementos no están incluidos en su html final de directiva, solo se representa la plantilla de directiva.

transclude: elemento significa que su plantilla de directiva no se usa, solo el elemento definido en su directiva se representa como html.

cuando define su directiva, entonces debe restringirse a E y cuando la agrega en la página, entonces

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