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

# Quiz API: управление квизом из JavaScript

> Читайте ответы, меняйте блоки, переходите между шагами и отправляйте квиз из JavaScript с помощью Quiz API и объекта llQuizApi.

Quiz API позволяет вашему JavaScript взаимодействовать с квизом, пока посетитель его заполняет. Вы можете прочитать ответы, изменить блок, перейти на нужный шаг или отправить квиз — не открывая сам квиз в конструкторе.

API можно использовать везде, где на странице выполняется JavaScript: в собственном коде квиза, в скрипт-блоке или в сниппете менеджера тегов.

## Как получить API

API передаётся вам в событии `ll-quiz-init` как `event.detail.llQuizApi`. Сохраните этот объект и используйте его, когда нужно.

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

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

<Note>
  Ваш скрипт может выполниться до или после загрузки квиза. Если он зарегистрируется поздно, событие `ll-quiz-init` автоматически отправится ему повторно, поэтому такой подход работает всегда.
</Note>

Каждое другое событие квиза тоже содержит `llQuizApi`, поэтому вы можете реагировать на шаг или ответ и действовать прямо в обработчике. См. [События квиза](/ru/features/quizzes/api/events).

## Шаги и блоки по имени

Каждая функция, принимающая шаг или блок, принимает **его имя или ID**. Имя — это то, что вы ввели в конструкторе, поэтому обычно используют его. ID генерируются автоматически и выглядят как `block-3f9c…`.

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

<Tip>
  Дайте каждому блоку и шагу понятное имя в конструкторе. Это единственная настройка, которая нужна для работы с API.
</Tip>

Если у двух блоков или двух шагов одинаковое имя, используется первый по порядку в квизе.

## Чтение ответов

`getAnswers()` возвращает все данные на данный момент ответы — по одной записи на блок. `getAnswersSimple()` возвращает те же ответы в виде простого объекта, ключами которого служат метки (label). Скрытые блоки и пустые ответы не включаются.

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

Это в точности те же `fields` и `fieldsSimple`, которые передают события, поэтому код, обрабатывающий одно, подойдёт и для другого.

## Где находится посетитель

```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` начинается с 0. `isSubmitted` становится `true`, когда в этом визите квиз был отправлен.

## Поиск блоков

| Вызов | Что возвращает |
| :- | :- |
| `getBlocks()` | Все блоки, которые хранят значение |
| `getBlock(nameOrId)` | Один блок |
| `getBlocksByStep(nameOrId)` | Блоки одного шага |
| `getCurrentStepBlocks()` | Блоки шага, который сейчас на экране |

В списки попадают только блоки, которые хранят значение. Заголовки, абзацы, изображения и подобные блоки в списки не входят. `getBlock()` дополнительно находит кнопки (Continue, Previous, Submit, Button), чтобы вы могли менять их текст или отключать их.

<Warning>
  `getBlock()` никогда не возвращает `undefined`. Если ничего не найдено или блок не может хранить значение, вы получите блок-заглушку: каждый вызов на ней пишет предупреждение в консоль и ничего не делает, а `getValue()` возвращает `""`. Код не упадёт, но если что-то не срабатывает, проверьте консоль.
</Warning>

<Accordion title="Какие блоки хранят значение?">
  Поля ввода (текст, email, телефон, число, textarea, дата, дата рождения, почтовый индекс, адрес, OTP), блоки выбора (multiple choice, image choice, select), checkbox, range slider, upload, signature и скрытые поля.

  Всё остальное — блоки отображения или навигации: заголовок, абзац, изображение, видео, разделитель, список, loader, countdown, progress, accordion, ссылки, custom code, tracking и кнопки. Вызов `getValue()`, `setValue()`, `reset()` или `validate()` на таких блоках вызывает ошибку. Контейнеры прозрачны: блоки внутри них перечисляются так же, как любые другие.
</Accordion>

## Чтение и изменение блока

Каждый блок, который вы получаете, — объект одного и того же типа, поэтому примеры ниже работают с любым блоком, который поддерживает вызов.

### Значение

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

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

Установка значения через API вызывает событие `ll-quiz-value-change` с `source: 'api'`, поэтому ваши обработчики могут отличить его от ввода посетителя.

<AccordionGroup>
  <Accordion title="Форматы значений по блокам">
    * **Checkbox**: `'checked'` или `'unchecked'`
    * **Multiple choice, image choice, select**: значение варианта, например `'pro'`
    * **Multiple choice с несколькими вариантами**: значения, соединённые разделителем, заданным в блоке
    * **Все остальные**: текст, который ввёл посетитель
  </Accordion>
</AccordionGroup>

### Метка и плейсхолдер

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

Метки — это обычный текст, кроме checkbox, где разрешён HTML для ссылок на условия. `setLabel()` и `getLabel()` вызывают ошибку на блоках, у которых нет метки.

### Варианты ответов

Блоки multiple choice, image choice и select предоставляют свои варианты:

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

Вызов `getOptions()` на любом другом блоке вызывает ошибку.

### Ошибки и фокус

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

### Кнопки

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

`enable()` и `disable()` работают с блоками Continue, Submit и Button; на остальных вызывают ошибку.

### Видимость

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

Скрытый блок не валидируется, не отправляется вместе с лидом и не отображается. `undefined` означает, что вы ничего не меняли, поэтому блок следует собственным настройкам.

## Валидация

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

Валидация асинхронная, потому что поля email, телефона и OTP проверяются на сервере. Скрытые блоки всегда проходят проверку.

<Info>
  Если шаг не проходит проверку, квиз также вызывает `ll-quiz-validation-error` со всеми непрошедшими блоками и сообщениями об ошибках, помеченное `source: 'api'`. Поэтому один обработчик может обрабатывать и попытки посетителя, и ваши. Подробнее — на [странице событий](/ru/features/quizzes/api/events#ll-quiz-validation-error).
</Info>

## Навигация и отправка

```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()` и `submit()` сначала валидируют шаг на экране. Если он невалиден, они остаются на месте, пишут предупреждение и вызывают `ll-quiz-validation-error`. `goBack()` никогда не валидирует.

`submit()` делает ровно то же, что кнопка Submit у посетителя: лид сохраняется, срабатывает `ll-quiz-submit` с ответом сервера, действует защита от повторной отправки и выполняется действие кнопки Submit после отправки. На шаге без кнопки Submit квиз отправляется и остаётся на месте. Возвращаемый promise завершается, когда всё это выполнено.

## Примеры

<AccordionGroup>
  <Accordion title="Предзаполнение из 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="Свой текст прогресса">
    ```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="Переход к первому полю с ошибкой">
    ```javascript theme={null}
    window.addEventListener('ll-quiz-validation-error', (event) => {
      const { errors, llQuizApi } = event.detail;
      llQuizApi.getBlock(errors[0].blockId).focus();
    });
    ```
  </Accordion>

  <Accordion title="Блокировка кнопки Continue, пока не пройдёт ваша проверка">
    ```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="Показ блока только при определённом ответе">
    ```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="Отправка по своей кнопке">
    ```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="Отправка ответов на свой эндпоинт">
    ```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>

## Все функции кратко

| Функция | Что делает |
| :- | :- |
| `getAnswers()` / `getAnswersSimple()` | Ответы на текущий момент |
| `getCurrentStep()` / `getCurrentStepBlocks()` | Шаг на экране и его блоки |
| `getSteps()` / `getInfo()` | Все шаги; ID квиза и статус отправки |
| `getBlocks()` / `getBlock()` / `getBlocksByStep()` | Поиск блоков |
| `validateStep(nameOrId)` | Валидация шага |
| `navigation.goNext()` / `goBack()` / `goToStep()` / `submit()` / `goToUrl()` | Переходы и отправка |

| Метод блока | Что делает |
| :- | :- |
| `getValue()` / `setValue()` / `reset()` | Ответ |
| `getLabel()` / `setLabel()` / `getPlaceholder()` / `setPlaceholder()` | Тексты |
| `getOptions()` | Варианты блока выбора или select |
| `validate()` / `getErrors()` / `focus()` | Валидация |
| `enable()` / `disable()` | Кнопки |
| `visibility.show()` / `hide()` / `get()` / `clear()` | Показ и скрытие |
| `blockID` / `blockType` / `variableName` | Идентификация |

<Accordion title="Старые названия функций (по-прежнему поддерживаются)">
  В ранних версиях для каждого типа поиска была отдельная функция. Они продолжают работать как раньше, поэтому уже написанный код менять не нужно. В новом коде используйте унифицированные функции.

  | Старое название | Что использовать |
  | :- | :- |
  | `getBlockByID(id)` / `getBlockByName(name)` | `getBlock()` |
  | `getBlocksByStepID(id)` / `getBlocksByStepName(name)` | `getBlocksByStep()` |
  | `validateStepByID(id)` / `validateStepByName(name)` | `validateStep()` |
</Accordion>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.