# Referencia de sintaxis de Handlebars

Incorpore parámetros y props a su plantilla con Handlebars, desde mostrar texto hasta crear tablas y contenido condicional.

Al diseñar una plantilla, a menudo es necesario incluir datos en su contenido: el nombre de un destinatario de `params`, un encabezado de `props` o una lista de productos mostrados como filas de una tabla. Tembuilder usa **Handlebars** para conectar estos valores a su HTML/CSS. Su sintaxis le permite marcar dónde deben aparecer los datos y describir cómo se debe mostrar el contenido.

Por ejemplo, escribe `{{ params.recipient }}` donde pertenece el nombre del destinatario. Cuando obtiene una vista previa del documento o genera un PDF, Tembuilder lee el valor coincidente y reemplaza la expresión con el contenido real. Esto le permite reutilizar el mismo diseño con diferentes conjuntos de datos.

Esta guía lo guía a través de la lectura de valores de [Parameters](/docs/es/data/parameters/) y [Props](/docs/es/data/parameters-props/), mostrando contenido condicionalmente, repitiendo listas y usando sintaxis avanzada cuando su plantilla necesita estructuras de datos más complejas.

## 1. De la plantilla al documento

Comience con un ejemplo simple: ha creado un accesorio de sección `heading` con el valor `Invoice` y ha declarado un parámetro `recipient` con el valor `Tembuilder`. En el HTML de la sección, coloca cada valor donde quieras que aparezca usando `{{ ... }}`:

```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="La plantilla HTML y los datos se convierten en contenido del documento">
<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>Factura</strong><div><p>Tembuilder</p></div></div></div></div>
<figcaption>Las expresiones se reemplazan antes de la paginación PDF.</figcaption>
</figure>

## 2. Elija la ruta de datos correcta

| Camino | Lecturas |
| --- | --- |
| `{{ params.recipient }}` | Datos proporcionados para esta ejecución, después de aplicar los valores predeterminados. |
| `{{ props.heading }}` | Props para la parte que se está compilando. En una sección, los valores de la sección anulan los valores Global con el mismo nombre. |
| `{{ global.props.company }}` | Global props explícitamente, incluso cuando una sección anula el mismo nombre. |
| `{{ @root.params.recipient }}` | Datos Run desde dentro de un bucle o bloque `with`. |

Utilice rutas `params.` explícitas en lugar de nombres de parámetros simples. Los nombres de los parámetros raíz también se exponen por motivos de compatibilidad, pero nombres como `props`, `params` y `global` están ocupados por el contexto de la plataforma.

Cada sección, encabezado y pie de página se compila con su propio contexto. `@root` significa la raíz de esa compilación, no otra sección. [Variants](/docs/es/data/variants/) selecciona anulaciones de Props antes de ejecutar las expresiones.

## 3. Texto, números, valores booleanos y valores faltantes

El siguiente objeto es **ejecutar datos**: ingrese sus campos en Run sin agregar un contenedor externo `params`. Declare tipos coincidentes en 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}}
```

El texto se muestra como texto, los números muestran su valor y la impresión directa de un booleano produce `true` o `false`. Utilice una condición para una etiqueta fácil de leer. Mantenga `2` numérico y `false` booleano; `"2"` y `"false"` son cadenas.

Un valor no resuelto normalmente no imprime nada. Esto no sustituye a declarar campos obligatorios o validar datos de ejecución. La sintaxis no es válida o un asistente desconocido detiene la compilación.

Handlebars no calcula `quantity * price`, no llama a `.toFixed(2)` ni formatea fechas/monedas automáticamente. Prepare totales y cadenas formateadas antes de renderizar. `{{ params.quantity + 1 }}` y `{{ params.total.toFixed(2) }}` no son expresiones compatibles con JavaScript.

## 4. Objetos y nombres de propiedades

```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>
```

Utilice nombres de campo como `recipientName` o `postal_code`. El editor reemplaza espacios, guiones y otros caracteres fuera de letras, dígitos y guiones bajos con `_`; el primer carácter debe ser una letra o un guión bajo. Para un esquema importado existente con claves como `postal code`, Handlebars puede leerlas usando `{{ params.labels.[postal code] }}`. Esa sintaxis no cambia las reglas de nomenclatura del editor. Para representar un objeto de manera significativa, seleccione sus campos o repítalos; imprimir todo el objeto no es una serialización JSON.

## 5. Condiciones: `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` toma la rama negativa para `false`, `null`, valores faltantes, una cadena vacía, cero y una matriz vacía. `includeZero=true` hace que el cero tome la rama positiva. Un objeto vacío y la cadena `"false"` toman la rama positiva. `unless` invierte la condición. `if` no cambia el contexto actual.

No hay asistentes `eq`, `gt`, `and` o `or` integrados en esta plataforma. Calcule un booleano como `overdue` en la entrada en lugar de escribir `{{#if params.balance > 0}}`.

## 6. Arrays: `each` y estados vacíos

```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` es el elemento actual: un objeto para `items`, una cadena para `tags`. El acceso directo a la matriz es posible con `{{ params.items.[0].name }}`. Para tablas largas, siga la [guía de paginación](/docs/es/editor/pagination/).

<figure class="doc-sim data-assets-illustration" aria-label="Cada elemento de la matriz se convierte en una fila de la tabla; las matrices vacías usan otra cosa">
<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>Artículo</b><b>Cantidad</b></div><div><span>Diseño</span><span>2</span></div><div><span>Revisión</span><span>1</span></div></div></div>
<figcaption>Un artículo → una fila. Una lista vacía → la rama else.</figcaption>
</figure>

## 7. Metadatos de bucle e iteración de objetos

| Expresión | Significado dentro de `each` |
| --- | --- |
| `@index` | Posición del array, comenzando en cero. |
| `@first`, `@last` | Banderas del primer/último elemento de la matriz. |
| `@key` | Nombre de propiedad al iterar un objeto. |

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

No utilice `@index + 1` para crear números de fila. Proporcione un campo `rowNumber` si necesita una numeración que comience en uno.

## 8. Contexto: `with`, rutas padre y raíz

```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` y `each` cambian de contexto. `../` vuelve al contexto principal; `@root` proporciona acceso estable a la raíz de compilación a través de bucles anidados. Agregar un `if` no requiere otro `../`.

Los alias hacen que las listas anidadas sean más fáciles de seguir. Aquí, declara `groups` como una matriz de objetos, cada uno con una matriz `name` y una matriz `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. Búsqueda dinámica y subexpresiones

Utilice `lookup` para una clave proporcionada como datos. Declare `labels` como objeto y `selectedKey` como Texto; Para `{ "labels": { "approved": "Approved" }, "selectedKey": "approved" }`:

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

Los paréntesis anidan un resultado auxiliar dentro de otro auxiliar. No evalúan JavaScript arbitrario. Los argumentos entre comillas son cadenas literales, mientras que las rutas sin comillas leen datos. `includeZero=true` es una opción de ayuda con nombre, no una asignación para ingresar datos.

## 10. Escape HTML y valores CSS

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

Para `recipient` igual a `Tembuilder & Tembuilder`, la fuente HTML contiene `Tembuilder &amp; Tembuilder` y el documento muestra **Tembuilder & Tembuilder**. Mantenga llaves dobles para la entrada ordinaria.

`{{{ params.trustedHtml }}}` y `{{& params.trustedHtml }}` insertan HTML sin escapar. Úselos únicamente para marcas confiables y desinfectadas que desee convertir en elementos del documento. Escapar no es una validación de URL o CSS. Valide los valores destinados a `href`, `src` o estilos.

En el editor CSS, un accesorio de color controlado se puede leer directamente:

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

Asigne a `accent` un color válido como `#2563eb`. Handlebars proporciona sustitución; el resultado aún debe ser válido CSS.

## 11. Comentarios, espacios en blanco y llaves literales

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

`~` junto a un delimitador recorta los espacios en blanco adyacentes en ese lado. Úselo con cuidado alrededor de palabras que necesitan un espacio de separación. Handlebars elimina sus propios comentarios durante la compilación. Tembuilder también elimina los comentarios de HTML durante la desinfección, por lo que ninguno de los tipos permanece en el documento final HTML.

Para mostrar una expresión literal en lugar de evaluarla:

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

El documento muestra `{{ params.recipient }}`. Los bloques sin formato (`{{{{raw}}}}…{{{{/raw}}}}`) requieren un asistente de bloque registrado; Esta plataforma no proporciona un asistente `raw`.

## 12. Parciales y otras funciones avanzadas

Un parcial en línea puede reutilizar el marcado **dentro de una fuente compilada**:

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

No se comparte automáticamente entre archivos de sección, encabezados o pies de página. `{{> sharedCard}}` necesita una definición; Tembuilder no expone un registro para parciales globales definidos por el usuario ni ayudantes personalizados de JavaScript.

Handlebars también admite parámetros parciales, selección parcial dinámica, bloques parciales y ayudas de bloques personalizados. Estas son capacidades de idioma, no una promesa de funciones de registro en la plataforma. No pegue etiquetas `registerHelper`, `registerPartial` o script en la plantilla HTML esperando que configuren la compilación.

El asistente integrado `log` escribe en el registro del entorno de ejecución en lugar de en PDF. Prefiera Vista previa y Run para inspeccionar la salida; Evite registrar datos de ejecución confidenciales. No se necesitan decoradores ni acceso a prototipos/métodos para la creación de documentos: utilice valores JSON simples y los ayudantes documentados.

## 13. Ejemplo de sección completa

Cree el accesorio de sección `heading = "Invoice"` y el accesorio Global `company = "Tembuilder"`. Declare `recipient` (Objeto con `name`: Texto), `items` (Matriz de objetos con `name`: Texto y `quantity`: Número), `paid` (Booleano) y `totalLabel` (Texto). Run con:

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

Pegar en la sección 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>
```

Contenido esperado: **Factura**, **Tembuilder → Tembuilder**, **Diseño × 2**, **Total: 250 000 VND**, **Pendiente de pago**. Pruebe con una matriz `items` vacía y `paid: true` para verificar ambas ramas alternativas en Vista previa/Run.

## 14. Resolución de problemas y reglas de creación de IA

| Síntoma | Verificar |
| --- | --- |
| Valor vacío | Ortografía del campo, tipo declarado, carga útil de ejecución, variante activa y contexto actual. |
| Valor incorrecto dentro de un bucle | Utilice `this`, un alias, `../` o `@root` para seleccionar el contexto deseado. |
| Cero oculto | Utilice `includeZero=true` donde cero es un valor mostrado válido. |
| Condición positiva inesperada | Busque una cadena `"false"` en lugar del booleano `false`. |
| Error de compilación | Haga coincidir los nombres de apertura/cierre de cada bloque; elimine los operadores JavaScript y los ayudantes/parciales no disponibles. |
| `[object Object]` | Seleccione campos de objetos o repítalos en lugar de imprimir el objeto completo. |

Para autores de IA: conserve los nombres y tipos de campos declarados, utilice espacios de nombres explícitos, calcule la lógica empresarial antes de renderizar, proporcione estados vacíos, mantenga los valores ordinarios escapados y verifique ejemplos con datos tanto completos como vacíos. Un valor faltante no demuestra una vinculación exitosa. Consulte [errores comunes](/docs/es/help/common-errors/).

## 15. Referencias oficiales de Handlebars

Utilice la [guía oficial Handlebars](https://handlebarsjs.com/guide/) para obtener la documentación completa en el idioma. El comportamiento de la plataforma descrito anteriormente tiene prioridad cuando un ejemplo ascendente requiere registro del lado del host o configuración del tiempo de ejecución.

- [Expresiones, escape, rutas y espacios en blanco](https://handlebarsjs.com/guide/expressions.html)
- [Ayudantes incorporados](https://handlebarsjs.com/guide/builtin-helpers.html)
- [Variables de datos de bucle y raíz](https://handlebarsjs.com/api-reference/data-variables.html)
- [Parciales y parciales en línea](https://handlebarsjs.com/guide/partials.html)
- [Ayudantes de bloqueo personalizados](https://handlebarsjs.com/guide/block-helpers.html)
