HTL Tutorial #7: data-sly-list - Iterazione su Array e Collezioni
HTL Tutorial #7: data-sly-list - Iterazione su Array e Collezioni
Cos'è data-sly-list?
data-sly-list itera su array, liste o collezioni e ripete l'elemento per ogni item.
Sintassi Base
<elemento data-sly-list="${array}">
<!-- Questo elemento viene ripetuto per ogni item -->
</elemento>Con Nome Variabile
<elemento data-sly-list.nomeItem="${array}">
${nomeItem}
</elemento>Esempio Semplice
<!-- Array di stringhe -->
<ul data-sly-list.tag="${properties.tags}">
<li>${tag}</li>
</ul>Input: properties.tags = ["HTML", "CSS", "JavaScript"]
Output:
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>Senza Nome Variabile
Se non specifichi un nome, HTL usa automaticamente item:
<!-- Senza nome -->
<ul data-sly-list="${properties.tags}">
<li>${item}</li>
</ul>
<!-- Equivalente a -->
<ul data-sly-list.item="${properties.tags}">
<li>${item}</li>
</ul>Iterare su Array di Oggetti
Esempio: Lista Prodotti
<div class="products" data-sly-use.model="com.example.ProductsModel">
<div data-sly-list.product="${model.products}" class="product-card">
<h3>${product.name}</h3>
<p class="price">€ ${product.price}</p>
<p>${product.description}</p>
<button>Aggiungi al carrello</button>
</div>
</div>Java Model (esempio):
public class ProductsModel {
public List<Product> getProducts() {
return Arrays.asList(
new Product("Laptop", 999.00, "Laptop potente"),
new Product("Mouse", 29.99, "Mouse wireless"),
new Product("Tastiera", 79.99, "Tastiera meccanica")
);
}
}Output:
<div class="products">
<div class="product-card">
<h3>Laptop</h3>
<p class="price">€ 999.0</p>
<p>Laptop potente</p>
<button>Aggiungi al carrello</button>
</div>
<div class="product-card">
<h3>Mouse</h3>
<p class="price">€ 29.99</p>
<p>Mouse wireless</p>
<button>Aggiungi al carrello</button>
</div>
<div class="product-card">
<h3>Tastiera</h3>
<p class="price">€ 79.99</p>
<p>Tastiera meccanica</p>
<button>Aggiungi al carrello</button>
</div>
</div>Variabile itemList
HTL fornisce automaticamente la variabile itemList con informazioni sull'iterazione:
<ul data-sly-list.item="${properties.items}">
<li>
${item}
(${itemList.index + 1}/${itemList.count})
</li>
</ul>Proprietà di itemList
| Proprietà | Descrizione | Tipo |
|---|---|---|
index |
Indice corrente (inizia da 0) | Number |
count |
Numero totale di elementi | Number |
first |
True se è il primo elemento | Boolean |
last |
True se è l'ultimo elemento | Boolean |
odd |
True se indice dispari | Boolean |
even |
True se indice pari | Boolean |
middle |
True se NON è primo né ultimo | Boolean |
Esempio completo:
<ul data-sly-list.item="${properties.navItems}">
<li class="${itemList.first ? 'first' : ''}
${itemList.last ? 'last' : ''}
${itemList.odd ? 'odd' : 'even'}">
${itemList.index + 1}. ${item.title}
</li>
</ul>Pattern Comuni
1. Lista con Indice
<ol data-sly-list.step="${properties.steps}">
<li>
<strong>Passo ${stepList.index + 1}:</strong>
${step}
</li>
</ol>2. Zebra Striping (Righe Alternate)
<table>
<tbody data-sly-list.row="${model.data}">
<tr class="${rowList.odd ? 'bg-light' : 'bg-white'}">
<td>${row.name}</td>
<td>${row.value}</td>
</tr>
</tbody>
</table>3. Primo e Ultimo Diversi
<nav>
<ul data-sly-list.page="${model.pages}">
<li>
<a href="${page.url}"
class="${pageList.first ? 'home-link' : ''}
${pageList.last ? 'last-link' : ''}">
${page.title}
</a>
</li>
</ul>
</nav>4. Separatori tra Elementi
<div class="breadcrumb">
<span data-sly-list.crumb="${model.breadcrumbs}">
<a href="${crumb.url}">${crumb.title}</a>
<span data-sly-test="${!crumbList.last}"> > </span>
</span>
</div>Output: Home > Products > Category > Item
5. Primi N Elementi
<!-- Mostra solo i primi 5 -->
<ul data-sly-list.item="${properties.items}">
<li data-sly-test="${itemList.index < 5}">
${item}
</li>
</ul>Liste Annidate
Puoi annidare data-sly-list per strutture complesse:
<div data-sly-use.nav="com.example.NavigationModel">
<!-- Menu principale -->
<nav>
<ul data-sly-list.section="${nav.sections}">
<li>
<h3>${section.title}</h3>
<!-- Sottomenu -->
<ul data-sly-list.item="${section.items}">
<li>
<a href="${item.url}">${item.title}</a>
</li>
</ul>
</li>
</ul>
</nav>
</div>Combinazione con data-sly-test
Lista Condizionale
<!-- Mostra lista solo se ha elementi -->
<ul data-sly-test="${properties.tags}"
data-sly-list.tag="${properties.tags}">
<li>${tag}</li>
</ul>
<!-- Messaggio se vuota -->
<p data-sly-test="${!properties.tags}">
Nessun tag disponibile
</p>Filtraggio Elementi
<ul data-sly-list.user="${model.users}">
<!-- Mostra solo utenti attivi -->
<li data-sly-test="${user.active}">
${user.name} (${user.email})
</li>
</ul>Esempi Pratici Completi
Esempio 1: Gallery Immagini
<div class="gallery" data-sly-use.gallery="com.example.GalleryModel">
<div class="grid">
<div data-sly-list.image="${gallery.images}" class="grid-item">
<img src="${image.url}"
alt="${image.alt}"
loading="${imageList.first ? 'eager' : 'lazy'}">
<div class="caption">
<h4>${image.title}</h4>
<p>${image.description}</p>
<small>Immagine ${imageList.index + 1} di ${imageList.count}</small>
</div>
</div>
</div>
</div>Esempio 2: Timeline Eventi
<div class="timeline" data-sly-use.events="com.example.EventsModel">
<div data-sly-list.event="${events.items}"
class="timeline-item ${eventList.odd ? 'left' : 'right'}">
<!-- Marker timeline -->
<div class="timeline-marker ${eventList.first ? 'first' : ''}
${eventList.last ? 'last' : ''}">
${eventList.index + 1}
</div>
<!-- Contenuto evento -->
<div class="timeline-content">
<h3>${event.title}</h3>
<time datetime="${event.date}">${event.formattedDate}</time>
<p>${event.description}</p>
<!-- Badge per primo evento -->
<span data-sly-test="${eventList.first}" class="badge-latest">
Ultimo evento
</span>
</div>
</div>
</div>Esempio 3: Table con Totale
<table data-sly-use.report="com.example.ReportModel">
<thead>
<tr>
<th>#</th>
<th>Descrizione</th>
<th>Quantità</th>
<th>Prezzo</th>
</tr>
</thead>
<tbody>
<tr data-sly-list.item="${report.items}">
<td>${itemList.index + 1}</td>
<td>${item.description}</td>
<td>${item.quantity}</td>
<td>€ ${item.price}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3"><strong>Totale</strong></td>
<td><strong>€ ${report.total}</strong></td>
</tr>
</tfoot>
</table>Esempio 4: Card Grid Responsive
<div class="card-grid" data-sly-use.blog="com.example.BlogModel">
<article data-sly-list.post="${blog.recentPosts}"
class="card ${postList.first ? 'featured' : ''}">
<!-- Immagine -->
<div class="card-image">
<img src="${post.thumbnail}"
alt="${post.title}"
loading="${postList.index < 3 ? 'eager' : 'lazy'}">
<!-- Badge Featured solo per il primo -->
<span data-sly-test="${postList.first}" class="badge-featured">
In Evidenza
</span>
</div>
<!-- Contenuto -->
<div class="card-body">
<h3>${post.title}</h3>
<p class="excerpt">${post.excerpt}</p>
<!-- Meta info -->
<div class="meta">
<time datetime="${post.date}">${post.formattedDate}</time>
<span class="dot">•</span>
<span>${post.readTime} min lettura</span>
</div>
<a href="${post.url}" class="btn">Leggi di più</a>
</div>
</article>
</div>data-sly-list vs data-sly-repeat
HTL ha due statement per iterazione:
data-sly-list: Più semplice, usaitemListdata-sly-repeat: Più dettagliato, vedremo nella prossima lezione
Per la maggior parte dei casi, data-sly-list è sufficiente!
Liste Vuote
Se l'array è vuoto/null, l'elemento NON viene renderizzato:
<ul data-sly-list.tag="${properties.tags}">
<li>${tag}</li>
</ul>
<!-- Se tags è vuoto: NESSUN output (nemmeno <ul>) -->Gestire liste vuote:
<div data-sly-test.hasTags="${properties.tags}">
<h3>Tags:</h3>
<ul data-sly-list.tag="${properties.tags}">
<li>${tag}</li>
</ul>
</div>
<p data-sly-test="${!hasTags}">
Nessun tag disponibile
</p>Best Practice
- Usa nomi variabili descrittivi:
product,user,imageinvece diitem - Sfrutta
itemList.first/lastper styling speciale - Combina con
data-sly-testper filtraggio - Lazy loading per immagini non immediate:
${!imageList.first} - Gestisci liste vuote con
data-sly-testseparato - Evita logica complessa nel loop - spostala nel Sling Model
Errori Comuni
❌ Modificare l'array durante l'iterazione
<!-- NON supportato - read-only! -->
<ul data-sly-list.item="${items}">
<li>${item}</li>
</ul>❌ Usare variabile fuori scope
<ul data-sly-list.tag="${properties.tags}">
<li>${tag}</li>
</ul>
${tag} <!-- ERRORE - fuori scope! -->Esercizi Pratici
- Navigation Menu: Lista con prima/ultima pagina diversa
- Product Grid: 3 colonne con righe zebrate
- Comments: Lista commenti con separatori
- FAQ Accordion: Domande/risposte con primi 3 elementi aperti di default
Prossima Lezione
Nella prossima lezione scopriremo data-sly-repeat, la versione avanzata di list con più informazioni di iterazione disponibili.
Lezione #7 della serie HTL Tutorial. ← Lezione precedente | Lezione successiva →