- Basics
- Basic Usage
- Basic Methods
- Attribute Configuration
- Asynchronous Mode
- Validation
- Apply
- Dispatch Events
- Using in Blade
Basics
Fields and components in FormBuilder
are used within forms that are processed by FormBuilder
. Thanks to FormBuilder
, fields are displayed and filled with data. FormBuilder
is used on the edit page, as well as for relationship fields such as HasOne
. You can also use FormBuilder
on your own pages, in modal windows, or even outside of MoonShine
.
use MoonShine\UI\Components\FormBuilder; TableBuilder::make( string $action = '', FormMethod $method = FormMethod::POST, FieldsContract|iterable $fields = [], mixed $values = [])
<x-moonshine::form name="crud-edit"> <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>
Basic Usage
Example usage of FormBuilder
:
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'])
-
action
- handler -
method
- request type, -
fields
- fields and components. -
values
- field values.
Basic Methods
Fields
The method fields()
is used to declare form fields and components:
fields(FieldsContract|Closure|iterable $fields)
FormBuilder::make('/crud/update') ->fields([ Heading::make('Title'), Text::make('Text'), ])
Form Name
The method name()
allows you to set a unique name for the form, through which events can be triggered.
FormBuilder::make('/crud/update') ->name('main-form')
Fill Fields
The method fill()
is used to fill fields with values:
fill(mixed $values = [])
FormBuilder::make('/crud/update') ->fields([ Heading::make('Title'), Text::make('Text'), ]) ->fill(['text' => 'value'])
Type Cast
The method cast()
is used to cast form values to a specific type. Since fields work with primitive types by default:
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))
In this example, we cast the data to the User
model format using ModelCaster
.
For more detailed information, refer to the TypeCasts section.
Fill and Type Cast
The method fillCast()
allows you to cast data to a specific type and fill them with values at the same time:
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) )
or
use MoonShine\TypeCasts\ModelCaster; FormBuilder::make('/crud/update') ->fields([ Heading::make('Title'), Text::make('Text'), ]) ->fillCast( User::query()->first(), new ModelCaster(User::class) )
Buttons
Form buttons can be modified and added.
To configure the "submit" button, use the method submit()
.
submit(string $label, array $attributes = [])
-
label
- button name, -
attributes
- additional attributes
FormBuilder::make('/crud/update') ->submit(label: 'Click me', attributes: ['class' => 'btn-primary'])
The method hideSubmit()
allows you to hide the submit
button.
FormBuilder::make('/crud/update') ->hideSubmit()
To add new buttons based on ActionButton
, use the method buttons()
buttons(iterable $buttons = [])
FormBuilder::make('/crud/update') ->buttons([ ActionButton::make('Delete', route('name.delete')) ])
Attribute Configuration
You can set any HTML attributes for the form using the method customAttributes()
.
FormBuilder::make() ->customAttributes(['class' => 'custom-form'])
Asynchronous Mode
If you need to submit the form asynchronously, use the method async()
.
async( Closure|string|null $url = null, string|array|null $events = null, ?AsyncCallback $callback = null,)
-
url
- request URL (by default, the request is sent to the action URL), -
events
- events triggered after a successful request, -
callback
- JS callback function after receiving a response.
FormBuilder::make('/crud/update') ->async()
After a successful request, you can trigger events by adding the events
parameter.
FormBuilder::make('/crud/update') ->name('main-form') ->async(events: [ AlpineJs::event(JsEvent::TABLE_UPDATED, 'crud-table'), AlpineJs::event(JsEvent::FORM_RESET, 'main-form'), ])
Event list for FormBuilder
:
-
JsEvent::FORM_SUBMIT
- submit the form, -
JsEvent::FORM_RESET
- reset the form values by its name,
The async()
method must come after the name()
method!
Calling Methods
asyncMethod()
allows you to specify the method name in the resource and call it asynchronously when submitting the FormBuilder
without the need to create additional controllers.
FormBuilder::make()->asyncMethod('updateSomething'),
// With notificationpublic function updateSomething(MoonShineRequest $request): MoonShineJsonResponse{ // $request->getResource(); // $request->getResource()->getItem(); // $request->getPage(); return MoonShineJsonResponse::make()->toast('My message', ToastType::SUCCESS);} // Redirectpublic function updateSomething(MoonShineRequest $request): MoonShineJsonResponse{ return MoonShineJsonResponse::make()->redirect('/');} // Redirectpublic function updateSomething(MoonShineRequest $request): RedirectResponse{ return back();} // Exceptionpublic function updateSomething(MoonShineRequest $request): void{ throw new \Exception('My message');}
Reactivity
By default, fields inside the form are reactive, but if the form is outside the resource, then reactivity will not be available, as the form does not know where to send requests. In the case of using the form outside of resources, you can specify the reactive URL yourself:
FormBuilder::make()->reactiveUrl(fn(FormBuilder $form) => $form->getCore()->getRouter()->getEndpoints()->reactive($page, $resource, $extra))
Validation
Displaying Validation Errors
By default, validation errors are displayed at the top of the form.
The method errorsAbove(bool $enable = true)
is used to control the display of validation errors at the top of the form. It allows you to enable or disable this feature.
FormBuilder::make('/crud/update') ->errorsAbove(false)
Pre-Cognitive Validation
If you need to perform pre-cognitive validation first, you need the method precognitive()
.
FormBuilder::make('/crud/update') ->precognitive()
Multiple Forms Simultaneously
If you have multiple forms on one page and they are not in async
mode, you also need to specify a name for the errorBag
in FormRequest
or in Controller
:
Learn more about errorBag naming
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
The method apply()
in FormBuilder
iterates over all form fields and calls their apply
methods.
apply( Closure $apply, ?Closure $default = null, ?Closure $before = null, ?Closure $after = null, bool $throw = false,)
-
$apply
- callback function; -
$default
- apply for the default field; -
$before
- callback function before applying; -
$after
- callback function after applying; -
$throw
- throw exceptions.
Examples
You need to save data from all fields of the FormBuilder in the controller:
$form->apply(fn(Model $item) => $item->save());
A more complex option, specifying events before and after saving:
$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);
Dispatch Events
To dispatch JavaScript events, you can use the method dispatchEvent()
.
dispatchEvent(array|string $events)
FormBuilder::make() ->dispatchEvent(AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default')),
By default, when calling an event with a request, all form data will be sent. If the form is large, you may need to exclude a set of fields. Exclude can be done through the exclude
parameter:
->dispatchEvent( AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default'), exclude: ['text', 'description'])
You can also completely exclude data from being sent through the withoutPayload
parameter:
->dispatchEvent( AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'default'), withoutPayload: true)
Submit Event
To submit the form, you can call the Submit event.
AlpineJs::event(JsEvent::FORM_SUBMIT, 'componentName')
Example of calling the event on the form page
protected function formButtons(): ListOf{ return parent::formButtons()->add(ActionButton::make('Save')->dispatchEvent(AlpineJs::event(JsEvent::FORM_SUBMIT, $this->uriKey())));}
For additional information on JS events, refer to the Events section.
Using in Blade
Basics
Forms can be created using the moonshine::form
component.
<x-moonshine::formname="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>