Skip to content

SForm > SFormRow

SForm и SFormRow позволяют быстро собирать функциональные формы.

В чем отличие от аналогов?

В отличие от популярных библиотек компонентов для Vue3:

  1. Унифицирует и упрощает вспомогательные элементы (напр. подсказки под полями) и часто используемые состояния (напр. заголовки слева) до простых атрибутов. Это обеспечивает одинаковую реализацию разными программистами, избавляет от визуальных отличий, упрощает дальнейшую поддержку и сохраняет взаимозаменяемость между проектами.
  2. Сразу из коробки связывает форму с InertiaJS-формами и/или Laravel FormRequest-ами, одинаково и аккуратно выводя ошибки валидации
  3. Минимизируют синтаксис и связанность до одной модели на уровне SForm, что делает код чище, упрощает его написание, чтение и поддержку.
Что будет ценно улучшить
  1. Сразу привязывать лейблы правильным образом к соответствующим input-полям, что обеспечит поддержку ARIA — это будет ценно для проектов на европейский рынок, т.к. там это требование законодательства.

С формой InertiaJS

InertiaJS предлагает useForm-компонент, который мы используем по дефолту для всех форм.

Логин
Пароль
vue
<template>
    <SForm v-model="form" method="post" action="/users/login">
        <SFormRow title="Логин" name="login">
            <SInput />
        </SFormRow>
        <SFormRow title="Пароль" name="password">
            <SInput type="password" />
        </SFormRow>
        <SButton>Войти</SButton>
    </SForm>
</template>
vue
<template>
    <SForm v-model="form" method="post" action="/users/login">
        <SFormRow title="Логин" name="login">
            <SInput />
        </SFormRow>
        <SFormRow title="Пароль" name="password">
            <SInput type="password" />
        </SFormRow>
        <SButton>Войти</SButton>
    </SForm>
</template>

<script setup>
import { useForm } from '@inertiajs/vue3';
import { SForm, SFormRow, SInput, SButton } from 'startup-ui';

const form = useForm({
    login: '',
    password: '',
});
</script>

Для компонентов внутри <SFormRow /> не нужно отдельно прописывать модель — она автоматически берется из модели <SForm /> по имени.

Аналогично не нужно как-то обрабатывать loading-состояние и отдельно выводить ошибки валидации — при необходимости этот функционал уже реализован в форме.

С собственным submit-методом

Если по какой-то причине нам нужно вместо атрибутов method/action задать собственный submit-метод, сделать это можно следующим образом:

Логин
Пароль
vue
<template>
    <SForm @submit="submit" :errors="errors" :loading="isLoading">
        ...
    </SForm>
</template>
vue
<template>
    <SForm v-model="form" @submit="submit" :errors="errors" :loading="isLoading">
        <SFormRow title="Логин" name="login">
            <SInput />
        </SFormRow>
        <SFormRow title="Пароль" name="password">
            <SInput type="password" />
        </SFormRow>
        <SButton>Войти</SButton>
    </SForm>
</template>

<script setup>
import { ref } from 'vue';
import { SForm, SFormRow, SInput, SButton } from 'startup-ui';

const isLoading = ref(false);
const errors = ref({});
const form = ref({ login: '', password: '' });

function submit() {
    isLoading.value = true;
    // Ваша логика запроса
}
</script>

Так как мы используем собственный метод, то для показа состояния загрузки формы может понадобиться задавать свой набор ошибок (errors), а также loading-состояние, которое показывает, находится ли сейчас форма в процессе отправки (чтобы избежать повторной отправки по ошибке)

Подсказки под полями

Если под полем нужно выводить подсказку, это делается в <SFormRow>:

Логин
Имя пользователя или email
Пароль
vue
<template>
    <SFormRow title="Логин" name="login" hint="Имя пользователя или email">
        <SInput />
    </SFormRow>
</template>
vue
<template>
    <SForm v-model="form" method="post" action="/users/login">
        <SFormRow title="Логин" name="login" hint="Имя пользователя или email">
            <SInput />
        </SFormRow>
        <SFormRow title="Пароль" name="password">
            <SInput type="password" />
        </SFormRow>
        <SButton>Войти</SButton>
    </SForm>
</template>

<script setup>
import { useForm } from '@inertiajs/vue3';
import { SForm, SFormRow, SInput, SButton } from 'startup-ui';

const form = useForm({
    login: '',
    password: '',
});
</script>

Заголовки слева

По умолчанию заголовки выводятся над полями формы, но иногда бывает нужно показать их слева от полей. Сделать это можно следующим образом:

Логин
Имя пользователя или email
Пароль
vue
<template>
    <SForm titles-at-left titles-width="170">
        ...
    </SForm>
</template>
vue
<template>
    <SForm v-model="form" titles-at-left titles-width="170" method="post" action="/users/login">
        <SFormRow title="Логин" name="login">
            <SInput />
        </SFormRow>
        <SFormRow title="Пароль" name="password">
            <SInput type="password" />
        </SFormRow>
        <SButton>Войти</SButton>
    </SForm>
</template>

<script setup>
import { useForm } from '@inertiajs/vue3';
import { SForm, SFormRow, SInput, SButton } from 'startup-ui';

const form = useForm({
    login: '',
    password: '',
});
</script>

Дополнительный параметр titles-width позволяет задать ширину заголовков.

Установка моделей инпутов напрямую

По дефолту <SFormRow /> привязывает модели вложенных компонентов к соответствующему полю из модели <SForm />. Но это делается исключительно для удобства и не является обязательным. Иногда, когда нужно задать модели вручную это возможно сделать напрямую:

vue
<template>
    <SForm v-model="form">
        <SFormRow>
            <SSwitch v-model="form.hasAgreement">Согласен с правилами</SSwitch>
            <SSwitch v-model="form.hasNotifications">Согласен получать оповещения</SSwitch>
        </SFormRow>
    </SForm>
</template>
vue
<template>
    <SForm v-model="form">
        <SFormRow>
            <SSwitch v-model="form.hasAgreement">Согласен с правилами</SSwitch>
            <SSwitch v-model="form.hasNotifications">Согласен получать оповещения</SSwitch>
        </SFormRow>
    </SForm>
</template>

<script setup>
import { useForm } from '@inertiajs/vue3';
import { SForm, SFormRow, SSwitch } from 'startup-ui';

const form = useForm({
    hasAgreement: false,
    hasNotifications: false,
});
</script>

Вывод ошибок из кастомных ключей

Иногда бывает нужно выводить ошибки из кастомных ключей errors-массива (или вложенных путей). Сделать это можно с помощью атрибута error-key:

Кол-во заказов
vue
<template>
    <SFormRow title="Кол-во заказов" :error-key="['orders.minCount', 'orders.maxCount']">
        <div class="order-formrow">
            <label class="order-formrow-item">
                <span>Минимум</span>
                <SInput v-model="form.minCount" type="number" min="0" style="max-width: 80px;"/>
            </label>
            <label class="order-formrow-item">
                <span>Максимум</span>
                <SInput v-model="form.maxCount" type="number" min="0" style="max-width: 80px;"/>
            </label>
        </div>
    </SFormRow>
</template>
vue
<template>
    <SForm v-model="form" :errors="errors" @submit.prevent="submit">
        <SFormRow title="Кол-во заказов" :error-key="['orders.minCount', 'orders.maxCount']">
            <div class="order-formrow">
                <label class="order-formrow-item">
                    <span>Минимум</span>
                    <SInput v-model="form.minCount" type="number" min="0" style="max-width: 80px;"/>
                </label>
                <label class="order-formrow-item">
                    <span>Максимум</span>
                    <SInput v-model="form.maxCount" type="number" min="0" style="max-width: 80px;"/>
                </label>
            </div>
        </SFormRow>
        <SButton>Отправить</SButton>
    </SForm>
</template>

<script setup>
import { ref } from 'vue';
import { SForm, SFormRow, SInput, SButton } from 'startup-ui';

const errors = ref({});
const form = ref({ minCount: '', maxCount: '' });

function submit() {
    if (!form.value.minCount) {
        errors.value['orders.minCount'] = 'Минимальное количество не может быть меньше 1';
    }
    if (!form.value.maxCount) {
        errors.value['orders.maxCount'] = 'Максимальное количество не может быть меньше 1';
    }
}
</script>

Поддерживаются:

  • Пути через точку: orders.0
  • Звездочка для всех вложенных ключей: orders.*
  • Массивы: ['orders.0', 'orders.1']

Интерфейс компонента SForm

Свойства (Props)

НазваниеТипПо умолчаниюОписание
formobject-Объект формы InertiaJS (рекомендуется).
methodstring'post'HTTP-метод: post, put, patch, delete, get.
actionstring-URL для отправки формы.
preserveScrollbooleantrueСохранять ли позицию скролла после отправки.
isDirtybooleanfalseСостояние «изменено» (предупреждение при уходе со страницы).
loadingbooleanundefinedСостояние загрузки (переопределяет внутреннее состояние формы).
summaryErrorsbooleanfalseПоказывать ли список всех ошибок вверху формы.

Слоты (Slots)

НазваниеОписание
defaultСодержимое формы (инпуты, кнопки и т.д.).

Интерфейс компонента SFormRow

Свойства (Props)

НазваниеТипПо умолчаниюОписание
titlestring-Заголовок (лейбл) поля.
hintstring-Текст-подсказка под заголовоком.
errorstring | string[]-Текст ошибки или массив ошибок.
errorKeystring-Ключ ошибки в объекте form.errors (если используется пропс errorKey).
requiredbooleanfalseПомечает поле как обязательное (добавляет красную звездочку).
sidebooleanfalseРасполагает заголовок слева от поля (горизонтальный лейаут).

Слоты (Slots)

НазваниеОписание
defaultСодержимое строки (обычно компонент ввода — инпут, селект и т.д.).
titleКастомный заголовок (вместо пропса title).
hintКастомная подсказка (вместо пропса hint).