Angular Templates: las directivas ng-template, ng-container y ngTemplateOutlet

Hace pocos días Angular ha liberado su nueva versión, la 6.0.0. En Profile estamos deseando probar las novedades del framework de referencia para los desarrolladores frontend, pero hoy nos vamos a centrar en cómo utilizar las directivas de Angular Templates.

En este post aprenderás a usar las directivas de ng-template, ng-container y ngTemplateOutlet y descubrirás todo su potencial. Aunque no te hayas dado cuenta, llevas usándolas desde que comenzaste a tocar este framework. La directiva estructural más famosa de Angular, ngIf, está basada en las templates.

Ahora que ya estamos más cómodos y sabemos de lo que hablamos, ¡vamos a echarle leña al fuego!

Angular Templates: las directivas ng-template, ng-container y ngTemplateOutlet

Conozcamos la directiva ng-template

Esta directiva representa, tal y como se intuye en su nombre, una template de Angular. El contenido de esta etiqueta contendrá una parte de una template que luego se puede reutilizar y añadirse a otras templates para formar la template de un componente.

Directiva Angular ng-template

Ya te habrás dado cuenta de que si pruebas el ejemplo anterior no renderiza nada. Pero no te asustes, es justo el comportamiento que esperábamos ya que solo estamos definiendo la template pero aún no la estamos utilizando.

Vamos a renderizarla con ngIf

Renderizar ng-template con ngIf

¡Ahora sí! Ya podemos ver que nuestra template ha sido renderizada. Este es un escenario de ngIf/else muy común donde mostramos una alternativa de template ‘nopeople’ mientras no hay datos en ese array, ya sea porque aún no han llegado del backend o este filtrado.

Directiva Angular ngIf

Para asignar la referencia de una template utilizamos la sintaxis ‘#nopeople’. En nuestro ejemplo la cláusula else apunta a esta referencia.

Como comentábamos al inicio del post, la directiva ngIf también usa las templates. Pero, ¿cómo lo hace? Vamos a bucear en las entrañas de Angular para jugar un poco. Lo que sucede en este caso es que el elemento en el que está puesto la directiva estructural ngIf se posiciona dentro de una ng-template. Y por otra parte la directiva *ngIf se divide en otras dos: [ngIf] y [ngIfElse], que son la sintaxis de input en Angular.

En este caso, si atamos cabos, podemos intuir que con nuestra otra familiar directiva estructural ngFor ocurre un proceso similar a este. Si alguna vez has probado a poner dos directivas estructurales en un mismo elemento ya sabrás que da un error. Vamos a ver cómo podemos solucionar esto:

Resolviendo error al poner dos directivas de Angular

Parece que lo hemos solucionado. Si probamos el ejemplo anterior todo funcionará bien pero aquí hay algo que no me gusta… Poner un elemento extra como solución no queda muy limpio… ¿Podríamos aplicar una segunda directiva estructural sin añadir un nuevo elemento?

Sí, y para eso, tenemos la directiva estructural ng-container. Pero espera, antes de avanzar con esto, te habrás fijado que el array de personas lo hemos definido como People[]. En typescript tenemos lo que se llaman interfaces, que nos ayudan y nos facilitan la vida a la hora de escribir código. Son como un contrato en el que se especifican los elementos que debe contener, ya sea a la clase que se le implementa o, en nuestro caso, como un nuevo tipo.

La directiva ng-container

Directiva de Angular ng-container

Ahora sí, con esta directiva no es necesario crear un div extra. Renderiza lo que contiene o bien la template nopeople. Pero renderizar referencias de templates o apuntar a otras como con ngIf es solo el principio.

También tiene otro uso importante y es que puede renderizar templates dinámicamente. Para poder hacerlo usaremos la directiva ngTemplateOutlet.

Directiva Angular ng-container

Con ngTemplateOutlet podemos tener nuestra template en cualquier sitio de la página e instanciarla. Estamos referenciando a la template nopeople con su referencia ‘#nopeople’ y usamos la directiva estructural ngTemplateOutlet para instanciar la template.

Ahora que ya sabemos instanciar templates vamos a ver a qué pueden acceder.

El contexto de las templates

Dentro de la etiqueta ng-template tenemos acceso a las mismas variables de contexto que son visibles en la template exterior, como por ejemplo la variable ‘people’. Esto se debe a que las instancias de ng-template tienen acceso al mismo contexto en el cual están integradas. Además cada template también puede definir su set de variables. Vamos a ver un ejemplo aislado para entenderlo mejor.

El contexto en las templates de Angular

En esta template, a diferencia de las anteriores, tenemos una variable de entrada llamada ‘peopleCounter’ definida con la propiedad ng-template usando el prefijo ‘let-’. Esta variable es visible dentro de la ng-template, pero no fuera. El contenido de la variable se determina por la expresión que está asignada a la propiedad let-peopleCounter. La expresión es evaluada por un objeto de contexto que se pasa en la ngTemplateOutlet conjunto con la template de referencia a la que se va a instanciar. Este objeto de contexto debe de tener una propiedad llamada ‘numberOfPeople’ para que se muestre algún valor dentro de la template. El objeto de contexto se pasa a la ngTemplateOutlet a través de la propiedad de contexto, que puede recibir cualquier expresión que evalúe a un objeto.

Parece que la cosa ya va cogiendo forma y podemos ver el potencial de estas directivas, un par de cosillas más y ¡estarás hecho un Templates Master!

Referencias de templates en nuestra clase del componente

Ya hemos visto que podemos referenciar nuestras templates en la template en la que estamos, pero también es posible hacer referencia a esta en la clase del componente con el decorador ‘ViewChild’.

Referencias de templates de Angular en nuestra clase de componente

La template se puede inyectar como cualquier otro elemento DOM o componente, añadiendo a ViewChild el nombre de referencia, en nuestro caso ‘nopeople’. Por lo tanto ahora podemos hacer cosas como pasar la template de referencia a otros componentes, como por ejemplo un parámetro de entrada.

Componentes configurables con templates de entrada

Vamos a hacer que nuestro componente sea configurable a través de una entrada que sea una template de referencia. Nuestro componente muestra la template ‘nopeople’ cuando el array de personas es cero. Vamos a dar la opción de que si a nuestro componente le pasan otra template de referencia mediante una entrada se muestre esa template y, si no, mantendremos la que hemos hecho por defecto.

configurando los componentes con templates de entrada en Angular

configurando los componentes con templates de entrada en Angular

 

Como puedes ver, hemos creado un componente llamado ‘people-list’, donde hemos puesto toda la lógica que teníamos antes en el ‘app.component’. Aquí podemos ver que tenemos una template definida por defecto que indica que no hay personas en inglés, llamada ‘defaultNopeople’. Esta se usará mientras la propiedad de entrada ‘customNopeopleTpl’ sea undefined. Si esta propiedad está definida, entonces la template de entrada personalizada pasada por ‘customNopeopleTpl’y se usará para mostrar el contenido en español.

La template no people personalizada está instanciada dentro del ng-container usando la propiedad ngTemplateOutlet. La decisión de que template usar (default o custom) está determinada por la expresión ternaria, aunque podríamos dejar esa lógica en un método de la clase si fuera más complicado.

Resumen y conclusiones

Ya está, ¡estás hecho un Templates Master! Ya has visto que con las directivas ng-template, ng-container y ngTemplateOutlet combinadas puedes crear componentes super customizables y dinámicos.

Si ya has trasteado la librería de componentes @profiless/profile-lib-components del último post sobre Angular, te habrás dado cuenta que se ha usado en varios de los componentes. Con estas directivas puedes cambiar totalmente la apariencia de un componente basándote en templates de entrada y puedes definir una template y instanciarla en varios sitios de la aplicación.

Esto es solo una manera de combinarlas, así que ¡adelante! Prueba y trastea todo lo que quieras con estas directivas ahora que ya estas hecho un Master.

¿Te pareció interesante? Compártelo:
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInPrint this pageEmail this to someone

Sobre el Autor:

Front End Developer en Profile Software Services con muchas ganas de aprender siempre. Angular Framework lover!