CreateAnother Retain Some Data

With the panel builder, CreateAction, how can i retain data when a user clicks the create another button? Ive seen quite a few different ways to go about it, but none of them seemed that clean or native. Right now I am not even doing a custom action() and hoping i dont have to redo that whole process.
5 Replies
Mark Chaney
Mark ChaneyOP8mo ago
public static function createComparable($action, $form, $data, $livewire, $arguments): void
{
$model = $action->getModel();
$record = $action->process(function (array $data, Table $table) use ($model): Model {
$relationship = $table->getRelationship();
$pivotData = [];
if ($relationship instanceof BelongsToMany) {
$pivotColumns = $relationship->getPivotColumns();
$pivotData = Arr::only($data, $pivotColumns);
$data = Arr::except($data, $pivotColumns);
}
if ($translatableContentDriver = $table->makeTranslatableContentDriver()) {
$record = $translatableContentDriver->makeRecord($model, $data);
} else {
$record = new $model;
$record->fill($data);
}
if (
(! $relationship) ||
$relationship instanceof HasManyThrough
) {
$record->save();
return $record;
}
if ($relationship instanceof BelongsToMany) {
$relationship->save($record, $pivotData);
return $record;
}
/** @phpstan-ignore-next-line */
$relationship->save($record);
return $record;
});
$action->record($record);
$form->model($record)->saveRelationships();
$livewire->mountedTableActionRecord($record->getKey());

if ($arguments['another'] ?? false) {
$action->record(null);
// Ensure that the form record is anonymized so that relationships aren't loaded.
$form->model(self::class);
$livewire->mountedTableActionRecord(null);
$preservedData = Arr::only($data, ['property_id']);
$form->fill();
$form->fill($preservedData);
$action->successNotificationTitle('Comparable Unit added successfully');
$action->success();
$action->halt();
return;
}
$action->successNotificationTitle('Comparable Unit added successfully');
$action->success();
}
public static function createComparable($action, $form, $data, $livewire, $arguments): void
{
$model = $action->getModel();
$record = $action->process(function (array $data, Table $table) use ($model): Model {
$relationship = $table->getRelationship();
$pivotData = [];
if ($relationship instanceof BelongsToMany) {
$pivotColumns = $relationship->getPivotColumns();
$pivotData = Arr::only($data, $pivotColumns);
$data = Arr::except($data, $pivotColumns);
}
if ($translatableContentDriver = $table->makeTranslatableContentDriver()) {
$record = $translatableContentDriver->makeRecord($model, $data);
} else {
$record = new $model;
$record->fill($data);
}
if (
(! $relationship) ||
$relationship instanceof HasManyThrough
) {
$record->save();
return $record;
}
if ($relationship instanceof BelongsToMany) {
$relationship->save($record, $pivotData);
return $record;
}
/** @phpstan-ignore-next-line */
$relationship->save($record);
return $record;
});
$action->record($record);
$form->model($record)->saveRelationships();
$livewire->mountedTableActionRecord($record->getKey());

if ($arguments['another'] ?? false) {
$action->record(null);
// Ensure that the form record is anonymized so that relationships aren't loaded.
$form->model(self::class);
$livewire->mountedTableActionRecord(null);
$preservedData = Arr::only($data, ['property_id']);
$form->fill();
$form->fill($preservedData);
$action->successNotificationTitle('Comparable Unit added successfully');
$action->success();
$action->halt();
return;
}
$action->successNotificationTitle('Comparable Unit added successfully');
$action->success();
}
This works, but not my favorite solution as i have to include a lot of logic that im not overriding. If i can avoid it, please let me know. Im then calling it with:
->action(fn ($action, $form, $data, $livewire, $arguments) => ComparableUnit::createComparable($action, $form, $data, $livewire, $arguments))
->action(fn ($action, $form, $data, $livewire, $arguments) => ComparableUnit::createComparable($action, $form, $data, $livewire, $arguments))
ah shoot, this would require changes based on if this is a standalone or table action too. grrr There has to be a better way to do this. Seems pretty natural to want some customization with create another fills
dissto
dissto8mo ago
I needed something similar but also wasn't satisfied. I simply get the latest created model and fill it with that. This will inevitably introduce race conditions though. But in my case it was only for models that also have a user_id on it so it was no big deal🤔
青木
青木2mo ago
I used a different approach by redirecting the logic about another in the engorged create method.
<?php

namespace App\Filament\Pda\Resources\DataBatchItemResource\Pages;

use App\Filament\Pda\Resources\DataBatchItemResource;
use Filament\Resources\Pages\CreateRecord;
use Filament\Support\Exceptions\Halt;
use Filament\Support\Facades\FilamentView;

use function Filament\Support\is_app_url;

class CreateDataBatchItem extends CreateRecord
{
protected static string $resource = DataBatchItemResource::class;

public function create(bool $another = false): void
{
...

$redirectUrl = $this->getRedirectUrl();

if ($another) {
$resource = static::getResource();

$redirectUrl = $resource::getUrl('create', ['record' => $this->getRecord(), ...$this->getRedirectUrlParameters()]);
}

$this->redirect($redirectUrl, navigate: FilamentView::hasSpaMode() && is_app_url($redirectUrl));
}

protected function mutateFormDataBeforeCreate(array $data): array
{
$data['user_id'] = auth('web')->id();

return parent::mutateFormDataBeforeCreate($data);
}

protected function getRedirectUrlParameters(): array
{
$data = [];

if (isset(request()->query('tableFilters')['batch_id']['batch_id'])) {
$data = ['tableFilters[batch_id][batch_id]' => request()->query('tableFilters')['batch_id']['batch_id']];
}

if (isset($this->form->getRawState()['batch_id'])) {
$data = ['tableFilters[batch_id][batch_id]' => $this->form->getRawState()['batch_id']];
}

return $data;
}
}
<?php

namespace App\Filament\Pda\Resources\DataBatchItemResource\Pages;

use App\Filament\Pda\Resources\DataBatchItemResource;
use Filament\Resources\Pages\CreateRecord;
use Filament\Support\Exceptions\Halt;
use Filament\Support\Facades\FilamentView;

use function Filament\Support\is_app_url;

class CreateDataBatchItem extends CreateRecord
{
protected static string $resource = DataBatchItemResource::class;

public function create(bool $another = false): void
{
...

$redirectUrl = $this->getRedirectUrl();

if ($another) {
$resource = static::getResource();

$redirectUrl = $resource::getUrl('create', ['record' => $this->getRecord(), ...$this->getRedirectUrlParameters()]);
}

$this->redirect($redirectUrl, navigate: FilamentView::hasSpaMode() && is_app_url($redirectUrl));
}

protected function mutateFormDataBeforeCreate(array $data): array
{
$data['user_id'] = auth('web')->id();

return parent::mutateFormDataBeforeCreate($data);
}

protected function getRedirectUrlParameters(): array
{
$data = [];

if (isset(request()->query('tableFilters')['batch_id']['batch_id'])) {
$data = ['tableFilters[batch_id][batch_id]' => request()->query('tableFilters')['batch_id']['batch_id']];
}

if (isset($this->form->getRawState()['batch_id'])) {
$data = ['tableFilters[batch_id][batch_id]' => $this->form->getRawState()['batch_id']];
}

return $data;
}
}
Mark Chaney
Mark ChaneyOP2mo ago
@青木 its changed a lot since then, its already natively available now
青木
青木2mo ago
Is the way you use different from me? I want to know how you do it.
Want results from more Discord servers?
Add your server