Skip to content

Интеграция с сервером и персистентность

Ошибки валидации с сервера

Отобразите ответ backend'а с ошибками валидации на form.errors — без ручного разворачивания в каждом проекте.

ts
import { applyServerErrors } from '@macrulez/vue-form-schema'

const res = await fetch('/api/users', { method: 'POST', body: JSON.stringify(form.values.value) })
if (!res.ok) {
  const { formErrors } = applyServerErrors(form, await res.json(), { format: 'laravel' })
  if (formErrors.length) toast.error(formErrors[0]) // ошибки, не привязанные к конкретному полю
}

Встроенные format:

ФорматФорма
'laravel'{ message, errors: { field: ["msg", ...], "nested.field": [...] } }
'drf'{ field: ["msg"], nested: { field: ["msg"] } } (сплющивается в dot-paths); non_field_errors / detail становятся formErrors
'flat'{ field: "msg" | ["msg", ...] } — значение по умолчанию; подходит для большинства самописных API

Либо передайте собственный маппер для чего угодно ещё: (raw) => ({ fieldErrors: {...}, formErrors: [...] }).

Ошибки полей, установленные так, ведут себя как любая другая запись в errors — при следующей клиентской валидации этого поля (по умолчанию по blur, либо на каждое нажатие клавиши при validateOn: 'input'), она пересчитывается из собственных валидаторов схемы, и серверная ошибка естественным образом заменяется. submit() тоже полностью пересчитывает errors, так что устаревшая серверная ошибка никогда не переживает до следующей попытки отправки.

applyServerErrors(form, raw, options?):

ОпцияТипПо умолчаниюОписание
format'laravel' | 'drf' | 'flat' | ((raw) => ...)'flat'Имя встроенного формата или кастомный маппер
touchbooleantrueПометить затронутые поля как touched, чтобы ошибки показались сразу
mergebooleantrueОбъединять с существующими errors, а не заменять их

normalizeServerErrors(raw, format?) выполняет тот же маппинг, не трогая форму, если вам нужны просто { fieldErrors, formErrors }.

Персистентные формы

ts
useForm({
  schema,
  persist: 'local', // или 'session'
  persistKey: 'checkout', // опционально — по умолчанию хэш от имён полей
})

Значения восстанавливаются из хранилища в onMounted. reset() очищает сохранённое значение. SSR-безопасно: чтение из хранилища защищено проверкой typeof window !== 'undefined'.

Режим отладки

ts
// Логировать каждое изменение values в console.group
useForm({ schema, debug: true })
ts
// Реактивный снапшот всего состояния формы
import { useFormDebug } from '@macrulez/vue-form-schema'

const { snapshot } = useFormDebug(form)
// snapshot.value = { values, errors, touched, isDirty, isValid, isSubmitting }

Vue DevTools

vue-form-schema/devtools добавляет кастомный инспектор Forms (каждый активный экземпляр useForm() — values/errors/touched/isValid/isDirty, вживую) и слой таймлайна Forms (события setField/touch/submit/submitSuccess/submitError/reset/asyncValidate) в браузерное расширение Vue DevTools / отдельное приложение.

ts
// main.ts — только для dev, импортируется динамически, чтобы @vue/devtools-api
// никогда не попал в продакшен-бандл
const app = createApp(App)
if (import.meta.env.DEV) {
  const { installFormDevtools } = await import('@macrulez/vue-form-schema/devtools')
  installFormDevtools(app)
}
app.mount('#app')

Это отдельная точка входа намеренно — сам useForm() всегда лишь пишет в небольшой независимый от зависимостей внутренний реестр (почти нулевая цена, без импорта @vue/devtools-api), независимо от того, был ли вызван installFormDevtools, так что поддержка devtools ничего не стоит в базовом бандле, если вы не включите её сами. Требует @vue/devtools-api (peer-зависимость, ^6 || ^7 || ^8 — установите её рядом).