Gairebé cap interfície real mostra sempre exactament el mateix contingut: una tasca pot estar pendent, en progrés o feta, i probablement vulguis mostrar una insígnia diferent segons quin sigui el seu estat. A la lliçó anterior ja vas utilitzar, de passada, un operador ternari dins d'una interpolació; en aquesta lliçó aprofundiràs en les diferents formes de renderitzar contingut condicionalment a Lit, quan convé cadascuna, i les aplicaràs per donar a <task-card> una insígnia d'estat que canvia segons les dades de la tasca.

Contingut

  1. Renderitzat condicional: no és màgia, és JavaScript
  2. L'operador ternari: l'opció més habitual
  3. L'operador &&: mostrar o amagar sense alternativa
  4. Extreure la lògica a funcions auxiliars
  5. Compte amb els "falsy" en utilitzar &&
  6. La directiva when: una menció de passada
  7. Aplicant-ho a <task-card>: insígnia segons l'estat

  1. Renderitzat condicional: no és màgia, és JavaScript

Una de les idees més importants que cal interioritzar sobre Lit és que no existeix una sintaxi especial de plantilles per a condicionals, a l'estil {% if %} d'altres motors de plantilles que potser coneixes d'altres contextos. Lit no necessita inventar una sintaxi pròpia perquè, com vas veure a la lliçó "El Motor de Plantillas de Lit", dins de ${} es pot escriure qualsevol expressió JavaScript vàlida, i JavaScript ja disposa d'operadors capaços d'expressar una condició en forma d'expressió: l'operador ternari i l'operador &&.

Aquesta és, de fet, una de les senyes d'identitat del disseny de Lit: en lloc de crear un llenguatge de plantilles paral·lel amb les seves pròpies regles a aprendre, reutilitza JavaScript tal com és. Qui ja sap JavaScript ja sap, sense adonar-se'n, gran part de "la sintaxi de condicionals de Lit".

  1. L'operador ternari: l'opció més habitual

L'operador ternari (condició ? valorSiVertader : valorSiFals) és la forma més comuna de renderitzar condicionalment a Lit quan hi ha dues alternatives possibles, totes dues amb contingut a mostrar:

render() {
  return html`
    <p>${this.completada ? 'Tarea finalizada' : 'Tarea pendiente'}</p>
  `;
}

El resultat de cada branca del ternari pot ser, igual que en qualsevol interpolació, text simple, un número, o fins i tot una altra plantilla html aniuada (com es va veure a la lliçó anterior):

render() {
  return html`
    <p>
      ${this.completada
        ? html`<span class="icono-ok">✓</span> Finalizada`
        : html`<span class="icono-pendiente">○</span> Pendiente`}
    </p>
  `;
}

Aquí cada branca del ternari retorna una plantilla html diferent, amb el seu propi <span> amb una classe diferent. Lit gestiona això sense cap problema: cada vegada que render() s'executa, avalua la condició i col·loca al DOM el resultat de la branca corresponent, substituint el que hi hagués abans si la branca activa ha canviat des del renderitzat anterior.

  1. L'operador &&: mostrar o amagar sense alternativa

Quan només interessa mostrar alguna cosa si es compleix una condició, i no hi ha cap contingut alternatiu a mostrar en cas contrari, el patró habitual és l'operador lògic &&:

render() {
  return html`
    <article>
      <h3>${this.titulo}</h3>
      ${this.urgente && html`<p class="aviso">⚠ Esta tarea es urgente</p>`}
    </article>
  `;
}

Aquest patró es basa en com avalua JavaScript l'operador &&: si l'operand de l'esquerra (this.urgente) és "fals", l'expressió completa s'avalua com aquell valor fals, sense arribar a avaluar l'operand de la dreta; si és "vertader", l'expressió completa pren el valor de l'operand de la dreta (la plantilla html de l'avís). Quan this.urgente és false, la interpolació completa val false, i Lit, en trobar false (o null, o undefined) com a resultat d'una interpolació de contingut, senzillament no renderitza res en aquest punt, sense deixar cap rastre al DOM.

Aquest patró és preferible al ternari quan no existeix una alternativa raonable a mostrar en el cas contrari; escriure this.urgente ? html\...` : ''funciona igual de bé, peròthis.urgente && html`...`` comunica amb més claredat la intenció de "mostrar això només si es compleix la condició, i res en cas contrari".

  1. Extreure la lògica a funcions auxiliars

Quan la lògica condicional comença a tenir més de dues o tres branques, o quan el càlcul de què mostrar és una mica més elaborat que una simple comparació, resulta molt més llegible extreure aquesta lògica a un mètode propi de la classe (una funció auxiliar) i cridar-lo des de dins de la interpolació:

import { LitElement, html } from 'lit';

class TaskCard extends LitElement {
  constructor() {
    super();
    this.estado = 'en-progreso'; // 'pendiente' | 'en-progreso' | 'hecha'
  }

  renderIndicadorEstado() {
    if (this.estado === 'hecha') {
      return html`<span class="indicador ok">✓ Hecha</span>`;
    }
    if (this.estado === 'en-progreso') {
      return html`<span class="indicador progreso">◐ En progreso</span>`;
    }
    return html`<span class="indicador pendiente">○ Pendiente</span>`;
  }

  render() {
    return html`
      <article>
        <h3>${this.titulo}</h3>
        ${this.renderIndicadorEstado()}
      </article>
    `;
  }
}

Aquest patró —un mètode renderAlgo() que la mateixa classe crida des de render()— és extremadament habitual al codi Lit real, inclòs a la documentació oficial i en projectes grans. Permet utilitzar sentències completes de JavaScript (if, switch, bucles, variables intermèdies amb const) que no encaixarien directament dins d'un ${}, ja que allà només s'admeten expressions, com es va explicar a la lliçó anterior. L'únic requisit és que el mètode, igual que el mateix render(), acabi retornant un valor vàlid per interpolar: una plantilla html, text, un número, o null/undefined/false si no cal mostrar res.

  1. Compte amb els "falsy" en utilitzar &&

El patró condició && html\...`vist a l'apartat 3 amaga una trampa clàssica de JavaScript que convé conèixer. L'operador&&no comprova estrictament si la condició éstrue; comprova si és "vertadera" en el sentit ampli de JavaScript (el que es coneix com "truthy"), i hi ha diversos valors que JavaScript considera "falsy" a més de false: 0, ''(cadena buida),null, undefinediNaN`.

El problema apareix quan la condició és un número que pot vàlidament valer 0:

render() {
  return html`
    <article>
      <h3>${this.titulo}</h3>
      ${this.numeroDeComentarios && html`<p>${this.numeroDeComentarios} comentarios</p>`}
    </article>
  `;
}

Si this.numeroDeComentarios val 0, l'expressió 0 && html\...`s'avalua com0(no com la plantilla), i aquí hi ha la trampa: Lit sí que renderitza el número0com a contingut de text, així que a la pantalla apareixerà literalment un0` solt, en lloc de no mostrar res. La solució habitual és forçar una comparació explícita que produeixi un booleà real:

${this.numeroDeComentarios > 0 && html`<p>${this.numeroDeComentarios} comentarios</p>`}

Aquesta regla general convé recordar-la sempre que s'utilitzi && per a renderitzat condicional: si la condició és un número o una cadena que podria vàlidament ser 0 o '', cal convertir-la explícitament a un booleà (amb una comparació com > 0, o amb !!valor) abans d'utilitzar-la amb &&.

  1. La directiva when: una menció de passada

Lit inclou, entre el seu catàleg de directives incorporades, una anomenada when que expressa d'una manera una mica més explícita la mateixa idea que un operador ternari:

import { when } from 'lit/directives/when.js';

render() {
  return html`
    ${when(
      this.completada,
      () => html`<span>✓ Finalizada</span>`,
      () => html`<span>○ Pendiente</span>`
    )}
  `;
}

when rep la condició, una funció que produeix la plantilla per al cas vertader, i opcionalment una altra funció per al cas fals. El seu comportament, a la pràctica, és molt semblant al d'un operador ternari amb plantilles aniuades; la diferència principal és que les branques es passen com a funcions (el que retarda la seva execució fins que realment es necessiten) i que, per a qui llegeix el codi, deixa més explícita la intenció de "renderitzat condicional" com a concepte, davant d'un ternari que també podria estar seleccionant un simple valor no relacionat amb plantilles.

Aquesta directiva es menciona aquí només perquè la reconeguis si la trobes a la documentació oficial o en projectes de tercers; l'estudi de les directives de Lit en general —què són, com funcionen per dins i quan aporten valor davant JavaScript "a pèl"— és el contingut del mòdul 7, "Directives i Funcionalitats Avançades de Plantilles". Durant la resta d'aquest curs, i en particular en aquest mòdul, se seguirà utilitzant JavaScript estàndard (ternaris, &&, funcions auxiliars) com a tècnica principal, precisament perquè no requereix importar res addicional i demostra que el renderitzat condicional a Lit no depèn de cap funcionalitat especial.

  1. Aplicant-ho a <task-card>: insígnia segons l'estat

Amb les tècniques anteriors ja es pot donar a <task-card> una insígnia d'estat que canviï el seu aspecte i el seu text segons la tasca estigui pendent, en progrés o feta. S'utilitzarà el patró de funció auxiliar de l'apartat 4, per ser el més llegible quan hi ha més de dues alternatives:

import { LitElement, html } from 'lit';

class TaskCard extends LitElement {
  constructor() {
    super();
    this.titulo = 'Preparar la demo del sprint';
    this.estado = 'en-progreso'; // 'pendiente' | 'en-progreso' | 'hecha'
    this.urgente = false;
  }

  renderInsigniaEstado() {
    if (this.estado === 'hecha') {
      return html`<span class="insignia insignia--hecha">✓ Hecha</span>`;
    }
    if (this.estado === 'en-progreso') {
      return html`<span class="insignia insignia--progreso">◐ En progreso</span>`;
    }
    return html`<span class="insignia insignia--pendiente">○ Pendiente</span>`;
  }

  render() {
    return html`
      <article>
        <h3>${this.titulo}</h3>
        ${this.renderInsigniaEstado()}
        ${this.urgente && html`<p class="aviso">⚠ Urgente</p>`}
      </article>
    `;
  }
}

customElements.define('task-card', TaskCard);

Aquest component combina les tres tècniques vistes a la lliçó: una funció auxiliar (renderInsigniaEstado) que encapsula una lògica de tres branques mitjançant if normals (impossible d'expressar directament dins d'un únic ${}), i el patró && per mostrar l'avís d'urgència només quan correspon. Fixa't que les classes CSS (insignia--hecha, insignia--progreso...) s'interpolen aquí només com a referència de noms; la seva definició visual real —com es veuen aquests colors i icones— és contingut del mòdul 4, "Estils en Components Lit". De moment, sense aquests estils, la insígnia es veurà com a text sense format especial, i això és exactament l'esperat en aquest punt del curs.

Errors Comuns i Consells

  • Utilitzar && amb condicions numèriques sense convertir a booleà: com s'ha vist a l'apartat 5, cantidad && html\...`pot mostrar un0solt a pantalla sicantidad val zero. Convé forçar sempre una comparació explícita (cantidad > 0`) en aquests casos.
  • Aniuar massa ternaris seguits: encadenar diversos ternaris (a ? x : b ? y : c ? z : w) per representar més de dues alternatives és difícil de llegir. En quant hi hagi tres o més branques, és preferible extreure la lògica a una funció auxiliar amb if/switch, com es va fer a l'apartat 7.
  • Oblidar que retornar una cadena buida '' en una branca no és el mateix que no renderitzar res: encara que el resultat visual sigui el mateix (no apareix text), retornar '' continua inserint un node de text buit al DOM, mentre que retornar null, undefined o false fa que Lit no inserti res en absolut. A la pràctica aquesta diferència rarament importa, però convé conèixer-la per no sorprendre's en inspeccionar el DOM.
  • Repetir la mateixa condició diverses vegades a la plantilla: si necessites comprovar this.estado === 'hecha' en diversos llocs d'una plantilla llarga, és un senyal que convé extreure aquesta lògica a una funció auxiliar o a una variable local calculada al principi de render(), en lloc de repetir la comparació.

Exercicis

  1. Afegeix a la funció renderInsigniaEstado() un quart estat possible, 'bloqueada', que mostri una insígnia amb el text "⛔ Bloqueada" i la classe insignia--bloqueada.
  2. Utilitzant el patró && amb la correcció de l'apartat 5, afegeix a <task-card> un camp this.numeroDeComentarios (inicialitza'l a 0) i mostra un paràgraf "N comentarios" només quan aquest número sigui més gran que zero. Comprova manualment, canviant el valor des del constructor, que amb 0 no apareix cap "0" solt a pantalla.
  3. Reescriu la insígnia d'estat de l'apartat 7 utilitzant la directiva when mencionada a l'apartat 6, consultant la seva signatura exacta a la documentació oficial de Lit (lit/directives/when.js), només amb finalitats de pràctica de lectura de documentació (no cal integrar-la a la resta del curs).

Solucions

renderInsigniaEstado() {
  if (this.estado === 'hecha') {
    return html`<span class="insignia insignia--hecha">✓ Hecha</span>`;
  }
  if (this.estado === 'en-progreso') {
    return html`<span class="insignia insignia--progreso">◐ En progreso</span>`;
  }
  if (this.estado === 'bloqueada') {
    return html`<span class="insignia insignia--bloqueada">⛔ Bloqueada</span>`;
  }
  return html`<span class="insignia insignia--pendiente">○ Pendiente</span>`;
}
constructor() {
  super();
  // ...
  this.numeroDeComentarios = 0;
}

render() {
  return html`
    <article>
      <h3>${this.titulo}</h3>
      ${this.renderInsigniaEstado()}
      ${this.numeroDeComentarios > 0
        ? html`<p>${this.numeroDeComentarios} comentarios</p>`
        : ''}
    </article>
  `;
}

Amb this.numeroDeComentarios a 0, la condició this.numeroDeComentarios > 0 és false, així que no es mostra cap paràgraf ni cap "0" solt.

import { when } from 'lit/directives/when.js';

render() {
  return html`
    <article>
      <h3>${this.titulo}</h3>
      ${when(
        this.estado === 'hecha',
        () => html`<span class="insignia insignia--hecha">✓ Hecha</span>`,
        () => html`<span class="insignia insignia--pendiente">○ Pendiente / en progreso</span>`
      )}
    </article>
  `;
}

Aquesta solució es simplifica a només dues branques amb finalitats de pràctica; una rèplica exacta de les quatre branques de l'apartat 1 requeriria aniuar diverses crides a when, el que il·lustra precisament per què, amb més de dues alternatives, se sol preferir una funció auxiliar amb if/switch en lloc d'aniuar directives.

Conclusió

En aquesta lliçó has vist que el renderitzat condicional a Lit no requereix cap sintaxi especial: es basa directament en operadors estàndard de JavaScript, principalment l'operador ternari per triar entre dues alternatives i l'operador && per mostrar o amagar contingut sense alternativa, amb la cura de convertir explícitament a booleà les condicions que puguin valer 0 o cadena buida. També has aprés a extreure lògica condicional més complexa a funcions auxiliars dins de la mateixa classe, i has conegut de passada la directiva when, el seu estudi complet arribarà al mòdul 7. Amb tot això, <task-card> ja mostra una insígnia d'estat diferent segons la tasca estigui pendent, en progrés o feta, a més d'un avís condicional d'urgència.

A la següent lliçó, "Renderizado de Listas", faràs un pas més: en lloc de mostrar una única tasca, aprendràs a recórrer un array complet de tasques amb Array.map dins d'una plantilla, i utilitzaràs aquesta tècnica per construir <task-list>, el primer component de TaskFlow capaç de renderitzar diverses targetes <task-card> a partir d'una col·lecció de dades.

Curs de Lit

Mòdul 1: Introducció a Lit i Web Components

Mòdul 2: Plantilles Reactives i Renderitzat

Mòdul 3: Propietats i Estat Reactiu

Mòdul 4: Estils en Components Lit

Mòdul 5: Esdeveniments i Comunicació entre Components

Mòdul 6: Cicle de Vida i Comportament Avançat

Mòdul 7: Directives i Funcionalitats Avançades de Plantilles

Mòdul 8: Integració, Interoperabilitat i Desplegament

Mòdul 9: Proves i Bones Pràctiques

Mòdul 10: Projecte: Construint TaskFlow

© Copyright 2026. Tots els drets reservats