> ## Documentation Index
> Fetch the complete documentation index at: https://docs.landerlab.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Usa la Quiz API para una personalización avanzada

> Lee respuestas, modifica bloques, muévete entre pasos y envía tu quiz desde JavaScript.

La Quiz API permite que tu propio JavaScript se comunique con un quiz mientras un visitante lo rellena. Puedes leer lo que ha respondido, modificar un bloque, saltar a un paso o enviarlo, todo sin tocar el quiz en el editor.

Puedes usarla en cualquier sitio donde se ejecute JavaScript en la página: el código personalizado del propio quiz, un bloque de script o un fragmento de un gestor de etiquetas.

## Obtén la API

La API te la entrega el evento `ll-quiz-init` como `event.detail.llQuizApi`. Guarda ese objeto y úsalo siempre que lo necesites.

```javascript theme={null}
window.addEventListener('ll-quiz-init', (event) => {
  const quiz = event.detail.llQuizApi;

  quiz.getBlock('firstName').setValue('Ada');
});
```

<Note>
  Tu script puede ejecutarse antes o después de que se cargue el quiz. Si se registra tarde, `ll-quiz-init` se le reenvía automáticamente, así que este patrón siempre funciona.
</Note>

Todos los demás eventos del quiz incluyen el mismo `llQuizApi`, así que también puedes reaccionar a un paso o a una respuesta y actuar en ese mismo momento. Consulta [Eventos del quiz](/es/features/quizzes/api/events).

## Pasos y bloques por nombre

Todas las funciones que reciben un paso o un bloque aceptan **su nombre o su ID**. Los nombres son lo que escribiste en el editor, así que son lo que usarás normalmente. Los IDs se generan automáticamente y tienen este aspecto: `block-3f9c…`.

```javascript theme={null}
quiz.getBlock('email'); // por nombre
quiz.getBlock('block-3f9c1a2e-…'); // por ID, mismo resultado
quiz.getBlocksByStep('contact');
```

<Tip>
  Ponle un nombre claro a cada bloque y a cada paso en el editor. Es la única configuración que necesita la API.
</Tip>

Si dos bloques o dos pasos comparten nombre, se usa el primero según el orden del quiz.

## Lee las respuestas

`getAnswers()` devuelve todas las respuestas dadas hasta el momento, una entrada por bloque. `getAnswersSimple()` devuelve las mismas respuestas como un objeto sencillo cuyas claves son las etiquetas. Los bloques ocultos y las respuestas vacías no se incluyen.

```javascript theme={null}
quiz.getAnswers();
// [{ id: 'firstName', label: 'First name', value: 'Ada', key: 'firstName', stepId: 'step-…', stepName: 'contact' }, …]

quiz.getAnswersSimple();
// { 'First name': 'Ada', 'Plan': 'pro' }
```

Son exactamente los `fields` y `fieldsSimple` que incluyen los eventos, así que el código que gestiona uno gestiona los dos.

## Sabe dónde está el visitante

```javascript theme={null}
quiz.getCurrentStep(); // { id: 'step-…', name: 'contact', index: 1, total: 4 }
quiz.getCurrentStepBlocks(); // los bloques de ese paso
quiz.getSteps(); // [{ id, name, index }, …] en el orden del quiz
quiz.getInfo(); // { quizId: 'quiz-…', isSubmitted: false }
```

`index` empieza en 0. `isSubmitted` pasa a true en cuanto esta visita envía el quiz.

## Encuentra bloques

| Llamada                     | Devuelve                                  |
| :-------------------------- | :---------------------------------------- |
| `getBlocks()`               | Todos los bloques que contienen un valor  |
| `getBlock(nameOrId)`        | Un bloque                                 |
| `getBlocksByStep(nameOrId)` | Los bloques de un paso                    |
| `getCurrentStepBlocks()`    | Los bloques del paso que está en pantalla |

Las listas solo contienen bloques que guardan un valor. Los títulos, párrafos, imágenes y similares nunca aparecen. Además, `getBlock()` encuentra botones (Continue, Previous, Submit, Button), así que puedes cambiar su texto o desactivarlos.

<Warning>
  `getBlock()` nunca devuelve `undefined`. Si no hay coincidencias, o si el bloque no puede contener un valor, obtienes un bloque de reserva: cada llamada sobre él muestra un aviso en la consola y no hace nada, y `getValue()` devuelve `""`. Tu código nunca falla, pero revisa la consola si algo no tiene efecto.
</Warning>

<Accordion title="¿Qué bloques contienen un valor?">
  Campos de entrada (texto, email, teléfono, número, área de texto, fecha, fecha de nacimiento, código postal, dirección, OTP), opciones (opción múltiple, elección con imágenes, desplegable), casilla de verificación, control deslizante de rango, subida de archivos, firma y campos ocultos.

  Todo lo demás es visual o de navegación: título, párrafo, imagen, vídeo, separador, lista, loader, cuenta atrás, progreso, acordeón, enlaces, código personalizado, seguimiento y los botones. Llamar a `getValue()`, `setValue()`, `reset()` o `validate()` sobre uno de ellos lanza un error. Los contenedores son transparentes: los bloques que contienen se listan como cualquier otro bloque.
</Accordion>

## Lee y modifica un bloque

Todos los bloques que obtienes son el mismo tipo de objeto, así que los ejemplos siguientes funcionan en cualquier bloque que admita la llamada.

### Valor

```javascript theme={null}
const name = quiz.getBlock('firstName');

name.getValue(); // 'Ada'
name.setValue('Grace');
name.reset(); // vuelve a estar vacío
```

Establecer un valor mediante la API dispara `ll-quiz-value-change` con `source: 'api'`, así que tus listeners pueden distinguirlo de cuando escribe el visitante.

<AccordionGroup>
  <Accordion title="Formatos de valor por bloque">
    * **Casilla de verificación**: `'checked'` o `'unchecked'`
    * **Opción múltiple, elección con imágenes, desplegable**: el valor de la opción, por ejemplo `'pro'`
    * **Opción múltiple con varias selecciones**: los valores unidos por el separador configurado en el bloque
    * **Todo lo demás**: el texto que escribió el visitante
  </Accordion>
</AccordionGroup>

### Etiqueta y placeholder

```javascript theme={null}
name.getLabel(); // 'First name'
name.setLabel('Given name');

name.getPlaceholder(); // 'Ada'
name.setPlaceholder('Type your first name');

quiz.getBlock('continue-1').setLabel('Next step'); // también en botones
```

Las etiquetas son texto plano, salvo en una casilla de verificación, donde se permite HTML para enlazar a los términos. `setLabel()` y `getLabel()` lanzan un error en los bloques que no tienen etiqueta.

### Opciones

Los bloques de opción múltiple, elección con imágenes y desplegable exponen sus opciones:

```javascript theme={null}
quiz.getBlock('plan').getOptions();
// [{ id: 'option-…', label: 'Pro', value: 'pro', selected: true }, …]
```

Llamar a `getOptions()` en cualquier otro bloque lanza un error.

### Errores y foco

```javascript theme={null}
name.getErrors(); // ['This field is required.'] tras una validación fallida, [] en caso contrario
name.focus(); // mueve el cursor a ese campo
```

### Botones

```javascript theme={null}
const next = quiz.getBlock('continue-1');
next.disable();
await checkSomething(); // tu propio trabajo asíncrono
next.enable();
```

`enable()` y `disable()` funcionan en los bloques Continue, Submit y Button, y lanzan un error en cualquier otro.

### Visibilidad

```javascript theme={null}
const promo = quiz.getBlock('promoCode');

promo.visibility.hide();
promo.visibility.show();
promo.visibility.get(); // true, false o undefined (sin override)
promo.visibility.clear(); // elimina tu override
```

Un bloque oculto no se valida, no se envía con el lead y no se muestra. `undefined` significa que nunca lo has cambiado, así que el bloque sigue su propia configuración.

## Valida

```javascript theme={null}
const step = await quiz.validateStep('contact'); // { success: false }
const block = await quiz.getBlock('email').validate(); // { success: false, errors: ['Invalid email address.'] }
```

La validación es asíncrona porque los campos de email, teléfono y OTP se comprueban contra un servidor. Los bloques ocultos siempre la superan.

<Info>
  Cuando un paso falla, el quiz también dispara `ll-quiz-validation-error` con cada bloque que falla y su mensaje, marcado con `source: 'api'`. Así, un solo listener puede gestionar tanto los intentos del visitante como los tuyos. Tienes los detalles en la [página de eventos](/es/features/quizzes/api/events#ll-quiz-validation-error).
</Info>

## Navega y envía

```javascript theme={null}
await quiz.navigation.goNext();
quiz.navigation.goBack();
await quiz.navigation.goToStep('summary'); // nombre o ID
await quiz.navigation.submit();
quiz.navigation.goToUrl('https://example.com'); // añade `true` para abrir una pestaña nueva
```

`goNext()`, `goToStep()` y `submit()` validan primero el paso que está en pantalla. Si no es válido, no avanzan, muestran un aviso en la consola y disparan `ll-quiz-validation-error`. `goBack()` nunca valida.

`submit()` hace exactamente lo mismo que el botón Submit del visitante: se guarda el lead, se dispara `ll-quiz-submit` con la respuesta del servidor, se aplica la protección de envío único y se ejecuta la acción posterior al envío del botón Submit. En un paso sin botón Submit, el quiz se envía y se queda donde está. La promesa devuelta se resuelve cuando todo eso ha terminado.

## Recetas

<AccordionGroup>
  <Accordion title="Rellena campos desde la URL">
    ```javascript theme={null}
    window.addEventListener('ll-quiz-init', (event) => {
      const quiz = event.detail.llQuizApi;
      const params = new URLSearchParams(window.location.search);

      if (params.get('email')) quiz.getBlock('email').setValue(params.get('email'));
      if (params.get('plan')) quiz.getBlock('plan').setValue(params.get('plan'));
    });
    ```
  </Accordion>

  <Accordion title="Muestra un texto de progreso personalizado">
    ```javascript theme={null}
    window.addEventListener('ll-quiz-step-view', (event) => {
      const { index, total } = event.detail.llQuizApi.getCurrentStep();
      document.querySelector('#progress').textContent = `Step ${index + 1} of ${total}`;
    });
    ```
  </Accordion>

  <Accordion title="Salta al primer campo con un error">
    ```javascript theme={null}
    window.addEventListener('ll-quiz-validation-error', (event) => {
      const { errors, llQuizApi } = event.detail;
      llQuizApi.getBlock(errors[0].blockId).focus();
    });
    ```
  </Accordion>

  <Accordion title="Bloquea el botón Continue hasta que pase tu propia comprobación">
    ```javascript theme={null}
    window.addEventListener('ll-quiz-step-view', async (event) => {
      const quiz = event.detail.llQuizApi;
      if (quiz.getCurrentStep().name !== 'eligibility') return;

      const next = quiz.getBlock('continue-eligibility');
      next.disable();
      const ok = await fetch('/api/eligible?zip=' + quiz.getBlock('zip').getValue()).then((r) => r.ok);
      if (ok) next.enable();
      else next.setLabel('Not available in your area');
    });
    ```
  </Accordion>

  <Accordion title="Muestra un bloque solo para una respuesta concreta">
    ```javascript theme={null}
    window.addEventListener('ll-quiz-value-change', (event) => {
      const { blockName, value, llQuizApi } = event.detail;
      if (blockName !== 'plan') return;

      const promo = llQuizApi.getBlock('promoCode');
      value === 'premium' ? promo.visibility.show() : promo.visibility.hide();
    });
    ```
  </Accordion>

  <Accordion title="Envía el quiz desde tu propio botón">
    ```javascript theme={null}
    window.addEventListener('ll-quiz-init', (event) => {
      const quiz = event.detail.llQuizApi;

      document.querySelector('#my-submit').addEventListener('click', async () => {
        await quiz.navigation.submit(); // valida primero; se resuelve después de que se dispare ll-quiz-submit
        if (quiz.getInfo().isSubmitted) window.location.href = '/thank-you';
      });
    });
    ```
  </Accordion>

  <Accordion title="Envía las respuestas a tu propio endpoint">
    ```javascript theme={null}
    window.addEventListener('ll-quiz-submit', (event) => {
      fetch('https://example.com/leads', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(event.detail.fieldsSimple),
      });
    });
    ```
  </Accordion>
</AccordionGroup>

## Todas las funciones de un vistazo

| Función                                                                      | Qué hace                                             |
| :--------------------------------------------------------------------------- | :--------------------------------------------------- |
| `getAnswers()` / `getAnswersSimple()`                                        | Respuestas hasta el momento                          |
| `getCurrentStep()` / `getCurrentStepBlocks()`                                | El paso en pantalla y sus bloques                    |
| `getSteps()` / `getInfo()`                                                   | Todos los pasos; ID del quiz y si se ha enviado o no |
| `getBlocks()` / `getBlock()` / `getBlocksByStep()`                           | Encontrar bloques                                    |
| `validateStep(nameOrId)`                                                     | Validar un paso                                      |
| `navigation.goNext()` / `goBack()` / `goToStep()` / `submit()` / `goToUrl()` | Moverse y enviar                                     |

| En un bloque                                                          | Qué hace                                        |
| :-------------------------------------------------------------------- | :---------------------------------------------- |
| `getValue()` / `setValue()` / `reset()`                               | La respuesta                                    |
| `getLabel()` / `setLabel()` / `getPlaceholder()` / `setPlaceholder()` | Textos                                          |
| `getOptions()`                                                        | Opciones de un bloque de elección o desplegable |
| `validate()` / `getErrors()` / `focus()`                              | Validación                                      |
| `enable()` / `disable()`                                              | Botones                                         |
| `visibility.show()` / `hide()` / `get()` / `clear()`                  | Mostrar u ocultar                               |
| `blockID` / `blockType` / `variableName`                              | Identidad                                       |

<Accordion title="Nombres de funciones antiguos (siguen siendo compatibles)">
  Las versiones anteriores tenían una función por cada tipo de búsqueda. Siguen funcionando exactamente igual que antes, así que no necesitas cambiar nada de lo que ya hayas escrito. El código nuevo debería usar las funciones unificadas.

  | Nombre antiguo                                        | Usa en su lugar     |
  | :---------------------------------------------------- | :------------------ |
  | `getBlockByID(id)` / `getBlockByName(name)`           | `getBlock()`        |
  | `getBlocksByStepID(id)` / `getBlocksByStepName(name)` | `getBlocksByStep()` |
  | `validateStepByID(id)` / `validateStepByName(name)`   | `validateStep()`    |
</Accordion>
