Frammenti di contenuto visivo - Modelli visual-content-fragments-templates

In Adobe Experience Manager (AEM) as a Cloud Service, è possibile utilizzare i modelli HTML per visualizzare i frammenti di contenuto e distribuirli in formato HTML.

NOTE
I frammenti di contenuto visivo e il processo da Figma a frammenti di contenuto visivo sono attualmente in disponibilità limitata.
Se desideri partecipare, invia una richiesta dal tuo indirizzo e-mail ufficiale a experience-production-agent@adobe.com.

I modelli di HTML consentono di controllare la modalità di visualizzazione dei frammenti di contenuto. Puoi creare modelli HTML nell’editor di codice desiderato, quindi caricarli e assegnarli a Modelli per frammenti di contenuto in AEM. I segnaposto di contenuto che utilizzano Handlebars.js consentono di mappare il modello ai tipi di dati nel modello per frammenti di contenuto. Una volta assegnato a un modello, un modello è disponibile per essere utilizzato con qualsiasi frammento di contenuto basato sul modello, per visualizzare il frammento o per distribuirlo come esperienza modulare in formato HTML a qualsiasi canale, ad esempio web, e-mail, app mobile o altri.

Questo articolo spiega come creare modelli HTML personalizzati con sintassi Handlebars per il rendering dei frammenti di contenuto visivo.

Dopo aver creato i modelli, puoi:

NOTE
Consulta Frammenti di contenuto visivo per caricare, assegnare e utilizzare il modello in AEM.
NOTE
Utilizza il processo Figma to Visual Content Fragments per automatizzare il caricamento di una progettazione HTML.

Cosa imparerai what-you-will-learn

Dopo aver fornito un’introduzione (molto rapida) a:

  • Come utilizzare i modelli in AEM
  • Utilizzo dell’URL di pubblicazione

In questa pagina vengono descritti (più dettagliatamente):

  • Handlebars: nozioni di base sulla sintassi
  • Come accedere ai dati dei frammenti di contenuto
  • Utilizzo di frammenti di contenuto nidificati
  • Gestione di campi con più valori
  • Creazione di loop e logica condizionale
  • Best practice per la progettazione di modelli per frammenti di contenuto

Prerequisiti prerequisites

Per comprendere e utilizzare le tecnologie qui descritte, è necessario disporre di:

  • Nozioni di base su HTML
  • Familiarità con i frammenti di contenuto e i modelli per frammenti di contenuto di AEM
  • Informazioni sui modelli per frammenti di contenuto

Utilizzo di un modello HTML per frammenti di contenuto using-a-content-fragment-html-template

Utilizzo di un modello HTML per frammenti di contenuto in AEM using-a-content-fragment-html-template-in-aem

Per informazioni dettagliate su come utilizzare il modello in AEM, consulta:

Utilizzo dell’URL di pubblicazione del frammento di contenuto visivo using-the-visual-content-fragment-publish-url

Dopo aver creato i frammenti di contenuto visivo utilizzando il modello, puoi utilizzare l’URL di pubblicazione dei frammenti di contenuto visivo.

Handlebars - the (very) basics handlebars-the-very-basics

Handlebars è un linguaggio di modelli semplice che utilizza parentesi graffe doppie {{ }} per inserire contenuto dinamico in HTML.

Sintassi di base basic-syntax

Un esempio di sintassi di base di Handlebars:

<!-- Output a variable (HTML-escaped) -->
{{snippet-not-found:variableName}}

<!-- Output raw HTML (unescaped) -->
{{{htmlContent}}}

<!-- Comment (not rendered) -->
{{! This is a comment }}

Concetti fondamentali key-concepts

I concetti chiave di Handlebars:

Sintassi
Descrizione
Quando utilizzare
{{ }}
Evita i caratteri speciali di HTML
Metadati, etichette, booleani
{{{ }}}
Restituisce il HTML non elaborato (senza escape)
Testo formattato e output risorse
{{! }}
Commento solo Handlebars
Documentazione del modello
IMPORTANT
Utilizzare parentesi graffe ({{{ }}}) per i valori dei campi perché i valori sono HTML di cui è stato eseguito il rendering anticipato.

Riferimento contesto modello template-context-reference

Quando viene eseguito il rendering del modello, questo riceve un oggetto contestuale contenente tutti i dati sul frammento di contenuto. Ciò riguarderà:

  • frammento selezionato

  • tutti gli altri frammenti a cui si fa riferimento dal frammento selezionato

    note
    NOTE
    È possibile fare riferimento ai frammenti:
    • nell’interfaccia utente: fino alla profondità massima di 5
    • quando si utilizza l’API: la profondità è configurabile, fino alla profondità massima di 10

Frammento di contenuto content-fragment

Struttura dell’oggetto contestuale per il frammento di contenuto (selezionato):

Variabile
Tipo
Descrizione
properties
Mappa
Metadati del frammento (vedi Struttura delle proprietà)
fields
Mappa
Accesso diretto ai valori dei campi per nome
allFields
Elenco
Array di {name, value} per l’iterazione
hasFields
Booleano
true se il frammento ha campi

Struttura delle proprietà properties-structure

L’oggetto properties ha la stessa struttura per il frammento selezionato e per ogni frammento di riferimento.

Proprietà
Tipo
Descrizione
Esempio
id
Stringa
UUID del frammento
title
Stringa
Titolo del frammento
Ciclismo nello Utah meridionale
description
Stringa
Descrizione del frammento
Un’avventura…
path
Stringa
Percorso JCR del frammento
/content/dam/...
hasDescription
Booleano
True se la descrizione non è vuota
true
createdDate
Stringa
Data di creazione ISO-8601
modifiedDate
Stringa
Data di modifica ISO-8601
publishedDate
Stringa
Data di pubblicazione ISO-8601
status
Stringa
Stato di replica per il livello di pubblicazione
DRAFT
model
Mappa
Contiene: id, path, name, technicalName, description
validationStatus
Elenco
Voci come {property, message}
previewReplicationStatus
Stringa
Stato della replica per il livello di anteprima
tags
Elenco
Tag livello frammento. Ogni elemento: id, title, titlePath, name, path, description
fieldTags
Elenco
Tag a livello di campo. Stessa struttura di tags.

Esempi: accesso ai modelli

Per il frammento di contenuto (selezionato):

{{properties.title}}, {{properties.description}}, {{{fields.field_name}}}

Frammenti di contenuto di riferimento referenced-content-fragments

Struttura dell’oggetto contestuale per tutti i frammenti a cui si fa riferimento:

Variabile
Tipo
Descrizione
hasReferencedFragments
Booleano
true quando esistono riferimenti
referencedFragments
Elenco
Array di oggetti frammento di riferimento
referencesError
Booleano
true se si è verificato un errore durante il caricamento dei riferimenti
referencesErrorMessage
Stringa
Messaggio di errore quando referencesError è true

Struttura dei frammenti di riferimento referenced-fragment-structure

Ogni elemento in referencedFragments contiene:

Proprietà
Tipo
Descrizione
anchorId
Stringa
ID di ancoraggio sicuro per HTML (a livello di frammento; non una proprietà Frammento di contenuto)
properties
Mappa
Metadati del frammento (stessa struttura di cui sopra)
hasFields
Booleano
True se il frammento contiene campi
fields
Mappa
Accesso diretto ai campi all’interno di questo frammento
allFields
Elenco
Array di {name, value} per l’iterazione

Esempi: accesso al modello per il primo frammento di contenuto a cui si fa riferimento (primo elemento nell’elenco con indice 0):

{{referencedFragments.[0].anchorId}}, {{referencedFragments.[0].properties.title}}, {{referencedFragments.[0].properties.description}}

Oppure dalla mappa dei campi:

{{{ fields.referenced_cf_field_name.properties.description }}}

Accesso ai campi di base basic-field-access

Si consiglia l’accesso diretto ai campi, se necessario è possibile eseguire iterazioni in tutti i campi.

Accedi direttamente ai campi per nome utilizzando la mappa dei campi:

<!DOCTYPE html>
<html>
<head>
  <title>{{properties.title}}</title>
</head>
<body>
  <article>
    <h1>{{{fields.title}}}</h1>
    <p class="subtitle">{{{fields.subtitle}}}</p>
    <div class="content">
      {{{fields.description}}}
    </div>
    <div class="image">
      {{{fields.primaryImage}}}
    </div>
  </article>
</body>
</html>

Ricorda:

  • Usa parentesi graffe {{{ }}} per i valori di campo se contengono HTML (Rich Text) pre-renderizzati
  • I nomi dei campi (titolo, sottotitolo, descrizione, immagine primaria) devono corrispondere esattamente al modello per frammenti di contenuto
  • I campi mancanti non vengono visualizzati: non vengono generati errori e la sintassi Handlebars rimane presente (e visibile) nel frammento HTML renderizzato

Scorre tutti i campi iterate-through-all-fields

Utilizza allFields quando non conosci in anticipo i nomi dei campi:

<table>
  <thead>
    <tr>
      <th>Field Name</th>
      <th>Field Value</th>
    </tr>
  </thead>
  <tbody>
    {{#each allFields}}
    <tr>
      <td>{{name}}</td>
      <td>{{{value}}}</td>
    </tr>
    {{/each}}
  </tbody>
</table>

Ricorda:

  • {{name}} utilizza le parentesi graffe (etichetta testo normale)
  • {{{value}}} utilizza parentesi graffe (valore HTML pre-renderizzato)

Frammenti di contenuto nidificati nested-content-fragments

Quando un campo Frammento di contenuto fa riferimento a un altro frammento di contenuto, puoi utilizzare la notazione del punto per accedere direttamente ai campi nel frammento di riferimento.

Nidificazione a livello singolo single-level-nesting

Esempio di nidificazione a livello singolo:

<article>
  <h1>{{{fields.title}}}</h1>

  <!-- Access author (a referenced Content Fragment) -->
  <div class="author-info">
    <h3>Author</h3>
    <p>Name: {{{fields.author.name}}}</p>
    <p>Email: {{{fields.author.email}}}</p>
    <p>Bio: {{{fields.author.bio}}}</p>
  </div>

  <div class="content">
    {{{fields.content}}}
  </div>
</article>

Pattern: fields.referenceFieldName.nestedFieldName

Nidificazione a più livelli multi-level-nesting

Il sistema supporta una profondità di nidificazione illimitata:

<article>
  <h1>{{{fields.title}}}</h1>

  <div class="author-details">
    <!-- Level 1: Author -->
    <p>Author: {{{fields.author.name}}}</p>

    <!-- Level 2: Author's Organization -->
    <p>Organization: {{{fields.author.organization.name}}}</p>
    <p>Website: {{{fields.author.organization.website}}}</p>

    <!-- Level 3: Organization's Address -->
    <p>Located in: {{{fields.author.organization.address.city}}},
    {{{fields.author.organization.address.country}}}</p>
  </div>

  <div class="content">
    {{{fields.content}}}
  </div>
</article>

Pattern: fields.level1.level2.level3.fieldName (profondità limitata; il valore predefinito è 5, può essere esteso a 10 quando si utilizza l’API)

Requisito parametro API: idratazione api-parameter-requirements

Per abilitare l’accesso ai frammenti di contenuto nidificati, è necessario includere il parametro di query hydration nella chiamata API:

Per attivare l’idratazione:

# Enable hydration with depth=2 for 2 levels of nesting
GET /adobe/sites/cf/fragments/{id}/preview?hydration=%7B%22enabled%22%3Atrue%2C%22maxDepth%22%3A2%7D
maxDepth
Cosa viene caricato
1
Frammento principale + riferimenti diretti
2
Frammento principale + riferimenti diretti + relativi riferimenti
3+
Continua fino a 10 livelli

Campi multivalore multi-valued-fields

Esistono diversi tipi di campi con più valori.

Campi di testo con più valori multi-valued-text-fields

Testo, numero, data e altri campi semplici diventano matrici se multivalore:

<article>
  <h1>{{{fields.title}}}</h1>

  <!-- Access individual items by index (use dot before bracket) -->
  <div class="tags">
    <span class="tag">{{{fields.tags.[0]}}}</span>
    <span class="tag">{{{fields.tags.[1]}}}</span>
  </div>

  <!-- Better: Iterate through all tags -->
  <div class="tags">
    {{#each fields.tags}}
    <span class="tag">{{{this}}}</span>
    {{/each}}
  </div>
</article>

Quando si accede a elementi array per indice in Handlebars:

  • Utilizza:
    • .[0] (punto prima parentesi)
  • Non:
    • [0]

Campi numerici multivalore multi-valued-number-fields

I numeri vengono convertiti in stringhe per il rendering:

<div class="pricing">
  <h3>Available Prices:</h3>
  {{#each fields.prices}}
  <span class="price">${{{this}}}</span>
  {{/each}}
</div>

Riferimenti a frammenti di contenuto con più valori multi-valued-content-fragment-references

Quando un campo fa riferimento a più frammenti di contenuto:

<div class="authors">
  <h3>Authors:</h3>
  {{#each fields.authors}}
  <div class="author">
    <h4>{{{this.name}}}</h4>
    <p>Email: {{{this.email}}}</p>
    {{#if this.bio}}
    <p class="bio">{{{this.bio}}}</p>
    {{/if}}
  </div>
  {{/each}}
</div>

Riferimenti a risorse con più valori multi-valued-asset-references

I campi Riferimento contenuto configurati per i tipi di contenuto che sono risorse (ad esempio, immagini e documenti) vengono prerenderizzati come HTML. Le risorse multivalore diventano array:

<!-- Single asset -->
<div class="hero-image">
  {{{fields.heroImage}}}
</div>

<!-- Multi-valued: iterate through all images -->
<div class="gallery">
  {{#each fields.gallery}}
  <div class="image">{{{this}}}</div>
  {{/each}}
</div>

Riferimenti con più valori nidificati nested-multi-valued-references

I riferimenti multivalore possono contenere riferimenti multivalore a qualsiasi profondità:

{{#each fields.chapters}}
<div class="chapter">
  <h3>Chapter: {{{this.title}}}</h3>

  {{#each this.authors}}
  <p>Author: {{{this.name}}}</p>

  {{#each this.publications}}
  <p>Publication: {{{this.title}}}</p>
  {{/each}}
  {{/each}}
</div>
{{/each}}

Cicli e iterazione loops-and-iteration

Handlebars fornisce l’helper {{#each}} per l’iterazione su array e oggetti.

Iterazione su array iterating-over-arrays

Esempio di iterazione su array:

<!-- Simple array iteration -->
{{#each fields.tags}}
<span class="tag">{{{this}}}</span>
{{/each}}

<!-- Array of objects -->
{{#each fields.authors}}
<div class="author">
  <h4>{{{this.name}}}</h4>
  <p>{{{this.email}}}</p>
</div>
{{/each}}

<!-- With empty-state fallback -->
{{#each fields.tags}}
<span class="tag">{{{this}}}</span>
{{snippet-not-found:else}}
<p>No tags available.</p>
{{/each}}

Variabili speciali nei cicli special-variables-in-loops

All’interno di {{#each}} blocchi, Handlebars fornisce variabili speciali:

{{#each fields.items}}
<div class="item">
  <p>Index: {{@index}}</p>     <!-- 0-based index -->
  <p>Number: {{@number}}</p>   <!-- 1-based index -->
  <p>First: {{@first}}</p>     <!-- true for first item -->
  <p>Last: {{@last}}</p>       <!-- true for last item -->
  <p>Value: {{{this}}}</p>     <!-- current item -->
</div>
{{/each}}

<!-- Example: numbered steps with first/last CSS classes -->
<ul>
  {{#each fields.steps}}
  <li class="{{#if @first}}first{{/if}} {{#if @last}}last{{/if}}">
    Step {{@number}}: {{{this}}}
  </li>
  {{/each}}
</ul>

Iterazione su frammenti di riferimento iterating-over-referenced-fragments

Esempio di iterazione sui frammenti di riferimento:

{{#if hasReferencedFragments}}
<section class="references">
  <h2>Related Content</h2>
  {{#each referencedFragments}}
  <article id="{{anchorId}}">
    <h3>{{title}}</h3>
    {{#if hasDescription}}
    <p>{{description}}</p>
    {{/if}}
    {{#if hasFields}}
    <ul>
      {{#each allFields}}
      <li><strong>{{name}}:</strong> {{{value}}}</li>
      {{/each}}
    </ul>
    {{/if}}
  </article>
  {{/each}}
</section>
{{/if}}

Loop nidificati nested-loops

Esempio di loop nidificati:

{{#each fields.categories}}
<section class="category">
  <h2>{{{this.name}}}</h2>

  {{#each this.products}}
  <article class="product">
    <h3>{{{this.name}}}</h3>
    <p>{{{this.description}}}</p>
  </article>
  {{/each}}
</section>
{{/each}}

Rendering condizionale conditional-rendering

Utilizza le condizionali per mostrare o nascondere il contenuto in base alla disponibilità dei dati.

If/Else di base basic-if-else

Esempio di costrutto di base if-else:

{{#if hasMainDescription}}
<p class="description">{{properties.description}}</p>
{{snippet-not-found:else}}
<p class="no-description">No description available.</p>
{{/if}}

<!-- Check field existence before rendering -->
{{#if fields.author}}
<div class="author">
  <p>By {{{fields.author.name}}}</p>
</div>
{{/if}}

{{#if fields.publishDate}}
<time>{{{fields.publishDate}}}</time>
{{/if}}

A meno che (condizionale negativo) unless-negative-conditional

Un helper unless:

<!-- Show author unless explicitly hidden -->
{{#unless fields.hideAuthor}}
<div class="author">{{{fields.author.name}}}</div>
{{/unless}}

Condizionali nidificati nested-conditials

Esempio di condizionale nidificato:

{{#if fields.author}}
<div class="author">
  <h3>{{{fields.author.name}}}</h3>

  {{#if fields.author.bio}}
  <p class="bio">{{{fields.author.bio}}}</p>
  {{/if}}

  {{#if fields.author.website}}
  <a href="{{{fields.author.website}}}">Visit Website</a>
  {{/if}}
</div>
{{/if}}

Helper Handlebars integrati built-in-handlebars-helpers

Handlebars include diversi helper incorporati, oltre a {{#if}} e {{#each}}.

Helper
Descrizione
{{#if condition}}
Esegue il rendering del contenuto se la condizione è truthy. Valori falsy: false, undefined, null, 0, "", []
{{#unless condition}}
Esegue il rendering del contenuto se la condizione è falsy (inverso di #if)
{{#each array}}
Ripete il contenuto per ogni elemento; supporta {{else}} per gli array vuoti
{{#with object}}
Crea un nuovo ambito per un oggetto nidificato, riducendo la ripetizione del percorso
{{lookup this "key"}}
Cerca dinamicamente una proprietà per nome

Con Helper with-helper

Crea un nuovo ambito per gli oggetti nidificati per ridurre i prefissi di percorso ripetitivi:

{{#with fields.author}}
<div class="author">
  <h3>{{{name}}}</h3>     <!-- same as fields.author.name -->
  <p>{{{email}}}</p>      <!-- same as fields.author.email -->
  <p>{{{bio}}}</p>        <!-- same as fields.author.bio -->
</div>
{{/with}}

<!-- Useful for deeply nested objects -->
{{#with fields.author.organization}}
<div class="organization">
  <h4>{{{name}}}</h4>
  <p>{{{website}}}</p>
  {{#with address}}
  <address>
    {{{street}}}<br/>
    {{{city}}}, {{{country}}}
  </address>
  {{/with}}
</div>
{{/with}}

Modelli avanzati advanced-patterns

Seguono alcuni esempi di pattern avanzati.

Accesso al contesto padre nei loop nidificati accessing-parent-context-in-nested-loops

Utilizzare ../ per accedere all’ambito padre da un loop nidificato:

<h1>{{{fields.title}}}</h1>

{{#each fields.chapters}}
<section class="chapter">
  <h2>Chapter {{@number}}: {{{this.title}}}</h2>

  {{#each this.sections}}
  <article>
    <!-- Access parent chapter via ../ -->
    <p>Chapter: {{{../title}}}</p>

    <!-- Access root context via ../../ -->
    <p>Book: {{{../../fields.title}}}</p>

    <h3>{{{this.title}}}</h3>
    <div>{{{this.content}}}</div>
  </article>
  {{/each}}
</section>
{{/each}}

Classi CSS dinamiche dynamic-css-classes

Esempio di classi CSS dinamiche:

<article class="content-fragment {{#if hasMainDescription}}with-description{{/if}} {{#if hasReferencedFragments}}has-refs{{/if}}">
  <h1>{{properties.title}}</h1>
</article>

<ul class="tag-list">
  {{#each fields.tags}}
  <li class="tag {{#if @first}}first{{/if}} {{#if @last}}last{{/if}}">
    {{{this}}}
  </li>
  {{/each}}
</ul>

Esempi completi complete-examples

Sono forniti diversi esempi completi a titolo di riferimento.

Post di blog con autore

Un post di blog con i dettagli dell’autore:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{properties.title}}</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 40px; }
    .author-card { background: #f5f5f5; padding: 20px; border-radius: 8px; }
    .tags { display: flex; gap: 10px; }
    .tag { background: #007bff; color: white; padding: 5px 10px; border-radius: 4px; }
  </style>
</head>
<body>
  <article>
    <header>
      <h1>{{{fields.title}}}</h1>
      {{#if fields.publishDate}}
      <time datetime="{{{fields.publishDate}}}">{{{fields.publishDate}}}</time>
      {{/if}}
      {{#if fields.tags}}
      <div class="tags">
        {{#each fields.tags}}
        <span class="tag">{{{this}}}</span>
        {{/each}}
      </div>
      {{/if}}
    </header>

    {{#if fields.heroImage}}
    <figure>
      {{{fields.heroImage}}}
      {{#if fields.imageCaption}}
      <figcaption>{{{fields.imageCaption}}}</figcaption>
      {{/if}}
    </figure>
    {{/if}}

    <div class="content">
      {{{fields.content}}}
    </div>

    {{#if fields.author}}
    <aside class="author-card">
      <h3>About the Author</h3>
      <h4>{{{fields.author.name}}}</h4>
      {{#if fields.author.profilePicture}}
      <div class="author-image">{{{fields.author.profilePicture}}}</div>
      {{/if}}
      {{#if fields.author.bio}}
      <p>{{{fields.author.bio}}}</p>
      {{/if}}
      {{#if fields.author.email}}
      <p>Contact: <a href="mailto:{{{fields.author.email}}}">{{{fields.author.email}}}</a></p>
      {{/if}}
    </aside>
    {{/if}}
  </article>
</body>
</html>

Chiamata API richiesta:

GET /adobe/sites/cf/fragments/{id}/preview?hydration=%7B%22enabled%22%3Atrue%2C%22maxDepth%22%3A1%7D

Vista tabella generica (nessuna conoscenza precedente dei campi) generic-table-view-no-prior-knowledge-of-fields

Visualizzazione tabella generica, senza una conoscenza dei campi. È simile al modello generico:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{properties.title}}</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 40px; }
    table { width: 100%; border-collapse: collapse; margin: 20px 0; }
    th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
    th { background-color: #f4f4f4; font-weight: bold; }
    .ref-section { background: #f9f9f9; padding: 20px; margin: 20px 0; border-radius: 8px; }
  </style>
</head>
<body>
  <header>
    <h1>{{properties.title}}</h1>
    {{#if properties.description}}<p>{{properties.description}}</p>{{/if}}
    <p><small>Path: {{properties.path}}</small></p>
  </header>

  {{#if hasFields}}
  <section>
    <h2>Fields</h2>
    <table>
      <thead>
        <tr><th>Field Name</th><th>Field Value</th></tr>
      </thead>
      <tbody>
        {{#each allFields}}
        <tr>
          <td><strong>{{name}}</strong></td>
          <td>{{{value}}}</td>
        </tr>
        {{/each}}
      </tbody>
    </table>
  </section>
  {{/if}}

  {{#if hasReferencedFragments}}
  <section class="ref-section">
    <h2>Referenced Content Fragments</h2>
    {{#each referencedFragments}}
    <article id="{{anchorId}}" style="margin-bottom: 30px;">
      <h3>{{title}}</h3>
      {{#if hasDescription}}<p>{{description}}</p>{{/if}}
      <p><small>Path: {{path}}</small></p>
      {{#if hasFields}}
      <table>
        <thead>
          <tr><th>Field Name</th><th>Field Value</th></tr>
        </thead>
        <tbody>
          {{#each allFields}}
          <tr>
            <td><strong>{{name}}</strong></td>
            <td>{{{value}}}</td>
          </tr>
          {{/each}}
        </tbody>
      </table>
      {{/if}}
    </article>
    {{/each}}
  </section>
  {{/if}}
</body>
</html>

Best practice best-practices

Le best practice includono:

  1. Utilizza sempre parentesi graffe triple per i valori dei campi che contengono contenuto di markup HTML.

    • I valori dei campi sono HTML di cui è stato eseguito il pre-rendering.

      note
      NOTE
      Le doppie parentesi graffe mostrano i tag HTML non elaborati come testo normale.
    code language-handlebars
    <!-- CORRECT -->
    {{{fields.description}}}
    
    <!-- WRONG - displays HTML tags as text -->
    {{fields.description}}
    
  2. Verifica la presenza prima di accedere ai campi nidificati.

    code language-handlebars
    <!-- GOOD: check before accessing nested fields -->
    {{#if fields.author}}
    <p>By {{{fields.author.name}}}</p>
    {{/if}}
    
    <!-- RISKY: may render empty if author is not set -->
    <p>By {{{fields.author.name}}}</p>
    
  3. Se possibile, utilizza l’accesso diretto ai campi.

    • È più leggibile e gestibile rispetto all’iterazione di allFields e alla corrispondenza per nome.
  4. Modelli di struttura con commenti di sezione.

    code language-handlebars
    {{! ===== HEADER SECTION ===== }}
    <header>
      <h1>{{properties.title}}</h1>
    </header>
    
    {{! ===== MAIN CONTENT ===== }}
    <main>
      {{#if hasFields}}
      <!-- fields rendering -->
      {{/if}}
    </main>
    
    {{! ===== REFERENCES ===== }}
    {{#if hasReferencedFragments}}
    <!-- references rendering -->
    {{/if}}
    
  5. Gestisci i dati mancanti in modo semplice con i fallback.

    code language-handlebars
    {{#if fields.title}}
    <h1>{{{fields.title}}}</h1>
    {{snippet-not-found:else}}
    <h1>Untitled</h1>
    {{/if}}
    
  6. Utilizza sempre una struttura di documento HTML appropriata.

    code language-handlebars
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>{{properties.title}}</title>
    </head>
    <body>
      <!-- your content here -->
    </body>
    </html>
    
  7. Esegui il test con diversi scenari di contenuto:

    • Tutti i campi sono completamente compilati
    • Campi opzionali mancanti
    • Campi multivalore vuoti
    • Nidificazione profonda (più livelli)
    • Riferimenti non caricati
  8. Utilizza elementi HTML semantici:

    • Per una migliore accessibilità, utilizzare <article>, <header>, <main>, <footer>, <time>, <address> o simili.
  9. Mantieni gli stili nel CSS.

    • Utilizza <style> tag o fogli di stile esterni.
    • Se possibile, evita gli stili in linea.
  10. Logica complessa documento:

    • Usa commenti Handlebars ({{! }}).
    • Non utilizzare i commenti di HTML, visualizzati nell’output di rendering.

Risoluzione di problemi troubleshooting

Alcuni suggerimenti per la risoluzione dei problemi includono:

Problema
Sintomo
Soluzione
Il campo mostra i tag HTML come testo
<p>Hello World</p> visualizzato letteralmente
Usa parentesi graffe: {{{fields.description}}}
I campi dei frammenti di contenuto nidificati sono vuoti o mostrano [oggetto]
{{{fields.author.name}}} è vuoto
Abilita l’idratazione nella chiamata API; verifica l’ortografia del nome del campo; verifica che maxDepth sia sufficientemente profondo
Il campo multivalore mostra solo il primo elemento
Un array con cinque elementi esegue il rendering di un solo elemento
Utilizza {{#each fields.tags}} per eseguire iterazioni di tutti gli elementi
L’accesso all’indice della matrice non funziona
{{{fields.tags[0]}}} rendering vuoti
Usa sintassi parentesi: {{{fields.tags.[0]}}}
Frammenti di riferimento non visualizzati
hasReferencedFragments è sempre falso
Abilita idratazione: ?hydration=%7B%22enabled%22%3Atrue%7D; controllare anche {{#if referencesError}}
Il modello non esegue il rendering
Pagina vuota o output vuoto
Verificare la presenza di {{#if}} o {{#each}} blocchi non chiusi. Aggiungere l’output di diagnostica: <pre>hasFields: {{hasFields}} | title: {{properties.title}}</pre>
I commenti vengono visualizzati nella pagina di cui è stato eseguito il rendering
Testo del commento HTML visibile agli utenti finali
Utilizza i commenti Handlebars {{! comment }} invece di HTML <!-- comment -->
Il condizionale restituisce sempre true
{{#if fields.enabled}} è sempre truthy
Nota: la stringa "false" è truthy in Handlebars. Solo i valori effettivi false, null, undefined, 0, "" e [] sono falsy.
Caratteri speciali che vengono visualizzati come entità
&lt;, &amp; visualizzato invece di <, &
Usa parentesi graffe per il contenuto HTML pre-renderizzato: {{{fields.content}}}
Impossibile accedere alla variabile del loop esterno dal loop interno
La variabile dell’elemento padre #each non è definita
Usa ../ per l’ambito padre: {{{../name}}}; usa ../../ per l’ambito padre
L’elenco vuoto non mostra il messaggio di fallback
Il campo multivalore con zero elementi non mostra nulla
Usa {{else}} in {{#each}}: {{#each fields.tags}}...{{else}}<p>No tags</p>{{/each}}

Utilizzo delle risorse working-with-assets

Assets a cui si fa riferimento dai frammenti di contenuto viene sottoposto a pre-rendering come HTML da AEM. Pertanto, le parentesi graffe sono obbligatorie per tutti i riferimenti a risorse.

Tipo risorsa
Rendering come
Immagini
<img src="..." alt="...">
Video
<video> elemento
Documenti
Collegamento <a href="...">

Ricorda:

  • Per i campi delle risorse, utilizza sempre le parentesi graffe.
    Se si utilizzano parentesi graffe doppie, il tag HTML generato verrà eliminato e visualizzato come testo non elaborato anziché come immagine, video o collegamento.

Utilizzo campo risorsa asset-field-usage

Esempio di utilizzo del campo risorsa:

<!-- CORRECT - triple braces render the image -->
{{{fields.heroImage}}}
<!-- Output: <img src="path/to/image.jpg" alt="Hero"> -->

<!-- WRONG - double braces escape the tag, showing it as text -->
{{fields.heroImage}}
<!-- Output: &lt;img src="path/to/image.jpg" alt="Hero"&gt; -->

Helper per modelli personalizzati customer-template-helpers

Il sistema fornisce assistenti Handlebars personalizzati per la generazione di elementi HTML con attributi HTML personalizzati. Questi helper ti consentono di controllare il markup generato, gestendo al contempo la complessità dell’estrazione degli URL di origine dai contenuti pre-renderizzati.

Helper disponibili:

  1. asset - Genera <img> tag con attributi personalizzati
  2. text - Genera <span> tag per il wrapping del contenuto di testo con attributi personalizzati

Helper asset asset-helper

Sintassi:

{{{asset fieldValue attribute1="value1" attribute2="value2"}}}

Ricorda:

  • Utilizzare le parentesi graffe triple {{{ }}} con l’helper della risorsa, non le doppie.

Quattro esempi di base four-basic-examples

Quattro esempi di base sono:

<!-- Add a CSS class to an image -->
{{{asset fields.heroImage class="hero-image"}}}
<!-- Output: <img src="..." alt="..." class="hero-image"> -->

<!-- Add multiple CSS classes -->
{{{asset fields.productImage class="product-img responsive shadow"}}}

<!-- Add id and class -->
{{{asset fields.logo class="brand-logo" id="main-logo"}}}

<!-- Add data attributes -->
{{{asset fields.thumbnail class="thumb" data-category="product" data-id="123"}}}

Attributi supportati supported-attributes

Puoi aggiungere qualsiasi attributo HTML valido:

Attributo
Esempio
class
class="my-class another-class"
id
id="unique-id"
alt
alt="Custom alt text" (overrides existing alt)
data-*
data-index="1" data-type="hero"
aria-*
aria-label="Description" aria-hidden="true"
width
width="300"
height
height="200"
loading
loading="lazy"
style
style="border-radius: 8px;"

Sostituisci testo alternativo override-alt-text

L’attributo alt dell’immagine originale può essere sovrascritto:

{{{asset fields.photo alt="Custom description for accessibility"}}}

Esempio complesso complex-example

Un esempio complesso è:

<article class="blog-post">
<header>
{{{asset fields.featuredImage
class="featured-image responsive"
id="post-hero"
loading="lazy"
data-post-id="12345"}}}
</header>
</article>

Utilizzo con cicli using-with-loops

Helper risorse in loop:

{{#each fields.galleryImages}}
{{{asset this class="gallery-item" data-index=@index}}}
{{/each}}

Helper text text-helper

L’helper di testo genera un tag <span> che racchiude il contenuto di testo con classi CSS e attributi HTML personalizzati. Utile per formattare singoli campi di testo.

Sintassi:

{{{text fieldValue attribute1="value1" attribute2="value2"}}}

Ricorda:

  • Utilizzare le parentesi graffe triple {{{ }}} con l’helper di testo, non le doppie.

Tre esempi di base three-basic-examples

Tre esempi di base sono:

<!-- Add a CSS class to text -->
{{{text fields.title class="article-title"}}}
<!-- Output: <span class="article-title">The Title Text</span> -->

<!-- Add multiple attributes -->
{{{text fields.price class="price-tag" id="product-price" data-currency="USD"}}}

<!-- Style inline text -->
{{{text fields.highlightedText class="highlighted" style="background: yellow;"}}}

Casi d’uso comuni common-use-cases

Alcuni casi d’uso comuni includono:

<!-- Styling article metadata -->
<article>
<header>
{{{text fields.category class="category-badge"}}}
<h1>{{{fields.title}}}</h1>
{{{text fields.author class="byline"}}}
{{{text fields.publishDate class="date"}}}
</header>
</article>

<!-- Creating styled labels -->
<div class="product-card">
{{{text fields.productName class="product-name"}}}
{{{text fields.brand class="brand-label" data-brand-id="abc"}}}
{{{text fields.price class="price" id="main-price"}}}
</div>

<!-- Accessibility enhancements -->
{{{text fields.importantNote class="alert" role="alert" aria-live="polite"}}}

Con cicli with-loops

Un caso d’uso comune con i loop include:

{{#each fields.tags}}
{{{text this class="tag-badge"}}}
{{/each}}

Helper - Convalida degli attributi helpers-attribute-validation

Entrambi gli helper convalidano i nomi degli attributi prima di includerli nell’output.

Nomi di attributi validi:

  • Deve iniziare con una lettera (a-z, A-Z)

  • Può contenere solo lettere, cifre, trattini e trattini bassi; vedi le Convenzioni di denominazione

  • Senza distinzione tra maiuscole e minuscole

  • Ad esempio:

    • Valido:
      • class, id, data-value, aria-label, my_attr, dataIndex1
    • Non valido:
      • 123-attr, -class, @special, $money

I nomi di attributo non validi vengono automaticamente ignorati con un avviso nei registri:

{{{asset fields.image class="valid" 123-invalid="skipped" id="also-valid"}}}
<!-- Output: <img src="..." alt="..." class="valid" id="also-valid"> -->
<!-- 123-invalid is skipped because it starts with a number -->

Ricorda:

  • Verificare nei registri del server la presenza di avvisi relativi al formato di nome attributo “Bloccato non valido”.

Confronto tra output diretto e helper comparing-direct-output-to-helpers

Quando aumentare l’output diretto {{{fields.xxx}}}:

  • Non è necessario utilizzare uno stile personalizzato
  • Desideri l’output predefinito così com’è
  • Il campo contiene HTML complessi che non desideri modificare

Quando utilizzare gli helper:

  • È necessario aggiungere classi CSS per lo stile
  • È necessario aggiungere attributi HTML personalizzati (data-*, aria-* e altri)
  • Desideri una struttura HTML coerente e controllata

Confronto:

<!-- Direct output - uses whatever HTML the system generates -->
{{{fields.heroImage}}}
<!-- Output: <img src="/path/image.jpg" alt="Hero Image"> -->

<!-- With asset helper - full control over attributes -->
{{{asset fields.heroImage class="hero responsive" id="main-hero" loading="lazy"}}}
<!-- Output: <img src="/path/image.jpg" alt="Hero Image" class="hero responsive" id="main-hero" loading="lazy"> -->

Riferimento rapido quick-reference

Vengono fornite alcune informazioni di riferimento rapido.

Variabili di contesto context-variables

Le variabili di contesto:

{{properties}}                <!-- Main fragment metadata -->
{{fields}}                    <!-- Map keyed by field name to rendered values (such as strings, lists, nested maps for Content Fragment references, commerce maps, HTML, and others) -->
{{allFields}}                 <!-- List of { name, value } maps (uniform iteration) -->
{{hasFields}}.                <!-- Boolean -->
{{hasReferencedFragments}}.   <!-- Boolean -->
{{referencedFragments}}       <!-- List of referenced-fragment maps -->

Accesso ai campi field-access

Come accedere ai campi:

{{{fields.fieldName}}}                    <!-- Direct field -->
{{{fields.author.name}}}                  <!-- Nested Content Fragment field -->
{{{fields.author.org.address.city}}}      <!-- Multi-level nesting -->
{{{fields.tags.[0]}}}                     <!-- Array by index -->
{{#each fields.tags}}...{{/each}}         <!-- Array iteration -->
{{{fields.authors.[0].name}}}             <!-- Multi-valued Content Fragment reference -->

Flusso di controllo control-flow

Flusso di controllo:

{{#if condition}}...{{/if}}               <!-- Conditional -->
{{#if condition}}...{{else}}...{{/if}}    <!-- If/else -->
{{#unless condition}}...{{/unless}}       <!-- Negative conditional -->
{{#each array}}...{{/each}}               <!-- Iteration -->
{{#each array}}...{{else}}...{{/each}}    <!-- Iteration with fallback -->
{{#with object}}...{{/with}}              <!-- Change scope -->

Variabili di loop loop-variables

Le variabili di loop:

{{@index}}        <!-- 0-based index -->
{{@number}}       <!-- 1-based index -->
{{@first}}        <!-- true for first item -->
{{@last}}         <!-- true for last item -->
{{@key}}          <!-- Object property name -->
{{this}}          <!-- Current item -->
{{../parent}}     <!-- Access parent scope -->

Helper per modelli personalizzati custom-template-helpers

Il modello personalizzato aiuta a:

{{{asset fields.image class="css-class"}}}                <!-- Image with class -->
{{{asset fields.image class="c1" id="my-id"}}}            <!-- Image with multiple attrs -->
{{{asset fields.image alt="Custom alt text"}}}            <!-- Override alt text -->
{{{asset fields.image loading="lazy" data-x="val"}}}      <!-- Custom attributes -->

{{{text fields.title class="title-class"}}}               <!-- Span with class -->
{{{text fields.price class="price" id="p1"}}}             <!-- Span with multiple attrs -->
{{{text this class="item" data-index=@index}}}            <!-- In loops -->

Risorse aggiuntive additional-resources

Sono disponibili risorse aggiuntive:

recommendation-more-help
experience-manager-cloud-service-help-main-toc