HTL Tutorial #9: data-sly-template e data-sly-call - Template Riutilizzabili

HTL Tutorial #9: data-sly-template e data-sly-call - Template Riutilizzabili

Cos'è un Template HTL?

Un template è un blocco di markup riutilizzabile che puoi richiamare multiplevvolte con parametri diversi.

Pensa ai template come funzioni in programmazione!

Sintassi

Definire un Template

<sly data-sly-template.nomeTemplate="${@ param1, param2}">
  <!-- markup del template -->
  ${param1}
  ${param2}
</sly>

Richiamare un Template

<sly data-sly-call="${nomeTemplate @ param1='valore1', param2='valore2'}"></sly>

Esempio Base

<!-- Definizione template -->
<sly data-sly-template.userCard="${@ name, email}">
  <div class="user-card">
    <h3>${name}</h3>
    <p>${email}</p>
  </div>
</sly>

<!-- Uso del template -->
<sly data-sly-call="${userCard @ name='Mario', email='mario@example.com'}"></sly>
<sly data-sly-call="${userCard @ name='Luigi', email='luigi@example.com'}"></sly>

Output:

<div class="user-card">
  <h3>Mario</h3>
  <p>mario@example.com</p>
</div>
<div class="user-card">
  <h3>Luigi</h3>
  <p>luigi@example.com</p>
</div>

Perché Usare Template?

1. DRY (Don't Repeat Yourself)

Senza template (ripetitivo):

<div class="alert alert-success">
  <strong>Successo!</strong> Operazione completata
</div>

<div class="alert alert-danger">
  <strong>Errore!</strong> Qualcosa è andato storto
</div>

<div class="alert alert-warning">
  <strong>Attenzione!</strong> Controlla i dati
</div>

Con template (riutilizzabile):

<!-- Definizione -->
<sly data-sly-template.alert="${@ type, title, message}">
  <div class="alert alert-${type}">
    <strong>${title}</strong> ${message}
  </div>
</sly>

<!-- Uso -->
<sly data-sly-call="${alert @ type='success', title='Successo!', message='Operazione completata'}"></sly>
<sly data-sly-call="${alert @ type='danger', title='Errore!', message='Qualcosa è andato storto'}"></sly>
<sly data-sly-call="${alert @ type='warning', title='Attenzione!', message='Controlla i dati'}"></sly>

2. Manutenibilità

Modifichi il template una volta, il cambiamento si applica ovunque!

3. Consistenza

Tutti gli usi del template hanno la stessa struttura.

Template con Liste

Puoi combinare template con data-sly-list:

<!-- Template per singolo prodotto -->
<sly data-sly-template.productCard="${@ product}">
  <div class="product-card">
    <img src="${product.image}" alt="${product.name}">
    <h3>${product.name}</h3>
    <p class="price">${product.price}</p>
    <button>Aggiungi al carrello</button>
  </div>
</sly>

<!-- Uso con lista -->
<div data-sly-use.model="com.example.ProductsModel" class="product-grid">
  <sly data-sly-list.product="${model.products}"
       data-sly-call="${productCard @ product=product}"></sly>
</div>

Template Condizionali

<!-- Template per diversi tipi di badge -->
<sly data-sly-template.badge="${@ type, text}">
  <span class="badge badge-${type}">
    ${text}
  </span>
</sly>

<!-- Uso condizionale -->
<div data-sly-use.user="com.example.UserModel">
  <sly data-sly-test="${user.isPremium}"
       data-sly-call="${badge @ type='gold', text='Premium'}"></sly>

  <sly data-sly-test="${user.isModerator}"
       data-sly-call="${badge @ type='blue', text='Moderatore'}"></sly>

  <sly data-sly-test="${user.isAdmin}"
       data-sly-call="${badge @ type='red', text='Admin'}"></sly>
</div>

Template Annidati

Puoi definire template dentro template:

<!-- Template principale -->
<sly data-sly-template.articleCard="${@ article}">
  <!-- Template interno per meta info -->
  <sly data-sly-template.metaInfo="${@ date, author}">
    <div class="meta">
      <time>${date}</time>
      <span></span>
      <span>${author}</span>
    </div>
  </sly>

  <!-- Usa template -->
  <article class="card">
    <h3>${article.title}</h3>
    <p>${article.excerpt}</p>
    <sly data-sly-call="${metaInfo @ date=article.date, author=article.author}"></sly>
  </article>
</sly>

<!-- Uso -->
<sly data-sly-call="${articleCard @ article=myArticle}"></sly>

Template in File Esterni

Puoi definire template in file separati e includerli:

File: /apps/mysite/components/templates/cards.html

<sly data-sly-template.userCard="${@ user}">
  <div class="user-card">
    <h3>${user.name}</h3>
    <p>${user.email}</p>
  </div>
</sly>

<sly data-sly-template.productCard="${@ product}">
  <div class="product-card">
    <h3>${product.name}</h3>
    <p>${product.price}</p>
  </div>
</sly>

Uso nel componente:

<div data-sly-use.templates="/apps/mysite/components/templates/cards.html">
  <sly data-sly-call="${templates.userCard @ user=currentUser}"></sly>
  <sly data-sly-call="${templates.productCard @ product=featuredProduct}"></sly>
</div>

Pattern Comuni

1. Button Component

<sly data-sly-template.button="${@ text, url, style}">
  <a href="${url}" class="btn btn-${style || 'primary'}">
    ${text}
  </a>
</sly>

<!-- Uso -->
<sly data-sly-call="${button @ text='Scopri di più', url='/about', style='secondary'}"></sly>
<sly data-sly-call="${button @ text='Contattaci', url='/contact'}"></sly>

2. Icon con Testo

<sly data-sly-template.iconText="${@ icon, text}">
  <span class="icon-text">
    <i class="icon-${icon}"></i>
    <span>${text}</span>
  </span>
</sly>

<!-- Uso -->
<sly data-sly-call="${iconText @ icon='calendar', text='15 Gen 2025'}"></sly>
<sly data-sly-call="${iconText @ icon='user', text='Mario Rossi'}"></sly>
<sly data-sly-call="${iconText @ icon='tag', text='Tutorial'}"></sly>

3. Social Share Buttons

<sly data-sly-template.socialButton="${@ network, url, title}">
  <a href="https://${network}.com/share?url=${url}&title=${title}"
     class="social-btn social-${network}"
     target="_blank"
     rel="noopener">
    <i class="icon-${network}"></i>
    Condividi su ${network}
  </a>
</sly>

<!-- Uso -->
<div class="social-share">
  <sly data-sly-call="${socialButton @ network='facebook', url=currentPage.path, title=currentPage.title}"></sly>
  <sly data-sly-call="${socialButton @ network='twitter', url=currentPage.path, title=currentPage.title}"></sly>
  <sly data-sly-call="${socialButton @ network='linkedin', url=currentPage.path, title=currentPage.title}"></sly>
</div>

Esempio Completo: Card System

<!-- ============================================
     DEFINIZIONE TEMPLATE
     ============================================ -->

<!-- Template base card -->
<sly data-sly-template.baseCard="${@ title, content, footer}">
  <div class="card">
    <div class="card-header">
      <h3>${title}</h3>
    </div>
    <div class="card-body">
      ${content}
    </div>
    <div data-sly-test="${footer}" class="card-footer">
      ${footer}
    </div>
  </div>
</sly>

<!-- Template per card utente -->
<sly data-sly-template.userCard="${@ user}">
  <sly data-sly-call="${baseCard @
    title=user.name,
    content=user.bio,
    footer=user.email}">
  </sly>
</sly>

<!-- Template per card prodotto -->
<sly data-sly-template.productCard="${@ product}">
  <sly data-sly-call="${baseCard @
    title=product.name,
    content=product.description,
    footer='€ ' + product.price}">
  </sly>
</sly>

<!-- ============================================
     USO TEMPLATE
     ============================================ -->

<div data-sly-use.model="com.example.DashboardModel">
  <!-- Sezione utenti -->
  <section>
    <h2>Utenti</h2>
    <div class="grid">
      <sly data-sly-list.user="${model.users}"
           data-sly-call="${userCard @ user=user}"></sly>
    </div>
  </section>

  <!-- Sezione prodotti -->
  <section>
    <h2>Prodotti in Evidenza</h2>
    <div class="grid">
      <sly data-sly-list.product="${model.products}"
           data-sly-call="${productCard @ product=product}"></sly>
    </div>
  </section>
</div>

Parametri Opzionali

Puoi avere parametri opzionali usando l'operatore OR:

<sly data-sly-template.alert="${@ message, type, icon}">
  <div class="alert alert-${type || 'info'}">
    <i data-sly-test="${icon}" class="icon-${icon}"></i>
    ${message}
  </div>
</sly>

<!-- Con tutti i parametri -->
<sly data-sly-call="${alert @ message='Successo!', type='success', icon='check'}"></sly>

<!-- Con parametri opzionali omessi -->
<sly data-sly-call="${alert @ message='Info generica'}"></sly>
<!-- Usa type='info' e nessun icon -->

Best Practice

  1. Usa <sly> per template: non aggiunge markup inutile
  2. Nomi descrittivi: userCard, alertBox invece di template1
  3. Documentazione: commenta i parametri attesi
  4. File esterni per template condivisi: /apps/mysite/components/templates/
  5. Parametri con default: usa ${param || 'default'}
  6. Non esagerare: template troppo complessi sono difficili da manutenere
  7. Scope limitato: definisci template vicino al loro uso

Template vs Include

Feature Template Include
Parametri ✓ Supportati ❌ No
Riutilizzo ✓ Multipli call ✓ Include una volta
Scope Locale al file Nuovo scope
Performance ✓ Leggero Include file separato
Use Case Pattern ripetuti Componenti comuni

Quando usare cosa:

  • Template: Pattern ripetuti nello stesso file (cards, buttons, badges)
  • Include: Componenti completi (header, footer, navigation)

Errori Comuni

❌ Parametri non dichiarati

<!-- SBAGLIATO - 'name' non dichiarato -->
<sly data-sly-template.user="${@ email}">
  ${name} <!-- ERRORE! -->
</sly>

<!-- CORRETTO -->
<sly data-sly-template.user="${@ name, email}">
  ${name}
</sly>

❌ Call prima della definizione

<!-- SBAGLIATO - template non ancora definito -->
<sly data-sly-call="${myTemplate}"></sly>

<sly data-sly-template.myTemplate="${@}">
  <!-- ... -->
</sly>

<!-- CORRETTO - definisci prima -->
<sly data-sly-template.myTemplate="${@}">
  <!-- ... -->
</sly>

<sly data-sly-call="${myTemplate}"></sly>

❌ Template troppo complessi

<!-- SBAGLIATO - troppo complesso -->
<sly data-sly-template.megaTemplate="${@ a, b, c, d, e, f, g}">
  <!-- 100 righe di codice -->
</sly>

<!-- CORRETTO - dividi in più template -->
<sly data-sly-template.header="${@ title}">...</sly>
<sly data-sly-template.body="${@ content}">...</sly>
<sly data-sly-template.footer="${@ meta}">...</sly>

Esercizi Pratici

  1. Alert System: Template per alert (success, error, warning, info)
  2. Navigation Menu: Template per menu items con icone e badge
  3. Table Rows: Template riutilizzabile per righe tabella
  4. Media Object: Template per oggetti con immagine + testo

Prossima Lezione

Nella prossima lezione vedremo data-sly-attribute per manipolare attributi HTML dinamicamente.


Lezione #9 della serie HTL Tutorial. ← Lezione precedente | Lezione successiva →