> ## 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.

# Use a API do quiz para personalizações avançadas

> Leia respostas, altere blocos, navegue entre etapas e envie seu quiz via JavaScript.

A API do quiz permite que o seu próprio JavaScript se comunique com um quiz enquanto o visitante o preenche. Você pode ler o que ele respondeu, alterar um bloco, pular para uma etapa ou enviar o quiz, tudo isso sem mexer no quiz no construtor.

Você pode usá-la em qualquer lugar da página onde o JavaScript rode: no código personalizado do próprio quiz, em um bloco de script ou em um snippet de um gerenciador de tags.

## Obtenha a API

A API é entregue a você pelo evento `ll-quiz-init`, em `event.detail.llQuizApi`. Guarde esse objeto e use-o sempre que precisar.

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

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

<Note>
  Seu script pode rodar antes ou depois de o quiz carregar. Se ele for registrado depois, o `ll-quiz-init` é reenviado a ele automaticamente, então esse padrão sempre funciona.
</Note>

Todos os outros eventos do quiz trazem o mesmo `llQuizApi`, então você também pode reagir a uma etapa ou a uma resposta e agir ali mesmo. Veja [Eventos do quiz](/pt-BR/features/quizzes/api/events).

## Etapas e blocos pelo nome

Todas as funções que recebem uma etapa ou um bloco aceitam **o nome ou o ID**. Os nomes são o que você digitou no construtor, então é o que você normalmente vai usar. Os IDs são gerados automaticamente e têm o formato `block-3f9c…`.

```javascript theme={null}
quiz.getBlock('email'); // by name
quiz.getBlock('block-3f9c1a2e-…'); // by ID, same result
quiz.getBlocksByStep('contact');
```

<Tip>
  Dê um nome claro a cada bloco e etapa no construtor. Essa é a única configuração de que a API precisa.
</Tip>

Se dois blocos ou duas etapas tiverem o mesmo nome, será usado o primeiro na ordem do quiz.

## Leia as respostas

`getAnswers()` retorna todas as respostas dadas até o momento, com uma entrada por bloco. `getAnswersSimple()` retorna as mesmas respostas em um objeto simples, usando o rótulo (label) como chave. Blocos ocultos e respostas vazias ficam de fora.

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

São exatamente os mesmos `fields` e `fieldsSimple` que os eventos trazem, então o código que trata um formato também trata o outro.

## Saiba onde o visitante está

```javascript theme={null}
quiz.getCurrentStep(); // { id: 'step-…', name: 'contact', index: 1, total: 4 }
quiz.getCurrentStepBlocks(); // the blocks on that step
quiz.getSteps(); // [{ id, name, index }, …] in quiz order
quiz.getInfo(); // { quizId: 'quiz-…', isSubmitted: false }
```

`index` começa em 0. `isSubmitted` passa a ser true assim que o quiz é enviado nesta visita.

## Encontre blocos

| Chamada                     | Retorno                                |
| :-------------------------- | :------------------------------------- |
| `getBlocks()`               | Todos os blocos que armazenam um valor |
| `getBlock(nameOrId)`        | Um bloco                               |
| `getBlocksByStep(nameOrId)` | Os blocos de uma etapa                 |
| `getCurrentStepBlocks()`    | Os blocos da etapa exibida na tela     |

As listas contêm apenas blocos que armazenam um valor. Títulos, parágrafos, imagens e afins nunca são listados. Além disso, `getBlock()` também encontra botões (Continue, Previous, Submit, Button), para que você possa alterar o texto deles ou desativá-los.

<Warning>
  `getBlock()` nunca retorna `undefined`. Se nada corresponder, ou se o bloco não puder armazenar um valor, você recebe um bloco substituto: cada chamada nele registra um aviso e não faz nada, e `getValue()` retorna `""`. Seu código nunca quebra, mas confira o console se algo não tiver efeito.
</Warning>

<Accordion title="Quais blocos armazenam um valor?">
  Campos de entrada (text, email, phone, number, textarea, date, birth date, zip code, address, OTP), campos de escolha (multiple choice, image choice, select), checkbox, range slider, upload, signature e campos ocultos (hidden).

  Todo o resto é de exibição ou navegação: headline, paragraph, image, video, divider, list, loader, countdown, progress, accordion, links, custom code, tracking e os botões. Chamar `getValue()`, `setValue()`, `reset()` ou `validate()` em um desses blocos lança um erro. Os contêineres são transparentes: os blocos dentro deles são listados como qualquer outro bloco.
</Accordion>

## Leia e altere um bloco

Todo bloco retornado é o mesmo tipo de objeto, então os exemplos abaixo funcionam em qualquer bloco compatível com a chamada.

### Valor

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

name.getValue(); // 'Ada'
name.setValue('Grace');
name.reset(); // back to empty
```

Definir um valor pela API dispara o `ll-quiz-value-change` com `source: 'api'`, para que seus listeners consigam diferenciá-lo do que o visitante digita.

<AccordionGroup>
  <Accordion title="Formatos de valor por bloco">
    * **Checkbox**: `'checked'` ou `'unchecked'`
    * **Multiple choice, image choice, select**: o valor da opção, por exemplo `'pro'`
    * **Multiple choice com várias seleções**: os valores unidos pelo separador configurado no bloco
    * **Todos os outros**: o texto que o visitante digitou
  </Accordion>
</AccordionGroup>

### Rótulo e 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'); // buttons too
```

Os rótulos são texto simples, exceto no checkbox, que aceita HTML para incluir links para os termos. `setLabel()` e `getLabel()` lançam um erro em blocos que não têm rótulo.

### Opções

Os blocos multiple choice, image choice e select expõem suas opções:

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

Chamar `getOptions()` em qualquer outro bloco lança um erro.

### Erros e foco

```javascript theme={null}
name.getErrors(); // ['This field is required.'] after a failed validation, [] otherwise
name.focus(); // move the cursor there
```

### Botões

```javascript theme={null}
const next = quiz.getBlock('continue-1');
next.disable();
await checkSomething(); // your own async work
next.enable();
```

`enable()` e `disable()` funcionam nos blocos Continue, Submit e Button e lançam um erro em qualquer outro.

### Visibilidade

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

promo.visibility.hide();
promo.visibility.show();
promo.visibility.get(); // true, false or undefined (no override)
promo.visibility.clear(); // remove your override
```

Um bloco oculto não é validado, não é enviado com o lead e não é exibido. `undefined` significa que você nunca alterou a visibilidade, então o bloco segue as próprias configurações.

## Valide

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

A validação é assíncrona porque os campos de e-mail, telefone e OTP são verificados em um servidor. Blocos ocultos sempre passam.

<Info>
  Quando uma etapa não passa na validação, o quiz também dispara o `ll-quiz-validation-error` com cada bloco que falhou e a respectiva mensagem, marcado com `source: 'api'`. Assim, um único listener consegue tratar tanto as tentativas do visitante quanto as suas. Veja os detalhes na [página de eventos](/pt-BR/features/quizzes/api/events#ll-quiz-validation-error).
</Info>

## Navegue e envie

```javascript theme={null}
await quiz.navigation.goNext();
quiz.navigation.goBack();
await quiz.navigation.goToStep('summary'); // name or ID
await quiz.navigation.submit();
quiz.navigation.goToUrl('https://example.com'); // add `true` to open a new tab
```

`goNext()`, `goToStep()` e `submit()` validam primeiro a etapa exibida na tela. Se ela for inválida, eles não avançam, registram um aviso e disparam o `ll-quiz-validation-error`. `goBack()` nunca valida.

`submit()` faz exatamente o que o botão Submit faz para o visitante: o lead é salvo, o `ll-quiz-submit` é disparado com a resposta do servidor, a proteção contra envios duplicados é aplicada e a ação pós-envio do botão Submit é executada. Em uma etapa sem botão Submit, o quiz é enviado e permanece na mesma etapa. A promise retornada é resolvida quando tudo isso termina.

## Receitas

<AccordionGroup>
  <Accordion title="Preencher a partir da 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="Mostrar um texto de progresso 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="Ir para o primeiro campo com erro">
    ```javascript theme={null}
    window.addEventListener('ll-quiz-validation-error', (event) => {
      const { errors, llQuizApi } = event.detail;
      llQuizApi.getBlock(errors[0].blockId).focus();
    });
    ```
  </Accordion>

  <Accordion title="Segurar o botão Continue até a sua própria verificação passar">
    ```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="Mostrar um bloco apenas para uma resposta">
    ```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="Enviar a partir do seu próprio botão">
    ```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(); // validates first; resolves after ll-quiz-submit fired
        if (quiz.getInfo().isSubmitted) window.location.href = '/thank-you';
      });
    });
    ```
  </Accordion>

  <Accordion title="Enviar as respostas para o seu próprio 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 as funções em resumo

| Função                                                                       | O que faz                                               |
| :--------------------------------------------------------------------------- | :------------------------------------------------------ |
| `getAnswers()` / `getAnswersSimple()`                                        | Respostas até o momento                                 |
| `getCurrentStep()` / `getCurrentStepBlocks()`                                | A etapa exibida na tela e seus blocos                   |
| `getSteps()` / `getInfo()`                                                   | Todas as etapas; ID do quiz e se ele foi enviado ou não |
| `getBlocks()` / `getBlock()` / `getBlocksByStep()`                           | Encontrar blocos                                        |
| `validateStep(nameOrId)`                                                     | Validar uma etapa                                       |
| `navigation.goNext()` / `goBack()` / `goToStep()` / `submit()` / `goToUrl()` | Navegar e enviar                                        |

| Em um bloco                                                           | O que faz                               |
| :-------------------------------------------------------------------- | :-------------------------------------- |
| `getValue()` / `setValue()` / `reset()`                               | A resposta                              |
| `getLabel()` / `setLabel()` / `getPlaceholder()` / `setPlaceholder()` | Textos                                  |
| `getOptions()`                                                        | Opções de um bloco de escolha ou select |
| `validate()` / `getErrors()` / `focus()`                              | Validação                               |
| `enable()` / `disable()`                                              | Botões                                  |
| `visibility.show()` / `hide()` / `get()` / `clear()`                  | Mostrar ou ocultar                      |
| `blockID` / `blockType` / `variableName`                              | Identificação                           |

<Accordion title="Nomes de funções antigos (ainda compatíveis)">
  As versões anteriores tinham uma função para cada tipo de busca. Elas continuam funcionando exatamente como antes, então nada do que você já escreveu precisa mudar. Em código novo, use as funções unificadas.

  | Nome antigo                                           | Use em vez disso    |
  | :---------------------------------------------------- | :------------------ |
  | `getBlockByID(id)` / `getBlockByName(name)`           | `getBlock()`        |
  | `getBlocksByStepID(id)` / `getBlocksByStepName(name)` | `getBlocksByStep()` |
  | `validateStepByID(id)` / `validateStepByName(name)`   | `validateStep()`    |
</Accordion>
