HTL Tutorial #12: data-sly-unwrap - Rimuovere Wrapper HTML

HTL Tutorial #12: data-sly-unwrap - Rimuovere Wrapper HTML

Cos'è data-sly-unwrap?

data-sly-unwrap rimuove l'elemento HTML ma mantiene il suo contenuto.

Utile per eliminare wrapper non necessari nell'output finale.

Sintassi

<elemento data-sly-unwrap>
  Contenuto mantenuto
</elemento>

Output:

Contenuto mantenuto

L'elemento <elemento> viene rimosso!

Esempio Base

<div data-sly-unwrap>
  <p>Questo paragrafo rimane</p>
</div>

Output:

<p>Questo paragrafo rimane</p>

Il <div> è stato rimosso, il <p> rimane.

Perché Usarlo?

1. Wrapper Tecnici in Edit Mode

In AEM, i componenti hanno spesso wrapper per l'authoring che non servono in publish:

<div data-sly-unwrap="${wcmmode.disabled}">
  <p>${properties.text}</p>
</div>

In Edit Mode (wcmmode.disabled = false):

<div>
  <p>Testo del componente</p>
</div>

In Publish Mode (wcmmode.disabled = true):

<p>Testo del componente</p>

Il wrapper <div> viene rimosso in publish!

2. Markup Pulito

Evita <div> inutili nel DOM:

<!-- Componente -->
<div data-sly-unwrap="${!properties.showContainer}">
  <h2>${properties.title}</h2>
  <p>${properties.content}</p>
</div>

Se showContainer = false:

<h2>Titolo</h2>
<p>Contenuto</p>

Se showContainer = true:

<div>
  <h2>Titolo</h2>
  <p>Contenuto</p>
</div>

3. Conditional Wrapper

<div data-sly-unwrap="${!properties.addWrapper}"
     class="card">
  <h3>${properties.title}</h3>
  <p>${properties.text}</p>
</div>

L'autore decide se aggiungere il wrapper .card o no!

data-sly-unwrap Condizionale

data-sly-unwrap accetta un'espressione booleana:

<elemento data-sly-unwrap="${condizione}">
  Contenuto
</elemento>
  • true: Rimuove elemento
  • false: Mantiene elemento

Esempio con WCM Mode

<!-- Wrapper solo in edit mode -->
<sly data-sly-unwrap="${wcmmode.disabled}">
  <div class="component-wrapper">
    <div data-sly-resource="${'parsys' @ resourceType='wcm/foundation/components/parsys'}"></div>
  </div>
</sly>

Pattern Comuni

1. Lista Condizionale

<ul data-sly-unwrap="${properties.inline}">
  <li data-sly-list.item="${properties.items}">
    ${item}
  </li>
</ul>

Se inline = false (lista normale):

<ul>
  <li>Item 1</li>
  <li>Item 2</li>
</ul>

Se inline = true (lista inline, senza <ul>):

<li>Item 1</li>
<li>Item 2</li>

2. Wrapper Solo per Multipli Elementi

<div data-sly-unwrap="${itemList.count <= 1}">
  <div data-sly-list.item="${properties.items}">
    ${item}
  </div>
</div>

1 elemento (unwrap):

<div>Singolo item</div>

Multipli elementi (mantiene wrapper):

<div>
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</div>

3. Semantic HTML Condizionale

<section data-sly-unwrap="${!properties.isSection}">
  <h2>${properties.title}</h2>
  <p>${properties.content}</p>
</section>

L'autore decide se usare <section> semantico o solo contenuto.

Element <sly>

HTL fornisce un elemento speciale <sly> che è sempre unwrapped automaticamente:

<sly>
  <p>Contenuto</p>
</sly>

Output:

<p>Contenuto</p>

<sly> è perfetto per:

  • Template definitions
  • Logica HTL senza output
<!-- Template senza wrapper -->
<sly data-sly-template.myTemplate="${@ text}">
  <p>${text}</p>
</sly>

<!-- Lista senza wrapper -->
<sly data-sly-list.item="${items}">
  <div>${item}</div>
</sly>

Differenza <sly> vs data-sly-unwrap

Feature <sly> data-sly-unwrap
Unwrap Sempre Condizionale
Uso Wrapper logico Wrapper condizionale
Espressione No Sì (true/false)
Attributi Non nell'output Rimossi con elemento
<!-- SEMPRE rimosso -->
<sly>
  Contenuto
</sly>

<!-- CONDIZIONALMENTE rimosso -->
<div data-sly-unwrap="${condition}">
  Contenuto
</div>

Esempio Completo: Card Component

<div data-sly-use.card="com.example.CardModel"
     data-sly-unwrap="${card.unwrapContainer}"
     class="card ${card.styleClass}">

  <!-- Header condizionale -->
  <div data-sly-unwrap="${!card.hasHeader}" class="card-header">
    <h3>${card.title}</h3>
  </div>

  <!-- Body -->
  <div class="card-body">
    <p>${card.content}</p>
  </div>

  <!-- Footer condizionale -->
  <div data-sly-unwrap="${!card.hasFooter}" class="card-footer">
    <a href="${card.linkUrl}">${card.linkText}</a>
  </div>
</div>

Model:

public class CardModel {

    @ValueMapValue
    private String title;

    @ValueMapValue
    private String content;

    @ValueMapValue
    private String linkUrl;

    @ValueMapValue
    private String linkText;

    @ValueMapValue
    private boolean removeContainer;

    @ValueMapValue
    private String styleClass;

    public boolean getHasHeader() {
        return title != null && !title.isEmpty();
    }

    public boolean getHasFooter() {
        return linkUrl != null && !linkUrl.isEmpty();
    }

    public boolean getUnwrapContainer() {
        return removeContainer;
    }

    // Altri getters...
}

Output (con container, senza footer):

<div class="card featured">
  <div class="card-header">
    <h3>Titolo Card</h3>
  </div>
  <div class="card-body">
    <p>Contenuto della card</p>
  </div>
</div>

Output (senza container, con footer):

<div class="card-header">
  <h3>Titolo Card</h3>
</div>
<div class="card-body">
  <p>Contenuto della card</p>
</div>
<div class="card-footer">
  <a href="/link">Leggi di più</a>
</div>

Best Practice

  1. Usa <sly> per wrapper sempre rimossi
  2. data-sly-unwrap per condizioni: wrapper dinamici
  3. Naming chiaro: variabili come unwrapContainer, removeWrapper
  4. Semantic HTML: Mantieni markup semantico quando possibile
  5. Accessibilità: Non rimuovere elementi necessari per screen readers
  6. Testing: Testa entrambi i casi (wrapped/unwrapped)

Combinazione con Altri Statement

Con data-sly-test

<!-- Mostra solo se c'è contenuto, senza wrapper -->
<div data-sly-test="${properties.content}"
     data-sly-unwrap>
  ${properties.content}
</div>

Con data-sly-list

<div data-sly-unwrap="${properties.removeWrapper}">
  <div data-sly-list.item="${properties.items}">
    ${item}
  </div>
</div>

Con data-sly-element

<!-- Cambia tag O rimuovi completamente -->
<div data-sly-element="${properties.tag}"
     data-sly-unwrap="${!properties.tag}">
  Contenuto
</div>

Errori Comuni

❌ Unwrap con attributi necessari

<!-- SBAGLIATO - perde l'id! -->
<div id="important" data-sly-unwrap>
  Contenuto
</div>

<!-- CORRETTO - unwrap solo se id non serve -->
<div id="${properties.id}"
     data-sly-unwrap="${!properties.id}">
  Contenuto
</div>

❌ Dimenticare condizione

<!-- Sempre unwrapped (come <sly>) -->
<div data-sly-unwrap>

<!-- Condizionale -->
<div data-sly-unwrap="${condition}">

Esercizi Pratici

  1. Conditional Container: Componente con wrapper opzionale
  2. Edit/Publish Mode: Wrapper solo in edit
  3. List Wrapper: Lista con <ul> condizionale
  4. Semantic Sections: Section tag opzionale

Prossima Lezione

Nella prossima lezione vedremo data-sly-include e data-sly-resource per includere altri template e componenti.


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