diff --git a/packages/forms/docs/04-layout/06-section.md b/packages/forms/docs/04-layout/06-section.md index c6dbc394c9..5ca9a248e4 100644 --- a/packages/forms/docs/04-layout/06-section.md +++ b/packages/forms/docs/04-layout/06-section.md @@ -69,15 +69,15 @@ use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Section; Section::make('Rate limiting') + ->schema([ + // ... + ]) ->footerActions([ Action::make('test') ->action(function () { // ... }), ]) - ->schema([ - // ... - ]) ``` @@ -94,6 +94,9 @@ use Filament\Forms\Components\Section; use Filament\Support\Enums\Alignment; Section::make('Rate limiting') + ->schema([ + // ... + ]) ->footerActions([ Action::make('test') ->action(function () { @@ -101,9 +104,6 @@ Section::make('Rate limiting') }), ]) ->footerActionsAlignment(Alignment::End) - ->schema([ - // ... - ]) ``` ### Adding actions to a section without heading diff --git a/packages/panels/docs/03-resources/04-editing-records.md b/packages/panels/docs/03-resources/04-editing-records.md index c0b8668ff2..ee5a1ab4b2 100644 --- a/packages/panels/docs/03-resources/04-editing-records.md +++ b/packages/panels/docs/03-resources/04-editing-records.md @@ -178,6 +178,37 @@ class EditUser extends EditRecord Alternatively, if you're editing records in a modal action, check out the [Actions documentation](../../actions/prebuilt-actions/edit#lifecycle-hooks). +## Saving a part of the form independently + +You may want to allow the user to save a part of the form independently of the rest of the form. One way to do this is with a [section action in the header or footer](../../forms/layout/section#adding-actions-to-the-sections-header-or-footer). From the `action()` method, you can call `saveFormComponentOnly()`, passing in the `Section` component that you want to save: + +```php +use Filament\Forms\Components\Actions\Action; +use Filament\Forms\Components\Section; +use Filament\Notifications\Notification; +use Filament\Resources\Pages\EditRecord; + +Section::make('Rate limiting') + ->schema([ + // ... + ]) + ->footerActions([ + fn (string $operation): Action => Action::make('save') + ->action(function (Section $component, EditRecord $livewire) { + $livewire->saveFormComponentOnly($component); + + Notification::make() + ->title('Rate limiting saved') + ->body('The rate limiting settings have been saved successfully.') + ->success() + ->send(); + }) + ->visible($operation === 'edit'), + ]) +``` + +The `$operation` helper is available, to ensure that the action is only visible when the form is being edited. + ## Halting the saving process At any time, you may call `$this->halt()` from inside a lifecycle hook or mutation method, which will halt the entire saving process: diff --git a/packages/panels/src/Resources/Pages/EditRecord.php b/packages/panels/src/Resources/Pages/EditRecord.php index c6bd501482..1c219cccc2 100644 --- a/packages/panels/src/Resources/Pages/EditRecord.php +++ b/packages/panels/src/Resources/Pages/EditRecord.php @@ -9,6 +9,8 @@ use Filament\Actions\ForceDeleteAction; use Filament\Actions\ReplicateAction; use Filament\Actions\RestoreAction; use Filament\Actions\ViewAction; +use Filament\Forms\ComponentContainer; +use Filament\Forms\Components\Component; use Filament\Forms\Form; use Filament\Infolists\Infolist; use Filament\Notifications\Notification; @@ -172,6 +174,47 @@ class EditRecord extends Page } } + public function saveFormComponentOnly(Component $component): void + { + $this->authorizeAccess(); + + try { + $this->beginDatabaseTransaction(); + + $this->callHook('beforeValidate'); + + $data = ComponentContainer::make($component->getLivewire()) + ->schema([$component]) + ->model($component->getRecord()) + ->statePath($this->getFormStatePath()) + ->getState(); + + $this->callHook('afterValidate'); + + $data = $this->mutateFormDataBeforeSave($data); + + $this->callHook('beforeSave'); + + $this->handleRecordUpdate($this->getRecord(), $data); + + $this->callHook('afterSave'); + + $this->commitDatabaseTransaction(); + } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + $this->rollBackDatabaseTransaction() : + $this->commitDatabaseTransaction(); + + return; + } catch (Throwable $exception) { + $this->rollBackDatabaseTransaction(); + + throw $exception; + } + + $this->rememberData(); + } + protected function getSavedNotification(): ?Notification { $title = $this->getSavedNotificationTitle();