Основы
Поля и компоненты в FormBuilder используются внутри форм, которые обрабатываются FormBuilder.
Благодаря FormBuilder поля отображаются и заполняются данными.
FormBuilder используется на странице редактирования, а также для полей отношений, таких как HasOne.
Вы также можете использовать FormBuilder на своих собственных страницах, в модальных окнах или даже за пределами MoonShine.
make(string $action = '',FormMethod $method = FormMethod::POST,FieldsContract|iterable $fields = [],mixed $values = [],)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'])// orFormBuilder::make()->action('/crud/update')->method(FormMethod::POST)->fields([Hidden::make('_method')->setValue('put'),Text::make('Text')])->fill(['text' => 'Value'])FormBuilder::make(action:'/crud/update',method: FormMethod::POST,fields: [Hidden::make('_method')->setValue('put'),Text::make('Text')],values: ['text' => 'Value'])// orFormBuilder::make()->action('/crud/update')->method(FormMethod::POST)->fields([Hidden::make('_method')->setValue('put'),Text::make('Text')])->fill(['text' => 'Value'])
<x-moonshine::formname="crud-form":errors="$errors"precognitive><x-moonshine::form.inputname="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><x-moonshine::formname="crud-form":errors="$errors"precognitive><x-moonshine::form.inputname="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)fields(FieldsContract|Closure|iterable $fields)
FormBuilder::make('/crud/update')->fields([Heading::make('Title'),Text::make('Text'),])FormBuilder::make('/crud/update')->fields([Heading::make('Title'),Text::make('Text'),])
Имя формы
Метод name() позволяет установить уникальное имя для формы, через которое можно вызывать события.
FormBuilder::make('/crud/update')->name('main-form')FormBuilder::make('/crud/update')->name('main-form')
Заполнение полей
Метод fill() для заполнения полей значениями:
fill(mixed $values = [])fill(mixed $values = [])
FormBuilder::make('/crud/update')->fields([Heading::make('Title'),Text::make('Text'),])->fill(['text' => 'value'])FormBuilder::make('/crud/update')->fields([Heading::make('Title'),Text::make('Text'),])->fill(['text' => 'value'])
Приведение типов
Метод cast() для приведения значений формы к определенному типу.
Поскольку по умолчанию поля работают с примитивными типами.
cast(DataCasterContract $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))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)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(['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))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 = [])submit(string $label,array $attributes = [])
label- название кнопки,attributes- дополнительные атрибуты.
FormBuilder::make('/crud/update')->submit(label: 'Click me',attributes: ['class' => 'btn-primary'])FormBuilder::make('/crud/update')->submit(label: 'Click me',attributes: ['class' => 'btn-primary'])
Метод hideSubmit() позволяет скрыть кнопку "submit".
FormBuilder::make('/crud/update')->hideSubmit()FormBuilder::make('/crud/update')->hideSubmit()
Для добавления новых кнопок на основе ActionButton используйте метод buttons().
buttons(iterable $buttons = [])buttons(iterable $buttons = [])
FormBuilder::make('/crud/update')->buttons([ActionButton::make('Delete', route('name.delete'))])FormBuilder::make('/crud/update')->buttons([ActionButton::make('Delete', route('name.delete'))])
Настройка атрибутов
Вы можете установить любые html атрибуты для формы с помощью метода customAttributes().
FormBuilder::make()->customAttributes(['class' => 'custom-form'])FormBuilder::make()->customAttributes(['class' => 'custom-form'])
Асинхронный режим
Если необходимо отправить форму асинхронно, используйте метод async().
async(Closure|string|null $url = null,string|array|null $events = null,?AsyncCallback $callback = null,)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()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::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')FormBuilder::make()->asyncMethod('updateSomething')
Если метод возвращает файл для скачивания, вам необходимо добавить метод download().
FormBuilder::make()->asyncMethod('zip')->download()FormBuilder::make()->asyncMethod('zip')->download()
Примеры методов:
// С уведомлением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');}// С уведомлением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))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'),]),];}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'),]),];}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)FormBuilder::make('/crud/update')->errorsAbove(false)
Прекогнитивная валидация
Если необходимо сначала выполнить прекогнитивную валидацию, вам нужен метод precognitive().
FormBuilder::make('/crud/update')->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';// ...}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(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(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);$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)dispatchEvent(array|string $events)
FormBuilder::make()->dispatchEvent(AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default'))FormBuilder::make()->dispatchEvent(AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default'))
По умолчанию при вызове события с запросом будут отправлены все данные формы.
Если форма большая, то может потребоваться исключить набор полей.
Исключить можно через параметр exclude.
->dispatchEvent(AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default'),exclude: ['text', 'description'])->dispatchEvent(AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default'),exclude: ['text', 'description'])
Также можно полностью исключить отправку данных через параметр withoutPayload.
->dispatchEvent(AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default'),withoutPayload: true)->dispatchEvent(AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default'),withoutPayload: true)
Событие "Submit"
Для отправки формы можно вызвать событие Submit.
AlpineJs::event(JsEvent::FORM_SUBMIT,'componentName')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())));}protected function formButtons(): ListOf{return parent::formButtons()->add(ActionButton::make('Save')->dispatchEvent(AlpineJs::event(JsEvent::FORM_SUBMIT, $this->uriKey())));}
Для получения дополнительной информации о js событиях обратитесь к разделу Events.