# Référence de syntaxe Handlebars

Introduisez les paramètres et props dans votre modèle avec Handlebars, de l'affichage du texte à la création de tableaux et de contenu conditionnel.

Lors de la conception d'un modèle, vous devez souvent introduire des données dans son contenu : le nom d'un destinataire de `params`, un en-tête de `props` ou une liste de produits affichée sous forme de lignes de tableau. Tembuilder utilise **Handlebars** pour connecter ces valeurs à votre HTML/CSS. Sa syntaxe vous permet de marquer où les données doivent apparaître et de décrire comment le contenu doit être affiché.

Par exemple, écrivez `{{ params.recipient }}` à la place du nom du destinataire. Lorsque vous prévisualisez le document ou générez un PDF, Tembuilder lit la valeur correspondante et remplace l'expression par le contenu réel. Cela vous permet de réutiliser la même conception avec différents ensembles de données.

Ce guide vous guide à travers la lecture des valeurs de [Parameters](/docs/fr/data/parameters/) et [Props](/docs/fr/data/parameters-props/), en affichant le contenu de manière conditionnelle, en répétant des listes et en utilisant une syntaxe avancée lorsque votre modèle nécessite des structures de données plus complexes.

## 1. Du modèle au document

Commencez par un exemple simple : vous avez créé une section prop `heading` avec la valeur `Invoice` et déclaré un paramètre `recipient` avec la valeur `Tembuilder`. Dans le HTML de la section, placez chaque valeur à l'endroit où vous souhaitez qu'elle apparaisse à l'aide de `{{ ... }}` :

```handlebars
<h1>{{ props.heading }}</h1>
<p>{{ params.recipient }}</p>
```

```html
<h1>Invoice</h1>
<p>Tembuilder</p>
```

<figure class="doc-sim data-assets-illustration" aria-label="Le modèle HTML et les données deviennent le contenu du document">
<div class="sim-stage"><div class="ds-flow"><div class="ds-code"><code>{{ props.heading }} → Invoice</code><code>{{ params.recipient }} → Tembuilder</code></div><span class="ds-flow-arrow">→</span><div class="ds-paper"><small>Tembuilder</small><strong>Facture</strong><div><p>Tembuilder</p></div></div></div></div>
<figcaption>Les expressions sont remplacées avant la pagination PDF.</figcaption>
</figure>

## 2. Choisissez le bon chemin de données

| Chemin | Lectures |
| --- | --- |
| `{{ params.recipient }}` | Données fournies pour cette exécution, une fois les valeurs par défaut appliquées. |
| `{{ props.heading }}` | Props pour la pièce en cours de compilation. Dans une section, les valeurs de section remplacent les valeurs Global portant le même nom. |
| `{{ global.props.company }}` | Global props explicitement, même lorsqu'une section remplace le même nom. |
| `{{ @root.params.recipient }}` | Données Run provenant de l'intérieur d'une boucle ou d'un bloc `with`. |

Utilisez des chemins `params.` explicites au lieu de noms de paramètres nus. Les noms des paramètres racine sont également exposés pour des raisons de compatibilité, mais les noms tels que `props`, `params` et `global` sont occupés par le contexte de la plateforme.

Chaque section, en-tête et pied de page est compilé avec son propre contexte. `@root` signifie la racine de cette compilation, pas une autre section. [Variants](/docs/fr/data/variants/) sélectionne les remplacements de prop avant l'exécution des expressions.

## 3. Texte, nombres, booléens et valeurs manquantes

L'objet suivant est **run data** : saisissez ses champs dans Run sans ajouter de wrapper `params` externe. Déclarez les types correspondants dans Parameters → Schema.

```json
{
  "recipient": "Tembuilder & Tembuilder",
  "quantity": 2,
  "balance": 0,
  "paid": false,
  "totalLabel": "250,000 VND"
}
```

```handlebars
<p>{{ params.recipient }} · {{ params.quantity }}</p>
<p>{{ params.totalLabel }}</p>
{{#if params.paid}}Paid{{else}}Awaiting payment{{/if}}
```

Le texte s'affiche sous forme de texte, les nombres affichent leur valeur et l'impression directe d'un booléen produit `true` ou `false`. Utilisez une condition pour une étiquette conviviale. Conservez `2` numérique et `false` booléen ; `"2"` et `"false"` sont des chaînes.

Une valeur non résolue n'imprime normalement rien. Cela ne remplace pas la déclaration des champs obligatoires ou la validation des données d'exécution. Une syntaxe invalide ou un assistant inconnu arrête la compilation.

Handlebars ne calcule pas `quantity * price`, n'appelle pas `.toFixed(2)` et ne formate pas automatiquement les dates/devises. Préparez les totaux et les chaînes formatées avant le rendu. `{{ params.quantity + 1 }}` et `{{ params.total.toFixed(2) }}` ne sont pas des expressions JavaScript prises en charge.

## 4. Objets et noms de propriétés

```json
{
  "recipient": { "name": "Tembuilder", "address": { "city": "Hanoi" } },
  "labels": { "invoice_title": "Invoice", "postal_code": "10000" }
}
```

```handlebars
<p>{{ params.recipient.name }} · {{ params.recipient.address.city }}</p>
<h2>{{ params.labels.invoice_title }}</h2>
<p>{{ params.labels.postal_code }}</p>
```

Utilisez des noms de champs tels que `recipientName` ou `postal_code`. L'éditeur remplace les espaces, les tirets et autres caractères en dehors des lettres, des chiffres et des traits de soulignement par `_` ; le premier caractère doit être une lettre ou un trait de soulignement. Pour un schéma importé existant avec des clés telles que `postal code`, Handlebars peut les lire à l'aide de `{{ params.labels.[postal code] }}`. Cette syntaxe ne modifie pas les règles de dénomination de l’éditeur. Pour restituer un objet de manière significative, sélectionnez ses champs ou itérez-les ; l'impression de l'objet entier n'est pas une sérialisation JSON.

## 5. Conditions : `if`, `else`, `unless`

```handlebars
{{#if params.paid}}
  <p>Payment received</p>
{{else if params.overdue}}
  <p>Payment overdue</p>
{{else}}
  <p>Awaiting payment</p>
{{/if}}
{{#unless params.paid}}<p>Please pay before the due date.</p>{{/unless}}
{{#if params.balance includeZero=true}}<p>Balance: {{ params.balance }}</p>{{/if}}
```

`if` prend la branche négative pour `false`, `null`, les valeurs manquantes, une chaîne vide, zéro et un tableau vide. `includeZero=true` fait prendre à zéro la branche positive. Un objet vide et la chaîne `"false"` prennent la branche positive. `unless` inverse la condition. `if` ne change pas le contexte actuel.

Il n'y a pas d'assistants `eq`, `gt`, `and` ou `or` intégrés dans cette plate-forme. Calculez un booléen tel que `overdue` dans l'entrée au lieu d'écrire `{{#if params.balance > 0}}`.

## 6. Tableaux : `each` et états vides

```json
{
  "items": [{ "name": "Design", "quantity": 2 }, { "name": "Review", "quantity": 1 }],
  "tags": ["Draft", "Internal"]
}
```

```handlebars
<table>
  <thead><tr><th>Item</th><th>Quantity</th></tr></thead>
  <tbody>
    {{#each params.items}}
      <tr><td>{{ this.name }}</td><td>{{ this.quantity }}</td></tr>
    {{else}}
      <tr><td colspan="2">No items</td></tr>
    {{/each}}
  </tbody>
</table>
{{#each params.tags}}<span>{{ this }}</span>{{/each}}
```

`this` est l'élément actuel : un objet pour `items`, une chaîne pour `tags`. L'accès direct à la baie est possible avec `{{ params.items.[0].name }}`. Pour les tableaux longs, suivez [guide de pagination](/docs/fr/editor/pagination/).

<figure class="doc-sim data-assets-illustration" aria-label="Chaque élément du tableau devient une ligne du tableau ; les tableaux vides utilisent else">
<div class="sim-stage"><div class="ds-code"><code>{{#each params.items}}</code><code>  {{ this.name }} · {{ this.quantity }}</code><code>{{else}} No items {{/each}}</code></div><div class="ds-data-table"><div><b>Article</b><b>Quantité</b></div><div><span>Conception</span><span>2</span></div><div><span>Révision</span><span>1</span></div></div></div>
<figcaption>Un élément → une ligne. Une liste vide → la branche else.</figcaption>
</figure>

## 7. Métadonnées de boucle et itération d'objet

| Expression | Signification à l'intérieur de `each` |
| --- | --- |
| `@index` | Position du tableau, en commençant à zéro. |
| `@first`, `@last` | Indicateurs du premier/dernier élément du tableau. |
| `@key` | Nom de la propriété lors de l'itération d'un objet. |

```handlebars
{{#each params.tags}}
  {{#if @first}}<strong>Tags:</strong>{{/if}}
  {{ this }}{{#unless @last}}, {{/unless}}
{{/each}}
{{#each params.recipient}}
  <p>{{ @key }}: {{ this }}</p>
{{/each}}
```

N'utilisez pas `@index + 1` pour créer des numéros de ligne. Fournissez un champ `rowNumber` si vous avez besoin d'une numérotation commençant par un.

## 8. Contexte : `with`, chemins parents et racine

```handlebars
{{#with params.recipient}}
  <p>{{ name }}</p>
{{else}}
  <p>No recipient</p>
{{/with}}
{{#each params.items}}
  <p>{{ this.name }} — {{ ../props.heading }}</p>
  <small>{{ @root.global.props.company }}</small>
{{/each}}
```

`with` et `each` changent de contexte. `../` renvoie au contexte parent ; `@root` fournit un accès stable à la racine de compilation à travers des boucles imbriquées. L'ajout d'un `if` ne nécessite pas un autre `../`.

Les alias facilitent le suivi des listes imbriquées. Ici, déclarez `groups` comme un tableau d'objets, chacun avec un tableau `name` et un tableau `items` :

```handlebars
{{#each params.groups as |group groupIndex|}}
  <h2>{{ group.name }}</h2>
  {{#each group.items as |item itemIndex|}}
    <p>{{ groupIndex }}.{{ itemIndex }} — {{ item.name }}</p>
  {{/each}}
{{/each}}
```

## 9. Recherche dynamique et sous-expressions

Utilisez `lookup` pour une clé fournie en données. Déclarez `labels` comme objet et `selectedKey` comme texte ; pour `{ "labels": { "approved": "Approved" }, "selectedKey": "approved" }` :

```handlebars
<p>{{ lookup params.labels params.selectedKey }}</p>
{{#with (lookup params.labels params.selectedKey)}}<strong>{{ this }}</strong>{{/with}}
```

Les parenthèses imbriquent un résultat d'assistance dans un autre assistant. Ils n’évaluent pas les JavaScript arbitraires. Les arguments entre guillemets sont des chaînes littérales, tandis que les chemins sans guillemets lisent les données. `includeZero=true` est une option d'assistance nommée, pas une affectation aux données d'entrée.

## 10. Échappement HTML et valeurs CSS

```handlebars
<p>{{ params.recipient }}</p>
```

Pour `recipient` égal à `Tembuilder & Tembuilder`, la source HTML contient `Tembuilder &amp; Tembuilder` et le document affiche **Tembuilder & Tembuilder**. Conservez des accolades doubles pour une saisie ordinaire.

`{{{ params.trustedHtml }}}` et `{{& params.trustedHtml }}` insèrent HTML sans s'échapper. Utilisez-les uniquement pour le balisage fiable et aseptisé que vous avez l'intention de devenir des éléments de document. L'échappement n'est pas une validation d'URL ou de CSS. Validez les valeurs destinées à `href`, `src` ou aux styles.

Dans l'éditeur CSS, un accessoire Color contrôlé peut être lu directement :

```css
h1 { color: {{ props.accent }}; }
```

Donnez à `accent` une couleur valide telle que `#2563eb`. Handlebars fournit une substitution ; le résultat doit toujours être valide CSS.

## 11. Commentaires, espaces et accolades littérales

```handlebars
{{! Internal note, omitted from output }}
{{!-- A longer note that can include {{ expressions }} --}}
<span>{{ params.recipient ~}}</span>
```

`~` à côté d'un délimiteur coupe les espaces adjacents de ce côté. Utilisez-le avec précaution autour des mots qui nécessitent un espace de séparation. Handlebars supprime ses propres commentaires lors de la compilation. Tembuilder supprime également les commentaires HTML lors de la désinfection, de sorte qu'aucun des deux types ne reste dans le document final HTML.

Pour afficher une expression littérale plutôt que de l'évaluer :

```handlebars
<p>\{{ params.recipient }}</p>
```

Le document affiche `{{ params.recipient }}`. Les blocs bruts (`{{{{raw}}}}…{{{{/raw}}}}`) nécessitent un assistant de bloc enregistré ; cette plateforme ne fournit pas d'assistant `raw`.

## 12. Partiels et autres fonctionnalités avancées

Un partiel en ligne peut réutiliser le balisage **dans une source compilée** :

```handlebars
{{#*inline "recipientCard"}}
  <p>{{ name }}</p>
{{/inline}}
{{> recipientCard params.recipient}}
```

Il n'est pas partagé automatiquement entre les fichiers de section, les en-têtes ou les pieds de page. `{{> sharedCard}}` a besoin d'une définition ; Tembuilder n'expose pas de registre pour les partiels globaux définis par l'utilisateur ou les assistants JavaScript personnalisés.

Handlebars prend également en charge les paramètres partiels, la sélection partielle dynamique, les blocs partiels et les assistants de bloc personnalisés. Il s’agit de capacités linguistiques et non d’une promesse de fonctionnalités d’enregistrement sur la plateforme. Ne collez pas `registerHelper`, `registerPartial` ou les balises de script dans le modèle HTML en attendant qu'ils configurent la compilation.

L'assistant `log` intégré écrit dans le journal de l'environnement d'exécution plutôt que dans le PDF. Préférez Aperçu et Run pour inspecter la sortie ; évitez de consigner des données d’exécution sensibles. Les décorateurs et l'accès aux prototypes/méthodes ne sont pas nécessaires pour la création de documents : utilisez des valeurs JSON simples et les assistants documentés.

## 13. Exemple de section complète

Créez les Props de section `heading = "Invoice"` et les Props Global `company = "Tembuilder"`. Déclarez `recipient` (Objet avec `name` : Texte), `items` (Tableau d'objets avec `name` : Texte et `quantity` : Nombre), `paid` (Booléen) et `totalLabel` (Texte). Run avec :

```json
{
  "recipient": { "name": "Tembuilder" },
  "items": [{ "name": "Design", "quantity": 2 }],
  "paid": false,
  "totalLabel": "250,000 VND"
}
```

Coller dans la section HTML :

```handlebars
<h1>{{ props.heading }}</h1>
<p>{{ global.props.company }} → {{ params.recipient.name }}</p>
<ul>
  {{#each params.items}}
    <li>{{ this.name }} × {{ this.quantity }}</li>
  {{else}}
    <li>No items</li>
  {{/each}}
</ul>
<p>Total: {{ params.totalLabel }}</p>
<p>{{#if params.paid}}Paid{{else}}Awaiting payment{{/if}}</p>
```

Contenu attendu : **Facture**, **Tembuilder → Tembuilder**, **Design × 2**, **Total : 250 000 VND**, **En attente de paiement**. Essayez un tableau `items` vide et un `paid: true` pour vérifier les deux branches alternatives dans Preview/Run.

## 14. Dépannage et règles de création d'IA

| Symptôme | Vérifier |
| --- | --- |
| Valeur vide | Orthographe du champ, type déclaré, charge utile d'exécution, variante active et contexte actuel. |
| Mauvaise valeur dans une boucle | Utilisez `this`, un alias, `../` ou `@root` pour sélectionner le contexte souhaité. |
| Zéro caché | Utilisez `includeZero=true` où zéro est une valeur affichée valide. |
| Condition positive inattendue | Recherchez une chaîne `"false"` au lieu de la booléenne `false`. |
| Erreur de compilation | Faites correspondre les noms d'ouverture/fermeture de chaque bloc ; supprimez les opérateurs JavaScript et les assistants/partiels indisponibles. |
| `[object Object]` | Sélectionnez les champs de l'objet ou itérez-les au lieu d'imprimer l'objet entier. |

Pour les auteurs d'IA : conservez les noms et les types de champs déclarés, utilisez des espaces de noms explicites, calculez la logique métier avant le rendu, fournissez des états vides, conservez les valeurs ordinaires échappées et vérifiez les exemples par rapport aux données renseignées et vides. Une valeur manquante ne prouve pas une liaison réussie. Voir [erreurs courantes](/docs/fr/help/common-errors/).

## 15. Références officielles Handlebars

Utilisez le [guide officiel Handlebars](https://handlebarsjs.com/guide/) pour la documentation linguistique complète. Le comportement de la plateforme décrit ci-dessus est prioritaire lorsqu'un exemple en amont nécessite un enregistrement côté hôte ou une configuration d'exécution.

- [Expressions, échappement, chemins et espaces](https://handlebarsjs.com/guide/expressions.html)
- [Aide intégrée](https://handlebarsjs.com/guide/builtin-helpers.html)
- [Variables de données de boucle et de racine](https://handlebarsjs.com/api-reference/data-variables.html)
- [Partiaux et partiels en ligne](https://handlebarsjs.com/guide/partials.html)
- [Aide aux blocs personnalisés](https://handlebarsjs.com/guide/block-helpers.html)
