Разработка взаимозависимых полей с Admiral
Время прочтения — 10 минут


Содержание
При разработке админ-панелей часто возникает необходимость динамически изменять значения одного поля в зависимости от выбранного значения другого. Такие элементы интерфейса называются взаимозависимыми полями, которые позволяют упростить работу с формами и делают управление данными более удобным.
Применение взаимозависимых полей
Взаимозависимые поля широко используют в различных продуктах и сервисах, где данные структурированы и зависят друг от друга:
- Платформы бронирования – выбор специалиста определяет доступные услуги и свободное время для записи;
- Системы управления контентом – выбор категории отображает соответствующие подкатегории и поля для заполнения;
- E-commerce платформы – выбор бренда фильтрует доступные модели и их характеристики.
Упрощение разработки с помощью Admiral
Чтобы быстро и эффективно настраивать взаимозависимые поля, мы используем Admiral – нашу фронтенд админ-панель для создания CRUD-интерфейсов. Admiral позволяет быстро и легко создавать зависимости между полями без лишних запросов к серверу.
Главные преимущества Admiral:
- Готовые компоненты – экономия времени на разработке базовых элементов интерфейса;
- Гибкая кастомизация – настройка под специфические потребности вашего продукта;
- Совместимость с Laravel – простая интеграция с популярным PHP-фреймворком.
Установить Admiral можно по ссылке.
Как настроить взаимозависимые поля в Admiral
Рассмотрим практический пример настройки взаимозависимых полей с помощью Admiral.
Шаг 1: Настройка контроллера
В бэкенде каждому полю соответствует метод ajaxSelect, который принимает параметры зависимых полей и возвращает соответствующие данные.
Пример кода:
public function ajaxSelect(Request $request, $field, RecordValues $values)
{
return match ($field) {
'client_id' => $values->clients($request->input('query'), $request->input('location_id')),
'location_id' => $values->locations($request->input('query')),
'services' => $values->services($request->input('query'), $request->input('location_id'), $request->input('master_id')),
'master_id' => $values->masters($request->input('query'), $request->input('location_id')),
default => collect(),
};
}
Шаг 2: Создание методов выборки данных
Для каждого зависимого поля создаются методы, которые формируют выборку на основе переданных параметров.
Пример для клиентов:
public function clients(string $query, int $locationId)
{
return Client::query()
->when($query, fn ($q) => $q->where('name', 'ilike', "%{$query}%"))
->where('location_id', $locationId)
->limit(20)
->get(['id', 'first_name', 'last_name'])
->map(fn (Client $client) => [
'value' => $client->id,
'label' => $client->full_name,
]);
}
В этом примере список клиентов фильтруется по местоположению, заданному в поле location_id.
Шаг 3: Настройка зависимостей для других полей
Аналогичным образом настраиваются и другие поля, от которых зависят элементы формы. Достаточно передать значения зависимых полей в методы выборки данных.
Шаг 4: Создание взаимозависимых полей в клиентской части Admiral
Теперь, когда на стороне бэкенда написана соответствующая логика, добавим необходимые компоненты и логику внутри конфигурации функции создания круда (createCrud). А именно – в index.form.create.fields и index.form.edit.fields.
Как правило, мы создаем отдельный компонент, внутри которого рендерятся нужные нам поля. Это позволяет изолировать логику и не превратить функцию createCrud во что-то нечитаемое.
export const CRUD = createCRUD({
path: '/records',
resource: 'records',
form: {
create: {
fields: <RecordsFields />,
},
edit: {
fields: <RecordsFields />,
},
},
})
Для реализации компонента понадобится отрендерить поля и заблокировать зависимые от других значений поля, если необходимое в форме значение отсутствует, с помощью пропса disabled.
Также понадобится хук useUpdateEffect, который будет выполнять выборку данных при появлении в форме связанного значения. useUpdateEffect отличается от обычного useEffect тем, что будет срабатывать только при обновлении компонента, а не при первом рендере.
Ниже добавили простейшую реализацию компонента с зависимыми полями. В компоненте есть комментарии, которые более детально описывают логику.
import React from 'react'
import { AjaxSelectInput, FieldValues, useForm, useUpdateEffect } from '@devfamily/admiral'
import api from '@/src/config/api'
const resource = 'records'
const RecordsFields = () => {
const { values, setValues, setOptions } = useForm()
useUpdateEffect(() => {
setValues((prevValues: FieldValues) => ({
...prevValues,
// При изменении локации, сбрасываем выбранного мастера.
client_id: null,
}))
const fetchOptions = async () => {
if (!values.location_id) return
try {
const clientOptions = await api.getAjaxSelectOptions(resource, 'client_id', {
location_id: values.location_id,
})
setOptions((prevOptions: FieldValues) => ({
...prevOptions,
client_id: clientOptions,
}))
} catch (error) {
console.error('Failed to fetch options:', error)
}
}
fetchOptions()
// При появлении в форме айди локации, происходит срабатывание данного хука с последующей выборкой данных для получения списка клиентов.
}, [values.location_id])
return (
<>
<AjaxSelectInput
label="Место обслуживания"
name="location_id"
placeholder="Место обслуживания"
required
allowClear
fetchOptions={(field, query) =>
api.getAjaxSelectOptions(resource, field, {
query,
})
}
/>
<AjaxSelectInput
label="Клиент"
name="client_id"
placeholder="Клиент"
required
allowClear
fetchOptions={(field, query) => {
return api.getAjaxSelectOptions(resource, field, {
query,
location_id: values.location_id,
})
}}
// Поле будет заблокировано, пока не выберем локации в верхнем поле.
disabled={!values.location_id}
/>
</>
)
}
// Обёртка необходима, чтобы useUpdateEffect не срабатывал после инициализации формы.
const RecordsFieldsWrapper = () => {
const { options } = useForm()
return !!Object.keys(options).length ? <RecordsFields /> : <></>
}
export default RecordsFieldsWrapper
Ниже добавили простейшую реализацию компонента с зависимыми полями. В компоненте есть комментарии, которые более детально описывают логику.
Заключение
Использование Admiral для создания взаимозависимых полей делает разработку админ-панелей более удобной и эффективной. Наша админка предоставляет готовые инструменты для быстрой настройки интерфейса и упрощения управления данными. Попробуйте Admiral в своем проекте и оцените преимущества гибкого и функционального решения.
Остались вопросы по разработке взаимозависимых полей в Admiral? Мы здесь, чтобы помочь!