Custom Field does not submit data

Created a custom field as in the docs, using artisan make:form-field ProductPrices. The component looks like this and receives an array of Currency models:
class ProductPrices extends Field {
protected string $view = 'forms.components.product-prices';

protected array|Arrayable|string|Closure|null $currencies = null;

public function currencies( array|Arrayable|string|Closure|null $currencies ): static {
$this->currencies = $currencies;

return $this;
}

public function getCurrencies(): Collection {
return $this->evaluate( $this->currencies ) ?? new Collection();
}
}
class ProductPrices extends Field {
protected string $view = 'forms.components.product-prices';

protected array|Arrayable|string|Closure|null $currencies = null;

public function currencies( array|Arrayable|string|Closure|null $currencies ): static {
$this->currencies = $currencies;

return $this;
}

public function getCurrencies(): Collection {
return $this->evaluate( $this->currencies ) ?? new Collection();
}
}
And I use it in my form as:
->schema([
...
ProductPrices::make( 'pricesTest' )->currencies( Currency::all() ),
...]);
->schema([
...
ProductPrices::make( 'pricesTest' )->currencies( Currency::all() ),
...]);
The view of my custom component is:
@php
$currencies = $getCurrencies();
$id = $getId();
$statePath = $getStatePath();
@endphp

<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
<div>
@foreach($currencies as $currency)
@php $subStatePath = $statePath.'.'.$currency->id; @endphp
@php /* @var \App\Models\Currencies\Currency $currency */ @endphp
<div>
<input {{ $applyStateBindingModifiers('wire:model') }}="{{ $subStatePath }}">
</div>
@endforeach
</div>
</x-dynamic-component>
@php
$currencies = $getCurrencies();
$id = $getId();
$statePath = $getStatePath();
@endphp

<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
<div>
@foreach($currencies as $currency)
@php $subStatePath = $statePath.'.'.$currency->id; @endphp
@php /* @var \App\Models\Currencies\Currency $currency */ @endphp
<div>
<input {{ $applyStateBindingModifiers('wire:model') }}="{{ $subStatePath }}">
</div>
@endforeach
</div>
</x-dynamic-component>
And an input field is indeed generated for every currency: <div><input wire:model="data.pricesTest.1"></div> In EditProduct extends EditRecord, where I use the ProductResource with said form I do a dd():
protected function mutateFormDataBeforeSave( array $data ): array {
dd('before',$data);
}
protected function mutateFormDataBeforeSave( array $data ): array {
dd('before',$data);
}
array:12 [
...
"pricesTest" => null
...
]
array:12 [
...
"pricesTest" => null
...
]
Other values of 'default' Filament form fields are there but I cannot figure out why my custom field PricesTest isn't submitted into the form data. Can someone please point me where I'm going wrong?
Solution:
Thanks again for your help @Lara Zeus . It seems that the setup() function in the ProductPrices does the trick. I think it needs to be setup as an array. And it works when setting it up in the same way that CheckboxList() does. Final working code of the custom field: ```php class ProductPrices extends Field { ...
Jump to solution
6 Replies
Lara Zeus
Lara Zeus5mo ago
this can be obvious questions but 🙂 - the pricesTest is exist in db - pricesTest is fillable in your model - pricesTest is cast to array also after saving, check the database directly to sees if it stored or not
jelmerkeij
jelmerkeij5mo ago
Thank you for taking the time to reply. pricesTest isn't a real property on my Product model but for the sake of trying to work it out this doesn't make any difference when added:
class Product extends Model
{
use SoftDeletes;

public $pricesTest = [];

public $casts = [
'pricesTest' => 'array',
];

protected $fillable = [
'product_number',
'name',
...
'pricesTest',
];
...
}
class Product extends Model
{
use SoftDeletes;

public $pricesTest = [];

public $casts = [
'pricesTest' => 'array',
];

protected $fillable = [
'product_number',
'name',
...
'pricesTest',
];
...
}
I would expect the dd() data in mutateFormDataBeforeSave() to show the data from the form and not necessarily the model attributes. But it still comes up as null in mutateFormDataBeforeSave(). (also tried adding a column pricesTest to the db)
Lara Zeus
Lara Zeus5mo ago
ok do you get a console error?
Lara Zeus
Lara Zeus5mo ago
ok I tested you code, and I remember my class extending CheckboxList not Field not sure which trait you need (didnt deg deepr), but if it dosnt make any diff to you you can also extend CheckboxList and all will work
No description
jelmerkeij
jelmerkeij5mo ago
Thanks, I will look into this and report back if I get it working. If anybody knows which trait is needed then please let me know!
Solution
jelmerkeij
jelmerkeij5mo ago
Thanks again for your help @Lara Zeus . It seems that the setup() function in the ProductPrices does the trick. I think it needs to be setup as an array. And it works when setting it up in the same way that CheckboxList() does. Final working code of the custom field:
class ProductPrices extends Field {

protected string $view = 'forms.components.product-prices';

protected array|Arrayable|string|Closure|null $currencies = null;

protected function setUp(): void
{
parent::setUp();

$this->default([]);

$this->afterStateHydrated(static function (ProductPrices $component, $state) {
if (is_array($state)) {
return;
}

$component->state([]);
});
}

public function currencies( array|Arrayable|string|Closure|null $currencies ): static {
$this->currencies = $currencies;

return $this;
}

public function getCurrencies(): Collection {
return $this->evaluate( $this->currencies ) ?? new Collection();
}
}
class ProductPrices extends Field {

protected string $view = 'forms.components.product-prices';

protected array|Arrayable|string|Closure|null $currencies = null;

protected function setUp(): void
{
parent::setUp();

$this->default([]);

$this->afterStateHydrated(static function (ProductPrices $component, $state) {
if (is_array($state)) {
return;
}

$component->state([]);
});
}

public function currencies( array|Arrayable|string|Closure|null $currencies ): static {
$this->currencies = $currencies;

return $this;
}

public function getCurrencies(): Collection {
return $this->evaluate( $this->currencies ) ?? new Collection();
}
}