> Manuales > Manual de Lit

Cómo construir vistas complejas de los componentes Lit con varios templates. Tendremos un template principal que se apoyará en otros templates secundarios, lo que nos ayudará a crear componentes más fáciles de entender y sencillos de mantener.

Composición de templates en Lit

Comenzamos una serie de artículos para explorar las posibilidades de los templates en Lit. Como templates nos referimos al sistema para generar la vista del componente, es decir, la parte del componente que se ve en el navegador al utilizarlo.

Por supuesto, el template del componente es una parte fundamental y Lit ofrece diversas herramientas para poder mejorar las vistas y acceder a funciones interesantes como condicionales, bucles y más. Sin embargo, vamos a comenzar poco a poco, por lo que en este artículo solamente vamos a ver algo sencillo como es la composición de templates.

¿A qué nos referimos con la composición de templates?

Un template se define mediante un método render(), que ya hemos conocido, en el que se usa una serie de marcado, es decir, etiquetas HTML y su contenido.

Puede haber templates realmente simples, como por ejemplo un componente de botón, que será una caja con un texto y poco más. También puede haber templates complejos, que incluyan decenas de etiquetas con una estructura bastante elaborada. En esos casos, usar un único template puede resultar poco claro, porque puede que nos encontremos con mucho HTML junto y por tanto sea difícil de entender a primera vista y mantener en el futuro.

La solución sencilla para crear templates fácilmente mantenibles es realizar una composición de templates, en los que tenemos un template principal que va haciendo uso de una serie de sub-templates para conseguir el objetivo. Esto es muy fácil de realizar en Lit.

Cómo crear un template parcial

Ya vimos cómo se hace un template en un componente, porque ya hemos trabajado con el método render(), que es el template principal.

Podemos crear todos los métodos que necesitemos en el componente como templates secundarios. Para ello trabajaremos del mismo modo que se implementa render(), creando un método que devueleve el template generado por el Tagged Template String "html". Por ejemplo de esta manera:

titleTemplate() {
    return html`
        <h2>${this.title}</h2>
    `
}

En el método simplemente se hace el return del template generado, igual que habíamos visto en el método render.

Cómo invocar un template secundario

Para usar un template secundario invocamos el método del template correspondiente, dentro del template principal (método render()).

render() {
    return html`
        <div>
            <p>Este es el template principal y ahora vamos a invocar un template secundario</p>
            <section class="main">
                ${this.titleTemplate()}
            </section>
            <p>El marcado puede ser el que sea necesario. Simplemente se colocará el template secundario en el lugar donde lo estemos usando.</p>
        </article>
    `;
}

Por supuesto, todos los templates del componente, principal y secundarios, **pueden usar las propiedades del componente** y son igualmente **reactivos**.



## Componente card

Para ilustrar esta técnica con un ejemplo vamos a realizar un componente de tarjeta llamado ```dw-card```. Para realizar este componente realizaremos un template principal que usará a su vez tres templates por separado, para definir la parte del título, cuerpo de la tarjeta y del pie. 

> Este componente lo iremos utilizando para varias mejoras a medida que vayamos conociendo nuevas características de Lit. Quizás en esta primera etapa no sea todavía demasiado complejo, como para que fuese tan importante hacer una composición de templates, pero a medida que vayamos incrementando sus funcionalidades seguramente nos vendrá bien. En todo caso, nunca está de más tener organizado el código del template.

Por ejemplo, este sería el template principal del componente card, que invoca tres métodos de templates secundarios, uno para mostrar el título, otro para mostrar el cuerpo y otro para el pie de la tarjeta.

```javascript
render() {
    return html`
        <article>
            <section class="main">
                ${this.titleTemplate()}
                ${this.bodyTemplate()}
            </section>
            <section class="actions">
                ${this.actionsTemplate()}
            </section>
        </article>
    `;
}

Código completo del componente card

Ahora vamos a ver el código completo del componente dw-card, que hemos usado para este ejemplo de composición de templates.

import { LitElement, html, css } from 'lit';

export class DwCard extends LitElement {
    static styles = [
        css`
            :host {
                display: inline-block;
            }
            article {
                border: 1px solid #ddd;
                box-shadow: 2px 2px 4px rgba(20, 20, 20, 0.2);
                border-radius: 0.5rem;
            }
            .main {
                border-bottom: 2px solid #ddd;
                padding: 0 1rem;
            }
            h2 {
                margin: 1rem 0;
                font-size: 1.3rem;
            }
            .actions {
                padding: 1rem;
                text-transform: uppercase;
            }
            .actions p {
                margin: 0;
            }
            .actions a {
                text-decoration: none;
                color: #35e;
                letter-spacing: .5px;
            }
        `
    ];

    static get properties() {
        return {
            actionUrl: { type: String },
            actionLabel: { type: String },
            title: { type: String },
        };
    }

    render() {
        return html`
            <article>
                <section class="main">
                    ${this.titleTemplate()}
                    ${this.bodyTemplate()}
                </section>
                <section class="actions">
                    ${this.actionsTemplate()}
                </section>
            </article>
        `;
    }

    titleTemplate() {
        return html`
            <h2>${this.title}</h2>
        `
    }

    bodyTemplate() {
        return html`
            <div class="body"><slot></slot></div>
        `
    }

    actionsTemplate() {
        return html`
            <p><a href="${this.actionUrl}">${this.actionLabel}</a></p>
        `
    }
}
customElements.define('dw-card', DwCard);

Componer con slots

Hay una cosa nueva que hemos introducido en este componente y que tenemos que explicar. Se trata de los slots en componentes, que veremos de manera muy general y dedicaremos más adelante un artículo para conocerlos en detalle.

Si te fijas el template "bodyTemplate", tiene una etiqueta nueva llamada <slot>. Esa etiqueta hace referencia al contenido que se haya colocado en la etiqueta host.

Esto quiere decir que, cuando tenemos el uso de un componente de esta manera:

<dw-card>
	<p>Esto es el contenido del slot</p>
</dw-card>

El párrafo que está metido dentro del cuerpo de la etiqueta <dw-card>, o cualquier otro contenido que se albergase dentro de esta etiqueta, se considera un slot y tiene la particularidad de poder utilizarse dentro del propio componente.

Por tanto, en el lugar donde quieras que aparezca ese contenido de la etiqueta host, podrás usar la etiqueta <slot>.

Más adelante hablaremos de slots porque tienen características muy interesantes y un poco más avanzadas que debemos de conocer. De momento es todo lo que necesitas saber para poder entender este componente de tarjeta. Los slots son muy útiles para la composición del componente y para reutilizar el código HTML de la página, además de ayudar en el SEO. Hablaremos de todo esto con detalle en breve.

Usar el componente Card

Ya para acabar, vamos a ver cómo usar el componente de tarjeta. Éste recibe varios datos por sus atributos y también usa un slot para definir su cuerpo.

Un dato sencillo como el título de la tarjeta lo podemos pasar directamente como atributo, porque será una cadena, sin estilos ni saltos de línea. Sin embargo, el contenido del cuerpo podría ser bastante grande, como con varios párrafos, listas, imágenes, etc. Por eso lo ideal es meterlo como un slot, ya que nos permite poner dentro de la tarjeta cualquier cantidad de contenido.

El resultado será un web component que tendrá varios atributos definidos, junto con un contenido dentro.

<dw-card 
    title="Esta tarjeta mola!" 
    actionUrl="https://escuela.it" 
    actionLabel="EscuelaIT"
>
    <p>Hola, esto es una prueba de tarjeta!! ¿Qué te parece?</p>
    <p>Podría tener <b>cualquier cantidad de contenido</b></p>
</dw-card>

En este enlace de GitHub puedes ver el proyecto del manual, tal como hemos dejado el código hasta este punto.

Conclusión

Esperamos que haya sido útil esta información y que puedas aprender a organizar el código de tus vistas en los componentes Lit, para usar la composición de templates en los momentos en los que juzgues oportuno.

Gracias a esta técnica podrás crear componentes más organizados y fáciles de mantener, especialmente cuando tienen templates complejos, con bastante marcado y lógica dentro de las vistas.

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual