FileUpload Component is reloading after the first upload

I have a ComponentAction that opens a model that contains a FileUpload field. After uploading the first file the field resets spitting out Cannot read properties of null (reading 'getFiles') from file-upload.js?v=3.2.131.0:40. I can then immediately attach a file again and then it works fine. When i submit the form the form data object shows to have both files. Any help here would be appreciated.
ComponentAction::make('Message')
->label('Message')
->icon('heroicon-s-chat-bubble-bottom-center-text')
->modalDescription('Send us a message or files regarding this order.')
->modalSubmitActionLabel('Submit')
->form([

Textarea::make('message')
->rows(5),
FileUpload::make('attachments')
->disk('s3')
->multiple(),
])
->action(function (Opportunity $record, $data) {
return true;
}),
ComponentAction::make('Message')
->label('Message')
->icon('heroicon-s-chat-bubble-bottom-center-text')
->modalDescription('Send us a message or files regarding this order.')
->modalSubmitActionLabel('Submit')
->form([

Textarea::make('message')
->rows(5),
FileUpload::make('attachments')
->disk('s3')
->multiple(),
])
->action(function (Opportunity $record, $data) {
return true;
}),
Solution:
For those who stumble upon this thread, the problem I think is related to the same problem which causes actions to perform an additional query of the data when triggered. The solution I came up with was to just create my own custom view action and modal. Some solutions talk about reaching for things like wire-elements/modal but this can just as easily be done using FilamentPHPs built in modal views. I first start by creating a custom view for my modal and added it to my Resource's section header action: ``` ComponentActionAlias::make('Message')...
Jump to solution
4 Replies
toeknee
toeknee2mo ago
in your custom componentAction are you filling the form on mount?
daikazu
daikazuOP2mo ago
I did try filling the form and I still have the same results. I've tried this on both local and S3 disks. Here is a Gist of the entire resource class. Line 764 is the is the file upload field. https://gist.github.com/daikazu/f37babd13eaaecbcd941d98c9c15a95e
Solution
daikazu
daikazu4w ago
For those who stumble upon this thread, the problem I think is related to the same problem which causes actions to perform an additional query of the data when triggered. The solution I came up with was to just create my own custom view action and modal. Some solutions talk about reaching for things like wire-elements/modal but this can just as easily be done using FilamentPHPs built in modal views. I first start by creating a custom view for my modal and added it to my Resource's section header action:
ComponentActionAlias::make('Message')
->label('Message')
->view('filament.modals.customer-message'),
ComponentActionAlias::make('Message')
->label('Message')
->view('filament.modals.customer-message'),
customer-message.blade.php
<x-filament::modal id="send-message-form" width="4xl" :close-by-clicking-away="false" :close-by-escaping="true">
<x-slot name="trigger">
<x-filament::button icon="heroicon-s-chat-bubble-bottom-center-text" label="Message">
Message
</x-filament::button>
</x-slot>

<x-slot name="heading">Send Us A Message</x-slot>
<x-slot name="description">Send us a message or files regarding this order.</x-slot>

<livewire:customer-message-form
:email="$getRecord()->website->Email_Address__c"
:order-number="$getRecord()->Name"
/>

<x-slot name="footer">
<x-slot name="footerActions">
<x-filament::button
icon="heroicon-s-paper-airplane"
color="success"
label="Send"
x-on:click="$dispatch('send-customer-message')"
>
Send
</x-filament::button>

<x-filament::button
icon="heroicon-s-no-symbol"
color="danger"
label="Cancel"
x-on:click="$dispatch('close-modal', { id: 'send-message-form' })"
>
Cancel
</x-filament::button>
</x-slot>
</x-slot>
</x-filament::modal>
<x-filament::modal id="send-message-form" width="4xl" :close-by-clicking-away="false" :close-by-escaping="true">
<x-slot name="trigger">
<x-filament::button icon="heroicon-s-chat-bubble-bottom-center-text" label="Message">
Message
</x-filament::button>
</x-slot>

<x-slot name="heading">Send Us A Message</x-slot>
<x-slot name="description">Send us a message or files regarding this order.</x-slot>

<livewire:customer-message-form
:email="$getRecord()->website->Email_Address__c"
:order-number="$getRecord()->Name"
/>

<x-slot name="footer">
<x-slot name="footerActions">
<x-filament::button
icon="heroicon-s-paper-airplane"
color="success"
label="Send"
x-on:click="$dispatch('send-customer-message')"
>
Send
</x-filament::button>

<x-filament::button
icon="heroicon-s-no-symbol"
color="danger"
label="Cancel"
x-on:click="$dispatch('close-modal', { id: 'send-message-form' })"
>
Cancel
</x-filament::button>
</x-slot>
</x-slot>
</x-filament::modal>
daikazu
daikazuOP4w ago
And then I just created a Livewire component to handle the Form content and it now work like a charm!
# app/Livewire/CustomerMessageForm.php

class CustomerMessageForm extends Component implements HasForms
{
use InteractsWithForms;

#[Locked]
public ?string $email = null;

#[Locked]
public ?string $orderNumber = null;
public mixed $extraData = null;

/**
* @var array<string, mixed>
*/
public ?array $data = [];

public function mount(string $email, string $orderNumber, mixed $extraData = null): void
{

$this->email = $email;
$this->orderNumber = $orderNumber;
$this->extraData = $extraData;

$this->form->fill();

}

public function form(Form $form): Form
{
return $form
->schema([
Textarea::make('message')
->required()
->rows(5),

FileUpload::make('attachments')
->disk('s3')
->multiple()
//..
])
->statePath('data');
}

#[On('send-customer-message')]
public function submit(): void
{
$data = $this->form->getState();

$isMessageSent = SendCustomerServiceMessage::run(
email: $this->email,
orderNumber: $this->orderNumber,
data: $data
);

if ($isMessageSent) {
$this->form->fill();
$this->dispatch('close-modal', id: 'send-message-form');
Notification::make()
->title('Message Sent!')
->success()
->send();
} else {
Notification::make()
->title('Failed to send message, Please try again later')
->danger()
->send();
}
}
}
# app/Livewire/CustomerMessageForm.php

class CustomerMessageForm extends Component implements HasForms
{
use InteractsWithForms;

#[Locked]
public ?string $email = null;

#[Locked]
public ?string $orderNumber = null;
public mixed $extraData = null;

/**
* @var array<string, mixed>
*/
public ?array $data = [];

public function mount(string $email, string $orderNumber, mixed $extraData = null): void
{

$this->email = $email;
$this->orderNumber = $orderNumber;
$this->extraData = $extraData;

$this->form->fill();

}

public function form(Form $form): Form
{
return $form
->schema([
Textarea::make('message')
->required()
->rows(5),

FileUpload::make('attachments')
->disk('s3')
->multiple()
//..
])
->statePath('data');
}

#[On('send-customer-message')]
public function submit(): void
{
$data = $this->form->getState();

$isMessageSent = SendCustomerServiceMessage::run(
email: $this->email,
orderNumber: $this->orderNumber,
data: $data
);

if ($isMessageSent) {
$this->form->fill();
$this->dispatch('close-modal', id: 'send-message-form');
Notification::make()
->title('Message Sent!')
->success()
->send();
} else {
Notification::make()
->title('Failed to send message, Please try again later')
->danger()
->send();
}
}
}
resources/views/livewire/customer-message-form.blade.php
<div>
<form wire:submit="create">
{{ $this->form }}
</form>
</div>
<div>
<form wire:submit="create">
{{ $this->form }}
</form>
</div>

Did you find this page helpful?