Advanced

FormBuilder

Basics

Fields and decorations in FormBuilder are used inside forms, which are handled by FormBuilder.Thanks to FormBuilder, fields are displayed and filled with data.You can also use FormBuilder on your own pages or even outside of MoonShine.

make(
string $action = '',
string $method = 'POST',
Fields|array $fields = [],
array $values = []
)
  • action - handler
  • method - request type,
  • fields - fields and decorations.
  • values - field values.
FormBuilder::make(
action:'/crud/update',
method: 'PUT',
fields: [
Text::make('Text')
],
values: ['text' => 'Value']
)

Same thing through methods:

FormBuilder::make()
->action('/crud/update')
->method('PUT')
->fields([
Text::make('Text')
])
->fill(['text' => 'Value'])

Helper is also available:

{!! form(request()->url(), 'GET')
->fields([
Text::make('Text')
])
->fill(['text' => 'Value'])
!!}

Fields

The fields() method for declaring form fields and decorations:

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

Fill fields

fill() method for filling fields with values:

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

Casting

The cast() method for casting form values to a specific type.Since by default fields work with primitive types:

cast(MoonShineDataCast $cast)
use MoonShine\TypeCasts\ModelCast;
 
FormBuilder::make('/crud/update', 'PUT')
->fields([
Heading::make('Title'),
Text::make('Text'),
])
->fillCast(
['text' => 'value'],
ModelCast::make(User::class)
)

In this example, we cast the data to the User model format using ModelCast.

For more detailed information, please refer to the section TypeCasts

FillCast

The fillCast() method allows you to cast data to a specific type and immediately fill it with values:

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

or

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

Buttons

Form buttons can be modified and added.

To customize the "submit" button, use the submit() method.

submit(string $label, array $attributes = [])
  • label - button name,
  • attributes - additional attributes
FormBuilder::make('/crud/update', 'PUT')
->submit(label: 'Click me', attributes: ['class' => 'btn-primary'])

The hideSubmit() method allows you to hide the "submit" button.

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

To add new buttons based on ActionButton, use the buttons() method

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

Attributes

You can set any html attributes for the form using the customAttributes() method.

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

Form name

The name() method allows you to set a unique name for the form through which events can be raised.

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

Asynchronous mode

If you need to submit the form asynchronously, use the async() method.

async(
?string $asyncUrl = null,
string|array|null $asyncEvents = null,
?string $asyncCallback = null
)
  • asyncUrl - request url (by default the request is sent via action url),
  • asyncEvents - events raised after a successful request,
  • asyncCallback - js callback function after receiving a response.
FormBuilder::make('/crud/update', 'PUT')
->async()

After a successful request, you can raise events by adding the asyncEvents parameter.

FormBuilder::make('/crud/update', 'PUT')
->name('main-form')
->async(asyncEvents: ['table-updated-crud', 'form-reset-main-form'])

MoonShine already has a set of ready-made events:

  • table-updated-{name} - updating an asynchronous table by its name,
  • form-reset-{name} - reset form values by its name,
  • fragment-updated-{name} - updates a blade fragment by its name.

The async() method must come after the name() method!

Displaying validation errors

By default, validation errors are displayed at the top of the form.

errors_above_true errors_above_true_dark

The errorsAbove(bool $enable = true) method 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', 'PUT')
->errorsAbove(false)

errors_above_false errors_above_false_dark

Precognitive

If you need to perform precognition validation first, you need the precognitive() method.

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

Apply

The apply() method in FormBuilder iterates through 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 apply;
  • $after - callback function after apply;
  • $throw - throw exceptions.

Examples

It is necessary to save the data of all FormBuilder fields in the controller:

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

A more complex option, indicating 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
);

Calling methods

asyncMethod() allow you to specify the name of the method in the resource and call it asynchronously when sending FormBuilder without the need to create additional controllers.

public function components(): array
{
return [
FormBuilder::make()
->asyncMethod('updateSomething'),
];
}
// With toast
public function updateSomething(MoonShineRequest $request)
{
// $request->getResource();
// $request->getResource()->getItem();
// $request->getPage();
 
MoonShineUI::toast('MyMessage', 'success');
 
return back();
}
 
// Exception
public function updateSomething(MoonShineRequest $request)
{
throw new \Exception('My message');
}
 
// Custom json response
public function updateSomething(MoonShineRequest $request)
{
return MoonShineJsonResponse::make()->toast('MyMessage', ToastType::SUCCESS);
}

Dispatch events

To dispatch javascript events, you can use the dispatchEvent() method.

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

By default, when the request event is raised, all form data will be submitted. If the form is large, you may need to exclude a set of fields. You can exclude using the exclude parameter:

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

You can also completely exclude sending data through the withoutPayload parameter:

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

"Submit" event

To submit a form, you can call the Submit event.

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

Example of calling an event on a form page

public function formButtons(): array
{
return [
ActionButton::make('Save')->dispatchEvent(AlpineJs::event(JsEvent::FORM_SUBMIT, $this->uriKey()))
];
}

For more information about AlpineJs helpers, please refer to Js events.