При разработке админ-панелей часто возникает необходимость динамически изменять значения одного поля в зависимости от выбранного значения другого. Такие элементы интерфейса называются взаимозависимыми полями, которые позволяют упростить работу с формами и делают управление данными более удобным.
Применение взаимозависимых полей
Взаимозависимые поля широко используют в различных продуктах и сервисах, где данные структурированы и зависят друг от друга:
Платформы бронирования – выбор специалиста определяет доступные услуги и свободное время для записи;
Системы управления контентом – выбор категории отображает соответствующие подкатегории и поля для заполнения;
E-commerce платформы – выбор бренда фильтрует доступные модели и их характеристики.
Упрощение разработки с помощью Admiral
Чтобы быстро и эффективно настраивать взаимозависимые поля, мы используемAdmiral– нашу фронтенд админ-панель для создания CRUD-интерфейсов. Admiral позволяет быстро и легко создавать зависимости между полями без лишних запросов к серверу.Главные преимущества Admiral:
Готовые компоненты – экономия времени на разработке базовых элементов интерфейса;
Гибкая кастомизация – настройка под специфические потребности вашего продукта;
Совместимость с Laravel – простая интеграция с популярным PHP-фреймворком.
В этом примере список клиентов фильтруется по местоположению, заданному в поле location_id.
Шаг 3: Настройка зависимостей для других полей
Аналогичным образом настраиваются и другие поля, от которых зависят элементы формы. Достаточно передать значения зависимых полей в методы выборки данных.
Шаг 4: Создание взаимозависимых полей в клиентской части Admiral
Теперь, когда на стороне бэкенда написана соответствующая логика, добавим необходимые компоненты и логику внутри конфигурации функции создания круда (createCrud). А именно – в index.form.create.fields и index.form.edit.fields.
Как правило, мы создаем отдельный компонент, внутри которого рендерятся нужные нам поля. Это позволяет изолировать логику и не превратить функцию createCrud во что-то нечитаемое.
Для реализации компонента понадобится отрендерить поля и заблокировать зависимые от других значений поля, если необходимое в форме значение отсутствует, с помощью пропса 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? Мы здесь, чтобы помочь!