jelmerkeij
jelmerkeij
FFilament
Created by jelmerkeij on 4/19/2024 in #❓┊help
Spatie Translatable plugin: Possible to have persistent LocaleSwitcher?
Is it possible to have the LocaleSwitcher be persistent when navigating through List and Edit ResourcePages? So for example whenthe user selects the language "Spanish" it keeps it in the session or wherever and when reloading the page or navigating to another resource page that has the LocaleSwitcher it's still in Spanish instead of being reloaded to the first language (English) defined in:
SpatieLaravelTranslatablePlugin::make()->defaultLocales([
'en',
'es',
]),
SpatieLaravelTranslatablePlugin::make()->defaultLocales([
'en',
'es',
]),
2 replies
FFilament
Created by jelmerkeij on 3/12/2024 in #❓┊help
FileUpload: Uploading (large files) directly to S3
Again I'm struggling with uploading of large files (several gigabytes). I am experimenting with using the S3 (in my case, DigitalOcean) as the filesystem. This in the hopes of having the FileUpload component set up to upload directly to the server when selecting a file instead of sending it to a temp directory on the webserver first and avoiding "File too large" errors. But I cannot figure out how to do this. Is this even possible? Can anybody please point me in the right direction of example?
8 replies
FFilament
Created by jelmerkeij on 1/5/2024 in #❓┊help
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?
11 replies
FFilament
Created by jelmerkeij on 12/20/2023 in #❓┊help
Select list: How to handle soft deleted (trashed) relations?
In my form for a QuoteResource I have a Repeater with in there a Selectlist that uses a relation to select a product:
Forms\Components\Select::make( 'product_id' )
->relationship( 'product')
->getOptionLabelFromRecordUsing( fn( Product $record ) => ProductHelper::formatProductToSelectListOptionLabel( $record ) )
->searchable( [ 'name', 'product_number' ] );
Forms\Components\Select::make( 'product_id' )
->relationship( 'product')
->getOptionLabelFromRecordUsing( fn( Product $record ) => ProductHelper::formatProductToSelectListOptionLabel( $record ) )
->searchable( [ 'name', 'product_number' ] );
Now say the product get soft deleted in the meantime. If I go back to editing my quote in which this product was previously selected the selectlist now shows up empty because the product is of course deleted. I expect it to be still filled with the trashed product, but when trying to select a different product it should not show up available for selection. I've tried adding modifyQueryUsing: fn( Builder $query ) => $query->withTrashed() to the relationship parameters but this makes deleted products available for selection when adding a new item as well. Can anybody point me to how to handle this kind of situation?
2 replies
FFilament
Created by jelmerkeij on 12/14/2023 in #❓┊help
How to add extraAttributes (class) to Section container?
My form schema looks like this:
public static function form( Form $form ): Form {
return $form
->schema( [
Forms\Components\Group::make()->schema( [
Forms\Components\Section::make()
->schema( static::getDetailsFormSchema() )
->columns( 2 ),

Forms\Components\Section::make()
->schema( [ static::getItemsRepeater() ] )
->columns( 1 ),

Forms\Components\Section::make()
->schema( static::getQuoteGrandTotalsSchema() )
->columns( 1 ),
] )
] )
->columns( null );
}
public static function form( Form $form ): Form {
return $form
->schema( [
Forms\Components\Group::make()->schema( [
Forms\Components\Section::make()
->schema( static::getDetailsFormSchema() )
->columns( 2 ),

Forms\Components\Section::make()
->schema( [ static::getItemsRepeater() ] )
->columns( 1 ),

Forms\Components\Section::make()
->schema( static::getQuoteGrandTotalsSchema() )
->columns( 1 ),
] )
] )
->columns( null );
}
The output on the frontend is below (excerpt from the section). Now I want to add an extra CSS class to the column that contains the last section. Is that possible, and if so - how?
[For every Section the same div appears like this. I want to add the css class on the last section container as it were]

<div style="--col-span-default: 1 / -1;" class="col-[--col-span-default]"> <-- WANT TO ADD EXTRA CLASS HERE
<!--[if BLOCK]><![endif]-->
<section x-data="{
isCollapsed: false ,
}" class="fi-section rounded-xl bg-white shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
<!--[if BLOCK]><![endif]--> <!--[if ENDBLOCK]><![endif]-->
<div class="fi-section-content-ctn">
<div class="fi-section-content p-6">
[my GrandTotalsComponent here]
</div>
</div>
</section>
<!--[if ENDBLOCK]><![endif]-->
</div>
[For every Section the same div appears like this. I want to add the css class on the last section container as it were]

<div style="--col-span-default: 1 / -1;" class="col-[--col-span-default]"> <-- WANT TO ADD EXTRA CLASS HERE
<!--[if BLOCK]><![endif]-->
<section x-data="{
isCollapsed: false ,
}" class="fi-section rounded-xl bg-white shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
<!--[if BLOCK]><![endif]--> <!--[if ENDBLOCK]><![endif]-->
<div class="fi-section-content-ctn">
<div class="fi-section-content p-6">
[my GrandTotalsComponent here]
</div>
</div>
</section>
<!--[if ENDBLOCK]><![endif]-->
</div>
4 replies
FFilament
Created by jelmerkeij on 8/9/2023 in #❓┊help
How to set state 'is loading' or 'blocked' in modal form
9 replies
FFilament
Created by jelmerkeij on 8/4/2023 in #❓┊help
`mutateFormDataUsing()` not working on CreateAction?
In an Example app with Filament 3.0.7 I've setup a 'Tester' model with just 1 attribute - $name:
class Tester extends Model {

protected $fillable = [
'name',
];
}
class Tester extends Model {

protected $fillable = [
'name',
];
}
And generated a TestersResource for it. Now on the ListTesters::getHeaderActions() I'm trying to override the name on save:
Actions\CreateAction::make()->mutateFormDataUsing( function ( array $data ) {
$data['name'] = 'Overridden name';

return $data;
} ),
Actions\CreateAction::make()->mutateFormDataUsing( function ( array $data ) {
$data['name'] = 'Overridden name';

return $data;
} ),
The value is then not set in the model when saving. Am I doing something wrong? However setting the same mutateFormUsing on the EditAction does indeed work and set the model's $name attribute value to Overridden name.
4 replies
FFilament
Created by jelmerkeij on 8/4/2023 in #❓┊help
Livewire component has 'undefined variable' after updating Livewire?
I've setup a FormField as Livewire component in the a testing app using Filament 3 and Livewire 3: Component:
<?php

namespace App\Forms\Components;

use Filament\Forms\Components\Field;

class RangeSlider extends Field
{
protected string $view = 'forms.components.range-slider';

public string $testVar = 'testValue';
}
<?php

namespace App\Forms\Components;

use Filament\Forms\Components\Field;

class RangeSlider extends Field
{
protected string $view = 'forms.components.range-slider';

public string $testVar = 'testValue';
}
View:
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
Value is: {{ $testVar }}

<div x-data="{ state: $wire.entangle('{{ $getStatePath() }}') }">
<!-- Interact with the `state` property in Alpine.js -->
</div>
</x-dynamic-component>
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
Value is: {{ $testVar }}

<div x-data="{ state: $wire.entangle('{{ $getStatePath() }}') }">
<!-- Interact with the `state` property in Alpine.js -->
</div>
</x-dynamic-component>
Now where it says 'value is' it correctly echoed the value of my $testVar, but after updating via Composer it now throws an error Undefined variable $testVar Is there any way to mitigate this? Composer:
composer update -W
...
- Upgrading livewire/livewire (v3.0.0-beta.6 => v3.0.0-beta.7): Extracting archive
- Upgrading filament/support (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/widgets (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/actions (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/notifications (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/infolists (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/forms (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/tables (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/filament (v3.0.6 => v3.0.7): Extracting archive
- Upgrading guzzlehttp/psr7 (2.5.0 => 2.6.0): Extracting archive
- Upgrading guzzlehttp/promises (2.0.0 => 2.0.1): Extracting archive
- Upgrading phpunit/phpunit (10.2.7 => 10.3.1): Extracting archive
composer update -W
...
- Upgrading livewire/livewire (v3.0.0-beta.6 => v3.0.0-beta.7): Extracting archive
- Upgrading filament/support (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/widgets (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/actions (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/notifications (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/infolists (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/forms (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/tables (v3.0.6 => v3.0.7): Extracting archive
- Upgrading filament/filament (v3.0.6 => v3.0.7): Extracting archive
- Upgrading guzzlehttp/psr7 (2.5.0 => 2.6.0): Extracting archive
- Upgrading guzzlehttp/promises (2.0.0 => 2.0.1): Extracting archive
- Upgrading phpunit/phpunit (10.2.7 => 10.3.1): Extracting archive
6 replies
FFilament
Created by jelmerkeij on 6/16/2023 in #❓┊help
Set column action on condition
I have a table of products. Now if the product is of type 'bundled product' I want to bind an action that when clicked on the product name (the TextColumn) a modal opens displaying the contents of the product bundle. But if the product is not of type 'bundled' then you shouldn't be able to click the product name since there are no bundled products to display in the modal. So the action should not be attached in that case.
Tables\Columns\TextColumn::make( 'name' )
->sortable()
->searchable()
->action(
Tables\Actions\Action::make( 'showBundledProductsInModal' )
->action( fn() => null )
->modalHeading( 'Products in this bundle' )
->modalActions( [] )
->modalContent( fn( $record ) => view( 'filament.resources.products.table.bundled-products', [ 'record' => $record ] ) )
// I've tried visible, hidden...
//->visible( fn(): bool => ! empty( $this->record->product_type ) && (int) $this->record->product_type === ProductTypeEnum::BUNDLED->value )
),
Tables\Columns\TextColumn::make( 'name' )
->sortable()
->searchable()
->action(
Tables\Actions\Action::make( 'showBundledProductsInModal' )
->action( fn() => null )
->modalHeading( 'Products in this bundle' )
->modalActions( [] )
->modalContent( fn( $record ) => view( 'filament.resources.products.table.bundled-products', [ 'record' => $record ] ) )
// I've tried visible, hidden...
//->visible( fn(): bool => ! empty( $this->record->product_type ) && (int) $this->record->product_type === ProductTypeEnum::BUNDLED->value )
),
I've tried visible, hidden() on the action but they don't seem to work. Not when using a closure and not when passing in a hardcoded true of false value. The product name is always clickable and the action is executed.  Is it even possible to have the action conditionally set? How would I do that? Thanks for any help and pointers.
18 replies
FFilament
Created by jelmerkeij on 6/15/2023 in #❓┊help
Form builder: Select with getSearchResultsUsing() shows id on form load instead of name
2 replies
FFilament
Created by jelmerkeij on 6/8/2023 in #❓┊help
Can afterStateHydrated know if new record or editing?
When using the afterStateHydrated on a select field in a form, can you know if it's in the modal for creating a new record or updating an existing one? I only want to set the pre-selected value of parent_id when creating a new record through the 'simple' resource manager but not when editing an existing record so the value of an existing records parent_id doesn't accidentally change.
Forms\Components\Select::make( 'parent_id' )
->options( self::getSelectParentChoices() )
->afterStateHydrated( static function ( Forms\Components\Select $component, $state, callable $get ) {
//TODO Don't do this when editing an exisitng record
$viewingParentId = $component->getLivewire()->parent_id ?? - 1;
$component->state($viewingParentId);
} )
Forms\Components\Select::make( 'parent_id' )
->options( self::getSelectParentChoices() )
->afterStateHydrated( static function ( Forms\Components\Select $component, $state, callable $get ) {
//TODO Don't do this when editing an exisitng record
$viewingParentId = $component->getLivewire()->parent_id ?? - 1;
$component->state($viewingParentId);
} )
4 replies