Компоненты

FormBuilder

Основы

Поля и компоненты в FormBuilder используются внутри форм, которые обрабатываются FormBuilder. Благодаря FormBuilder поля отображаются и заполняются данными. FormBuilder используется на странице редактирования, а также для полей отношений, таких как HasOne. Вы также можете использовать FormBuilder на своих собственных страницах, в модальных окнах или даже за пределами MoonShine.

make(
string $action = '',
FormMethod $method = FormMethod::POST,
FieldsContract|iterable $fields = [],
mixed $values = [],
)
  • action - обработчик,
  • method - тип запроса,
  • fields - поля и компоненты,
  • values - значения полей.
FormBuilder::make(
action:'/crud/update',
method: FormMethod::POST,
fields: [
Hidden::make('_method')->setValue('put')
Text::make('Text')
],
values: ['text' => 'Value']
)
 
// or
 
FormBuilder::make()
->action('/crud/update')
->method(FormMethod::POST)
->fields([
Hidden::make('_method')->setValue('put')
Text::make('Text')
])
->fill(['text' => 'Value'])
<x-moonshine::form
name="crud-form"
:errors="$errors"
precognitive
>
<x-moonshine::form.input
name="title"
placeholder="Title"
value=""
/>
<x-slot:buttons>
<x-moonshine::form.button type="reset">Cancel</x-moonshine::form.button>
<x-moonshine::form.button class="btn-primary">Submit</x-moonshine::form.button>
</x-slot:buttons>
</x-moonshine::form>

Основные методы

Поля

Метод fields() для объявления полей формы и компонентов:

fields(FieldsContract|Closure|iterable $fields)
FormBuilder::make('/crud/update')
->fields([
Heading::make('Title'),
Text::make('Text'),
])

Имя формы

Метод name() позволяет установить уникальное имя для формы, через которое можно вызывать события.

FormBuilder::make('/crud/update')
->name('main-form')

Заполнение полей

Метод fill() для заполнения полей значениями:

fill(mixed $values = [])
FormBuilder::make('/crud/update')
->fields([
Heading::make('Title'),
Text::make('Text'),
])
->fill(['text' => 'value'])

Приведение типов

Метод cast() для приведения значений формы к определенному типу. Поскольку по умолчанию поля работают с примитивными типами.

cast(DataCasterContract $cast)
use MoonShine\Laravel\TypeCasts\ModelCaster;
 
FormBuilder::make('/crud/update')
->fields([
Heading::make('Title'),
Text::make('Text'),
])
->values(
['text' => 'value'],
)
->cast(new ModelCaster(User::class))

В этом примере мы приводим данные к формату модели User, используя ModelCaster.

Для более подробной информации обратитесь к разделу TypeCasts.

Заполнение и приведение к типу

Метод fillCast() позволяет привести данные к определенному типу и сразу заполнить их значениями.

fillCast(
mixed $values,
DataCasterContract $cast
)
use MoonShine\TypeCasts\ModelCaster;
 
FormBuilder::make('/crud/update')
->fields([
Heading::make('Title'),
Text::make('Text'),
])
->fillCast(
['text' => 'value'],
new ModelCaster(User::class)
)

или

use MoonShine\TypeCasts\ModelCaster;
 
FormBuilder::make('/crud/update')
->fields([
Heading::make('Title'),
Text::make('Text'),
])
->fillCast(
User::query()->first(),
new ModelCaster(User::class)
)

Кнопки

Кнопки формы можно модифицировать и добавлять.

Для настройки кнопки "submit" используйте метод submit().

submit(
string $label,
array $attributes = []
)
  • label - название кнопки,
  • attributes - дополнительные атрибуты.
FormBuilder::make('/crud/update')
->submit(
label: 'Click me',
attributes: ['class' => 'btn-primary']
)

Метод hideSubmit() позволяет скрыть кнопку "submit".

FormBuilder::make('/crud/update')
->hideSubmit()

Для добавления новых кнопок на основе ActionButton используйте метод buttons().

buttons(iterable $buttons = [])
FormBuilder::make('/crud/update')
->buttons([
ActionButton::make('Delete', route('name.delete'))
])

Настройка атрибутов

Вы можете установить любые html атрибуты для формы с помощью метода customAttributes().

FormBuilder::make()
->customAttributes(['class' => 'custom-form'])

Асинхронный режим

Если необходимо отправить форму асинхронно, используйте метод async().

async(
Closure|string|null $url = null,
string|array|null $events = null,
?AsyncCallback $callback = null,
)
  • url - url запроса (по умолчанию запрос отправляется по url action),
  • events - события, поднимаемые после успешного запроса,
  • callback - js callback функция после получения ответа.
FormBuilder::make('/crud/update')
->async()

После успешного запроса можно вызвать события, добавив параметр events.

FormBuilder::make('/crud/update')
->name('main-form')
->async(events: [
AlpineJs::event(JsEvent::TABLE_UPDATED, 'crud-table'),
AlpineJs::event(JsEvent::FORM_RESET, 'main-form'),
])

Список событий для FormBuilder:

  • JsEvent::FORM_SUBMIT - submit формы,
  • JsEvent::FORM_RESET - сброс значений формы по её имени,

Метод async() должен идти после метода name()!

Вызов методов

asyncMethod() позволяет указать имя метода в ресурсе и вызвать его асинхронно при отправке FormBuilder без необходимости создания дополнительных контроллеров.

FormBuilder::make()
->asyncMethod('updateSomething')
// С уведомлением
public function updateSomething(MoonShineRequest $request): MoonShineJsonResponse
{
// $request->getResource();
// $request->getResource()->getItem();
// $request->getPage();
 
return MoonShineJsonResponse::make()->toast('My message', ToastType::SUCCESS);
}
 
// Редирект
public function updateSomething(MoonShineRequest $request): MoonShineJsonResponse
{
return MoonShineJsonResponse::make()->redirect('/');
}
 
// Редирект
public function updateSomething(MoonShineRequest $request): RedirectResponse
{
return back();
}
 
// Исключение
public function updateSomething(MoonShineRequest $request): void
{
throw new \Exception('My message');
}

Реактивность

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

FormBuilder::make()
->reactiveUrl(
fn(FormBuilder $form) => $form->getCore()->getRouter()->getEndpoints()->reactive($page, $resource, $extra)
)

Значения полей

Если вы используете собственный controller обработчик, asyncMethod или обработчик ответа, то с помощью MoonShineJsonResponse у вас есть возможность заменить значения полей формы по селектору.

public function formAction(): MoonShineJsonResponse
{
return MoonShineJsonResponse::make()
->fieldsValues([
'.title' => 'Hello',
]);
}
 
protected function components(): iterable
{
return [
FormBuilder::make()
->asyncMethod('formAction')
->fields([
Text::make('Title')->class('title'),
]),
];
}

Селекторы

Также вы можете заменить HTML области по селекторам через метод asyncSelector.

public function formAction(): MoonShineJsonResponse
{
return MoonShineJsonResponse::make()->html([
'.some-class1' => time(),
'.some-class2' => time(),
]);
}
 
protected function components(): iterable
{
return [
FormBuilder::make()
->asyncMethod('formAction')
->asyncSelector(['.some-class1','.some-class2'])
->fields([
Div::make([])->class('some-class1'),
Div::make([])->class('some-class2'),
]),
];
}

Валидация

Отображение ошибок валидации

По умолчанию ошибки валидации отображаются в верхней части формы.

Метод errorsAbove(bool $enable = true) используется для управления отображением ошибок валидации в верхней части формы. Он позволяет включить или отключить эту функцию.

FormBuilder::make('/crud/update')
->errorsAbove(false)

Прекогнитивная валидация

Если необходимо сначала выполнить прекогнитивную валидацию, вам нужен метод precognitive().

FormBuilder::make('/crud/update')
->precognitive()

Несколько форм одновременно

Если у вас есть несколько форм на одной странице и они не в режиме "async", то вам также необходимо указать наименование для errorBag в FormRequest или в Controller. Наименование errorBag должно совпадать с наименованием соответствующей формы.

Подробнее о наименовании errorBag.

FormBuilder::make(route('multiple-forms.one'))
->name('formOne'),
 
FormBuilder::make(route('multiple-forms.two'))
->name('formTwo'),
 
FormBuilder::make(route('multiple-forms.three'))
->name('formThree')
 
class FormOneFormRequest extends FormRequest
{
protected $errorBag = 'formOne';
 
// ...
}
 
class FormTwoFormRequest extends FormRequest
{
protected $errorBag = 'formTwo';
 
// ...
}
 
class FormThreeFormRequest extends FormRequest
{
protected $errorBag = 'formThree';
 
// ...
}

Применение

Метод apply() в FormBuilder итерирует все поля формы и вызывает их методы apply().

apply(
Closure $apply,
?Closure $default = null,
?Closure $before = null,
?Closure $after = null,
bool $throw = false,
)
  • $apply - функция обратного вызова,
  • $default - применение для поля по умолчанию,
  • $before - функция обратного вызова перед применением,
  • $after - функция обратного вызова после применения,
  • $throw - выбрасывать исключения.

Примеры

Необходимо сохранить данные всех полей FormBuilder в контроллере:

$form->apply(fn(Model $item) => $item->save());

Более сложный вариант, с указанием событий до и после сохранения:

$form->apply(
static fn(Model $item) => $item->save(),
before: function (Model $item) {
if (! $item->exists) {
$item = $this->beforeCreating($item);
}
 
if ($item->exists) {
$item = $this->beforeUpdating($item);
}
 
return $item;
},
after: function (Model $item) {
$wasRecentlyCreated = $item->wasRecentlyCreated;
 
$item->save();
 
if ($wasRecentlyCreated) {
$item = $this->afterCreated($item);
}
 
if (! $wasRecentlyCreated) {
$item = $this->afterUpdated($item);
}
 
return $item;
},
throw: true
);

Отправка событий

Для отправки javascript событий можно использовать метод dispatchEvent().

dispatchEvent(array|string $events)
FormBuilder::make()
->dispatchEvent(
AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default')
)

По умолчанию при вызове события с запросом будут отправлены все данные формы. Если форма большая, то может потребоваться исключить набор полей. Исключить можно через параметр exclude.

->dispatchEvent(
AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default'),
exclude: ['text', 'description']
)

Также можно полностью исключить отправку данных через параметр withoutPayload.

->dispatchEvent(
AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default'),
withoutPayload: true
)

Событие "Submit"

Для отправки формы можно вызвать событие Submit.

AlpineJs::event(
JsEvent::FORM_SUBMIT,
'componentName'
)

Пример вызова события на странице формы

protected function formButtons(): ListOf
{
return parent::formButtons()
->add(
ActionButton::make('Save')
->dispatchEvent(AlpineJs::event(JsEvent::FORM_SUBMIT, $this->uriKey()))
);
}

Для получения дополнительной информации о js событиях обратитесь к разделу Events.