HTL Tutorial #8: data-sly-use - Caricare Logica Java e JavaScript
HTL Tutorial #8: data-sly-use - Caricare Logica Java e JavaScript
Cos'è data-sly-use?
data-sly-use carica logica esterna (Java o JavaScript) e la rende disponibile come variabile nel template HTL.
Principio chiave: La logica complessa appartiene a Java/JS, non al template HTL!
Sintassi Base
<div data-sly-use.varName="percorso.classe.Java">
${varName.property}
</div>Caricare Sling Model Java
1. Creare il Sling Model
package com.example.models;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
@Model(adaptables = Resource.class)
public class AuthorModel {
@ValueMapValue
private String name;
@ValueMapValue
private String bio;
@ValueMapValue
private String avatar;
// Getters
public String getName() {
return name;
}
public String getBio() {
return bio;
}
public String getAvatar() {
return avatar != null ? avatar : "/images/default-avatar.png";
}
// Logica aggiuntiva
public String getShortBio() {
if (bio != null && bio.length() > 100) {
return bio.substring(0, 100) + "...";
}
return bio;
}
public boolean hasBio() {
return bio != null && !bio.isEmpty();
}
}2. Usare nel Template HTL
<div data-sly-use.author="com.example.models.AuthorModel">
<!-- Accesso ai metodi del model -->
<h2>${author.name}</h2>
<img src="${author.avatar}" alt="${author.name}">
<!-- Metodo con logica -->
<p data-sly-test="${author.hasBio}">
${author.shortBio}
</p>
</div>Output:
<div>
<h2>Mario Rossi</h2>
<img src="/images/mario.jpg" alt="Mario Rossi">
<p>Sviluppatore AEM con 10 anni di esperienza...</p>
</div>Caricare Script JavaScript
1. Creare lo Script JS
File: /apps/mysite/components/author/author.js
"use strict";
use(function () {
var name = properties.get("name", "");
var bio = properties.get("bio", "");
return {
name: name,
bio: bio,
shortBio: bio.length > 100 ? bio.substring(0, 100) + "..." : bio,
hasBio: bio && bio.length > 0,
avatar: properties.get("avatar", "/images/default-avatar.png")
};
});2. Usare nel Template
<!-- Carica JS locale -->
<div data-sly-use.author="author.js">
<h2>${author.name}</h2>
<p>${author.shortBio}</p>
</div>Passare Parametri
Puoi passare parametri al model/script usando l'oggetto Options:
Sintassi
<div data-sly-use.model="${'com.example.Model' @ param1='value', param2=123}">
${model.result}
</div>Esempio Java
Model:
@Model(adaptables = Resource.class)
public class ProductModel {
@Inject
private Resource resource;
private String category;
private int maxResults;
@PostConstruct
protected void init() {
// Recupera parametri da Options
ValueMap props = resource.getValueMap();
category = props.get("category", String.class);
maxResults = props.get("maxResults", 10);
}
public List<Product> getProducts() {
// Usa parametri per filtrare
return productService.findByCategory(category, maxResults);
}
}HTL:
<div data-sly-use.products="${'com.example.ProductModel' @ category='electronics', maxResults=5}">
<ul data-sly-list.product="${products.products}">
<li>${product.name}</li>
</ul>
</div>Esempio JavaScript
Script products.js:
use(function () {
var category = this.category || "all";
var maxResults = this.maxResults || 10;
// Usa parametri
var products = getProductsByCategory(category, maxResults);
return {
products: products,
count: products.length
};
});HTL:
<div data-sly-use.data="${'products.js' @ category='books', maxResults=3}">
<p>${data.count} prodotti trovati</p>
</div>Scope delle Variabili
Le variabili create con data-sly-use sono disponibili:
- Nell'elemento e tutti i suoi figli
- Non fuori dall'elemento
<div data-sly-use.model="com.example.Model">
${model.title} <!-- OK -->
<p>${model.description}</p> <!-- OK -->
</div>
${model.title} <!-- ERRORE - fuori scope! -->Use Globale (Root Element)
Per rendere disponibile in tutto il template:
<div data-sly-use.page="com.example.PageModel">
<!-- Tutto il contenuto può usare 'page' -->
<header>
<h1>${page.title}</h1>
</header>
<main>
<p>${page.content}</p>
</main>
<footer>
<p>${page.author}</p>
</footer>
</div>Pattern Comuni
1. Component Model
Struttura tipica componente AEM:
/apps/mysite/components/article/
├── article.html (template HTL)
├── ArticleModel.java (Sling Model)
├── _cq_dialog.xml (dialog)
└── .content.xml (metadata)article.html:
<article data-sly-use.model="com.mysite.models.ArticleModel">
<header>
<h1>${model.title}</h1>
<time datetime="${model.publishDate}">${model.formattedDate}</time>
<p class="author">di ${model.authorName}</p>
</header>
<div class="content">
${model.content }
</div>
<footer>
<ul class="tags" data-sly-list.tag="${model.tags}">
<li>${tag}</li>
</ul>
</footer>
</article>2. Service Injection
Inject AEM services nel Model:
@Model(adaptables = {Resource.class, SlingHttpServletRequest.class})
public class NavigationModel {
@Inject
private PageManager pageManager;
@Inject
private Page currentPage;
@SlingObject
private ResourceResolver resourceResolver;
public List<NavigationItem> getNavigationItems() {
// Usa pageManager per navigare
Page rootPage = currentPage.getAbsoluteParent(2);
List<NavigationItem> items = new ArrayList<>();
Iterator<Page> children = rootPage.listChildren();
while (children.hasNext()) {
Page child = children.next();
if (!child.isHideInNav()) {
items.add(new NavigationItem(child.getTitle(), child.getPath()));
}
}
return items;
}
}HTL:
<nav data-sly-use.nav="com.mysite.models.NavigationModel">
<ul>
<li data-sly-list.item="${nav.navigationItems}">
<a href="${item.path}">${item.title}</a>
</li>
</ul>
</nav>3. Multipli data-sly-use
Puoi usare multipli models nello stesso template:
<div data-sly-use.page="com.example.PageModel"
data-sly-use.user="com.example.UserModel"
data-sly-use.config="com.example.ConfigModel">
<h1>${page.title}</h1>
<p>Benvenuto, ${user.name}</p>
<p>Lingua: ${config.locale}</p>
</div>Differenze Java vs JavaScript
| Aspetto | Java (Sling Model) | JavaScript |
|---|---|---|
| Performance | ✓ Più veloce (compilato) | Più lento (interpretato) |
| Type Safety | ✓ Fortemente tipizzato | Tipizzazione debole |
| IDE Support | ✓ Ottimo (autocomplete, refactoring) | Limitato |
| Testing | ✓ JUnit test completi | Più difficile |
| Injection | ✓ @Inject, @ValueMapValue | Limitato |
| Services | ✓ Accesso a tutti i service AEM | Solo resource access |
| Best For | Logica complessa, enterprise | Script semplici, prototipi |
Raccomandazione: Usa Java Sling Models per progetti enterprise!
Esempio Completo: Blog Post
Java Model
@Model(adaptables = {Resource.class, SlingHttpServletRequest.class})
public class BlogPostModel {
@Inject
private Page currentPage;
@ValueMapValue
private String title;
@ValueMapValue
private Calendar publishDate;
@ValueMapValue
private String[] tags;
@ValueMapValue
private String content;
public String getTitle() {
return title != null ? title : currentPage.getTitle();
}
public String getFormattedDate() {
if (publishDate == null) return "";
SimpleDateFormat sdf = new SimpleDateFormat("dd MMMM yyyy", Locale.ITALIAN);
return sdf.format(publishDate.getTime());
}
public List<String> getTags() {
return tags != null ? Arrays.asList(tags) : Collections.emptyList();
}
public String getExcerpt() {
if (content == null) return "";
String plainText = content.replaceAll("<[^>]*>", "");
return plainText.length() > 200 ? plainText.substring(0, 200) + "..." : plainText;
}
public int getReadingTime() {
if (content == null) return 0;
String plainText = content.replaceAll("<[^>]*>", "");
int wordCount = plainText.split("\\s+").length;
return Math.max(1, wordCount / 200); // 200 words per minute
}
public boolean hasTags() {
return tags != null && tags.length > 0;
}
}Template HTL
<article data-sly-use.post="com.mysite.models.BlogPostModel" class="blog-post">
<!-- Header -->
<header class="post-header">
<h1>${post.title}</h1>
<div class="post-meta">
<time datetime="${post.publishDate}">${post.formattedDate}</time>
<span class="dot">•</span>
<span>${post.readingTime} min lettura</span>
</div>
</header>
<!-- Contenuto -->
<div class="post-content">
${post.content }
</div>
<!-- Tags -->
<footer data-sly-test="${post.hasTags}" class="post-footer">
<h3>Tags:</h3>
<ul class="tag-list">
<li data-sly-list.tag="${post.tags}">
<a href="/blog/tag/${tag}">${tag}</a>
</li>
</ul>
</footer>
</article>Best Practice
- Preferisci Java Sling Models per progetti production
- Separa logica da presentazione: calcoli complessi nel model
- Use all'inizio: carica models nel root element quando possibile
- Naming chiaro:
author,product,configinvece dimodel,data - Injection over properties: usa
@Injectinvece diproperties.get() - Unit test dei models: testa la logica separatamente
- Documentazione: commenta methods pubblici
- Null safety: gestisci null/empty nei getters
Errori Comuni
❌ Path Java errato
<!-- SBAGLIATO - typo nel package -->
<div data-sly-use.model="com.exampel.Model">
<!-- CORRETTO -->
<div data-sly-use.model="com.example.Model">❌ Accesso fuori scope
<div data-sly-use.model="com.example.Model">
${model.title}
</div>
${model.title} <!-- ERRORE! -->❌ Non fare override di properties
// ❌ SBAGLIATO - shadow properties globale
public String getProperties() {
return "something";
}
// ✓ CORRETTO - nome diverso
public Map<String, Object> getComponentProperties() {
return componentProps;
}Esercizi Pratici
- User Profile Model: Crea model con avatar, bio, social links
- Product Catalog: Model con filtering e sorting
- Navigation Builder: Genera menu da page tree
Prossima Lezione
Nella prossima lezione vedremo data-sly-template e data-sly-call per creare template riutilizzabili e macro in HTL.
Lezione #8 della serie HTL Tutorial. ← Lezione precedente | Lezione successiva →