No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Template

8/22
Recursos

La API template nos permite conectar un web component de forma más profesional y organizada. También nos ayuda a clonar los elementos fácilmente. Como vimos en la clase anterior, el elemento no se clonaba, sino que se pasaba de etiqueta en etiqueta hasta la última en ser renderizada.

La etiqueta <template>

Template es una etiqueta que nos sirve como contenedor de código. Todo lo que escribamos adentro de esta etiqueta no se va a renderizar, sino que hay que activarlo mediante JavaScript. El profesor, sin embargo, no muestra cuál es dicho proceso y procede a utilizar una forma distinta. En el siguiente enlace vas a ver cómo se activa desde JS.

Escribir y activar el código dentro de la clase

De esta forma estamos armando toda la estructura HTML dentro de JavaScript, pero insertándola en la clase y fraccionando el HTML y CSS para más placer.

En este caso, creamos la clase, con su extensión y constructor, luego creamos un método que contendrá la estructura HTML (getElement). Adentro insertamos la variable template que contiene la estructura.

getTemplate() {
        const template = document.createElement('template');
       	template.innerHTML = `
		...(codigo HTML)
	`
}

Cómo clonar Elementos

Para clonar el código debemos indicar mediante el método cloneNode que se puede clonar. Para eso invocamos el contenido de getTemplate y lo anidamos a la clase (que luego al ser invocada en el HTML se convierte en la etiqueta misma)

render() { this.appendChild(this.getTemplate().content.cloneNode(true)) }

Paso final

Invocamos el render

render() { this.appendChild(this.getTemplate().content.cloneNode(true)) }
	`
}
connectedCallback() { this.render(); }

Contribución creada con los aportes de: Nazareno Aznar Altamiranda.

Aportes 21

Preguntas 10

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Basicamente la API Template nos permite conectar un web component de forma más profesional y organizada. También nos ayuda a clonar los elementos facilmente (Ya que como lo hicimos en la clase anterior el elemento no se clonaba, sino que se pasaba de etiqueta en etiqueta hasta la ultima en ser renderizada)

La etiqueta <template>

Es una etiqueta que nos sirve como contenedor de código. Todo lo que escribamos adentro de esta etiqueta no se va a renderizar , sino que hay que activarlo mediante Javascript. El profesor sin embargo no muestra cual es dicho proceso y procede a utilizar una forma distinta. En el siguiente enlace vas a ver cómo se activa desde JS:

Escribir y activar el código dentro de la clase

De esta forma estamos armando toda la estructura HTML dentro de Javascript, pero insertandola en la clase y fraccionando el HTML y CSS para más placer.

En este caso, creamos la clase, con su extension y constructor, luego creamos un método que contendrá la estructura HTML (getElement) . Adentro insertamos la variable template que contiene la estructura.

getTemplate() {
        const template = document.createElement('template');
       	template.innerHTML = `
		...(codigo HTML)
	`
}

En otro metodo (getStyles) todo lo que hacemos es retornar un literal string que contiene el código CSS (si queremos podemos contenerla en una variable, eso es a comodidad del programador)

getStyles() {
        return `...(código CSS)`
}

y luego al final del código de getElement la llamamos de esta forma

${this.getStyles()}

Clonar Elementos

Para clonar el código debemos indicar mediante el método cloneNode que se puede clonar. Para eso invocamos el contenido de getTemplate, y lo anidamos a la clase (que luego al ser invocada en el HTML se convierte en la etiqueta misma)

render() { this.appendChild(this.getTemplate().content.cloneNode(true)) }

Y FINALMENTE…

Invocamos el render

connectedCallback() { this.render(); }

Hola:

Si desean ver como se hace la transición primero pone el color azul y luego cambia al color rojo (minuto 11:50), se podría cambiar en la pestaña de network la velocidad de carga de la página:

Saludos 😃

una simple linea pero poderosa

section>h2{Hola mundo!}+div>p{Soy más texto ejemplo}

Hmmm, no ví exactamente para qué se usó la etiqueta <template> que escribimos en HTML, imagino que se verá en la siguiente clase
.
Por si les interesa, les dejo el código en mi repo (con ligeros cambios de texto xD)
.
Adicion de templates a los WebComponents

Apuntes y código con comentarios:

<h4>Template</h4>

Esto es opcional. Pero si adentro de tu componente van a venir muchos elementos que se conviertan en nodos, lo idal sería ocupar templates.

Recuerda: todo lo que esté dentro de la etiqueta <Template></Template> NO se va a renderizar de inicio.

Es importante que cloneNode(true) tenga el valor de true porque así podrá copiar todos los elementos anidados del HTML.

Podemos meter estilos con JS pero entrarán en conclicto con otros estilos, pero para esto usaremos ShadowDOM.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Custom Elements</title>
</head>
<body>

  <template>
    <h2>Hola desde h2 y template</h2>
    <div>
      <p>Soy más texto dentro de template</p>
    </div>
  </template>

  <my-element></my-element> <!!---Esto viene de JS en customElements.define()-->

  <script type="module" src="my-element.js"></script>

</body>
</html>
class myElement extends HTMLElement {
  constructor(){
    super(); //* Obtenemos acceso a todos los elementos y métodos de la clase que extendemos (heredamos)
  }

  getTemplate(){ //*Esto será puro HTML
    const template = document.createElement('template');
    template.innerHTML = `
      <section>
        <h2>Hola gente desde getTemplate()</h2>
        <div>
          <p>Soy un párrafo</p>
        </div>
      </section>
      ${this.getStyles()} //*Aplicamos los estilos
    `;
    return template;
  }

  getStyles(){ //*Esto será puro CSS
    return `
    <style>
      h2{
        color:red;
      }
    </style>
    `;
  }

  render(){
    this.append(this.getTemplate().content.cloneNode(true));
    //*Es importante que `cloneNode(true)` tenga el valor de true porque así podrá copiar todos los elementos anidados del HTML
  }

  //*Esto es lo que agregará cosas al DOM
  connectedCallback(){
    this.render();
  }
}

customElements.define('my-element' , myElement); //* Definimos que la clase se va a convertir en una etiqueta

para los que no entendieron lo de “template”.

lo que pasa es que solo la etiqueta “template” tiene la propiedad “content” con la que puedes hacer el “cloneNode(true)”.


this.getTemplate().content.cloneNode(true)

aquí NO esta clonando de la etiqueta template que creo en el html, esta clonando el innerHTML de la etiqueta “template” que creó con “document.createElement(“template”)”, de hecho si borran la etiqueta template del html verán que no efecta en nada.


const template = document.createElement("template");

a continuación lo que hacer es definir un “innerHTML” para esa etiqueta “template” que creó en la linea anterior.


const template = document.createElement("template"); // solo la etiqueta template tiene la propiedad "content"
        template.innerHTML = `
            <section>
                <h2>a</h2>
                <div>
                    <p>x</p>
                </div>
            </section>
        `
        return template;

luego en “render()” sucede la magia, si en render ustedes ponen “this.appendChild(this.getTemplate())” verán que les aparece una etiquete “template” dentro de “my-element”

js


this.appendChild(this.getTemplate()

html


    <my-element>
        <template></template>
    </my-element>

sin embargo si ponen " this.appendChild(this.getTemplate().content.cloneNode(true))", verán que les aparece solamente lo que definieron en el “innerHTML”, tal que:

js


render(){     this.appendChild(this.getTemplate().content.cloneNode(true))
}

html


    <my-element>
        <section>
            <h2>a</h2>
            <div>
                <p>x</p>
            </div>
        </section>
    </my-element>

y esto solo es posible hacerlo con la etiqueta “template” ya que dentro de otras etiquetas no existe la propiedad “content”

HTML Template

El elemento HTML <template> es un mecanismo para mantener el contenido HTML del lado del cliente que no se renderiza cuando se carga una página, pero que posteriormente puede ser instanciado durante el tiempo de ejecución empleando JavaScript.

Piensa en la plantilla como un fragmento de contenido que está siendo almacenado para un uso posterior en el documento. El analizador procesa el contenido del elemento <template> durante la carga de la página, pero sólo lo hace para asegurar que esos contenidos son válidos; sin embargo, estos contenidos del elemento no se renderizan.

Para lo que nos sirve la etiqueta <template> es justamente para tener una plantilla, que posteriormente utilizaremos para agregarle contenido dinámico con JavaScript para añadirlas al DOM, la plantilla como tal nunca se mostrará en la página, sólo se mostrarán los nodos creados desde JavaScript que la utilizaron como base para ser creados.

<!-- Creamos la plantilla -->
<template id="template-card">
	<figure>
		<img />
		<figcaption></figcaption>
	</figure>
</template>
const $container = document.querySelector(".container"),
  $template = document.getElementById("template-card").content,
  $fragment = document.createDocumentFragment(),
	cardsContent = [
    {
      title: "Tecnología",
      img: "https://placeimg.com/200/200/tech",
    },
    {
      title: "Animales",
      img: "https://placeimg.com/200/200/animals",
    }
  ];
// Por cada imagen que obtenemos de una API (por ejemplo) utilizaremos la plantilla y sólo le agregaremos el contenido
cardsContent.forEach((el) => {
  $template.querySelector("img").setAttribute("src", el.img);
  $template.querySelector("img").setAttribute("alt", el.title);
  $template.querySelector("figcaption").textContent = el.title;
  let $clone = document.importNode($template, true);
  $fragment.appendChild($clone);
});

$container.appendChild($fragment);

No entendi muy bien su uso.
Pienso que tiene que ver mas con optimizacion entonces 🤔
Al usar <Template> se crea un Document Fragment el cual no se renderiza, aqui entonces podemos usar innerHTML para definir la estructura HTML del template, dicho template (fragment) tiene un atributo de solo lectura que es content, el cual podemos clonar con cloneNode(true), este metodo recibe un parametro booleano que indica si el clonado sera profundo o no. Al clonarlo estamos transformando el string del template a nodos reales (elementos de HTML) que luego podemos insertar al DOM con append.
De esta forma nosotros solo le pasamos un solo Nodo con sus nodos hijos, en lugar de un innerHTML que el navegador tenga que traducir a nodos, lo cual deriva en mas seguridad y optimizacion. No estoy seguro si lo entendí correctamente.

MY NOTES FOR TEMPLATE

Cabe recalcar que el tema de css es algo de especificada y que saben que las líneas de css que son importante son las que se escriben al final, siempre van a ser mas importantes que las que están arriba es como si se sobrescribieran.

class myElement extends HTMLElement{
  
  constructor(){
    super();



    
  }

  //Generamos una funcion en cual tendremos nuestro template html y esta
    //Funcion retornara este template
  getTemplate(){

    const template = document.createElement('template');
    template.innerHTML = `
      <section>

        <h2>Hola mundo!</h2>
        <div>

          <p> Soy text ejemplo<p>
        
        </div>
      
      </section>

  <!-- Para utilizar nuestros estilos de nuestro metodo lo llamamos desde nuestro template html
       para que se agreguen -->    
      ${this.getStyles()}

    `;
    return template
  }
  //Podremos generar otro metodo para poner los estilos, pero esto mas que todo se hace por simples
    //Buenas practicas pero se puede hacer de otras maneras.
  getStyles(){
    return`

      <style>
        h2{

          color:red;
        }
      </style>
    
    `
  }
  //Generamos otro metodo para que el contenido de nuestra etiqueta template se pueda clonar
    //Para poderlo agregar al dom
  render(){

    //Agregamos el elemento al dom por dentro utilzamos la funcion que genera el template
      //y utilizamos el content.clone(true) para clonar el elemento
        //Le ponemos true porque si este fuera false solo tomaria las etiquetas padre y no
          //Todo lo que tienen por dentro las etiquetas

    this.appendChild(this.getTemplate().content.cloneNode(true))

  }

  
  connectedCallback(){
    //Inicializamos en el dom el metodo de render
    this.render();
    


  }

}

customElements.define('my-element', myElement);

La forma de usar los templates es, crear un código base entre las etiquetas <template>, es decir una plantilla.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Template</title>
  </head>
  <body>
    <h2 class="title">Soy un Template</h2>
    <template>
      <div>
      <p>Texto de muestra</p>
      </div>
    </template>
    <script type="module" src="./template.js"></script>
  </body>
</html>

Luego en JavaScript procedes a clonar el código que esta entre las etiquetas <template>, le adicionar lo que requieres y lo renderizas, ejemplo:

const template = document.querySelector('template').content.querySelector('p');
for (let i = 1; i < 10; i++) {
  let clone = template.cloneNode(true);
  clone.textContent = `Ciclo: ${i}`;
  document.body.appendChild(clone);
}

En el explorador se ve así:

Soy un Template
Ciclo: 1
Ciclo: 2
Ciclo: 3
Ciclo: 4
Ciclo: 5
Ciclo: 6
Ciclo: 7
Ciclo: 8
Ciclo: 9

Fue curioso, intente crear mi template y su contenido con createElement y append pero parece que al hacerlo de esa manera no funciona bien la clonación (segui el proceso y funciono hasta donde se veia en consola pero faltaba clonarlo, al clonarlo ya no funcionaba), usando el template literal si funciono con normalidad y luego me pregunte si tenia que ver con que no inicializamos los nodos en el constructor pero seguia sin funcionar.

Ahora me pregunto si el nombre del “template literal” tendrá que ver con esta etiqueta template y me quede con la duda de porque solo funciona usando innerHTML y no de la otra manera.

No se le entiende porque mezcla todo

Recomendación

No se si alguien mas a tenido este problema de que se le duplica el codigo o simplemente no se renderiza en lo particular es muy importante al trabajar con los web components
aperturar y cerrar de forma correcta cada etiqueta
<etiqueta></etiqueta> ya que podemos tener algunos inconvenientes al momento de renderizar

Un tip que lei no me acuerdo donde y me gusto es de cambiar el modo del lenguaje a HTML para escribir el template.innerHTML y que las etiquetas las cree de forma automatica

Para que se usa el template ¿?

Bueno al crear el nodo Template con Js nos sirve para simplemnte tener una base desde donde trabajar, en el ejemplo de la clase Diego genero la semantica dentro de un Section para tener un mejor control semantico y visual. La etiqueta simplente proporciono precisamente esa base para ahi colocar el codigo

Algo que no he visto comentado por otras personas es la necesidad de clonar el template o el resultado de `getTemplates()`. Cuando se crea un template, la información se guarda en la propiedad `.content`, que contiene el `#document-fragment`. Si no clonamos el template, la información del `document-fragment` se mueve al DOM y, si vuelves a llamar al template, no se mostrará nada porque el "template" original se ha movido. Si no se clona, solo podrás llamar al template una vez, ya que el `document-fragment` se habrá trasladado al DOM y no estará disponible para futuros llamados. En cambio, al clonar el template, podrás llamarlo tantas veces como desees, ya que el `document-fragment` se mantendrá en la propiedad `.content` y la plantilla estará siempre disponible. En el código de esta clase, si no se usa `cloneNode()`, al volver a llamar a `render()`, se creará un nuevo template y se añadirá al DOM este nuevo `document-fragment`. Dado que se crea un nuevo template en cada llamado, no habrá problema. Sin embargo, si intentas hacer esto fuera de una función, como en el código que incluiré a continuación, solo se mostrará una vez porque el `document-fragment` estará vacío debido a la falta de clonación. Además, si deseas agregar etiquetas o nodos a tu template utilizando `appendChild`, debes hacerlo a través de `this.template.content.appendChild()`, ya que dentro de la propiedad `content` es donde se encuentra el `document-fragment` y donde deberías almacenar la estructura que estás creando. ```js let a = document.createElement("section"); a.innerHTML= `

Hola mundo!

soy mas texto de ejemplo

` class myNotificationCustom extends HTMLElement{ constructor(){ super(); this.template = document.createElement("template"); this.template.content.appendChild(a) } render(){ this.appendChild(this.template.content); } connectedCallback(){ this.render(); this.render() this.render(); this.render() } } customElements.define("notification-custom",myNotificationCustom); ```

Se podría decir entonces que para el caso de una página en donde mi header se repite en todas las pantallas del proyecto puedo crear el _template _ y solo resta llamarlo en cada uno de los archivos del HTML?

Tip:

Para escribir HTML con atajos o ayudas, ve a la parte de abajo que dice Javascript, cambia a html y de nada.

Ya cuando no uses HTML cambia a HTML.

Ojo que el audio falla gachamente.

class Element extends HTMLElement {
    constructor(){
        super();
    }
    getTemplate() {
        const template = document.createElement('template');
        template.innerHTML = ` 
            <section>
                <h2>Hello Guys</h2>
                <div>
                    <p>Texto de ejemplo</p>
                </div>
            </section>
        `;
        return template;
    }

    render() {
        this.appendChild(this.getTemplate().content.cloneNode(true));
    }

    connectedCallback() {
        this.render();
    }
}

customElements.define("my-element", Element);```

,