How to use Alpine in Filament?

If I have this very basic example: MyPage.php
namespace App\Filament\Pages;

class MyPage extends Page implements HasForms
{
use InteractsWithForms;

public string $my_text_input = 'Hello, World!';
public string $another_text_input = 'How are you?';

public function form(Form $form): Form
{
return $form
->schema([
TextInput::make('my_text_input'),
TextInput::make('another_text_input'),
]);
}
}
namespace App\Filament\Pages;

class MyPage extends Page implements HasForms
{
use InteractsWithForms;

public string $my_text_input = 'Hello, World!';
public string $another_text_input = 'How are you?';

public function form(Form $form): Form
{
return $form
->schema([
TextInput::make('my_text_input'),
TextInput::make('another_text_input'),
]);
}
}
my-page.blade.php
<x-filament-panels::page>

<script>
document.addEventListener('alpine:init', () => {
console.log('Alpine initialized'); // It works

Alpine.data('my_text_input', ({ state }) => ({
state,

init() {
console.log(this.state) // Doesn't work
},
onclick() {
console.log(this.state) // Doesn't work
},
change() {
console.log(this.state) // Doesn't work
},

})
</script>

{{ $this->form }}

</x-filament-panels::page>
<x-filament-panels::page>

<script>
document.addEventListener('alpine:init', () => {
console.log('Alpine initialized'); // It works

Alpine.data('my_text_input', ({ state }) => ({
state,

init() {
console.log(this.state) // Doesn't work
},
onclick() {
console.log(this.state) // Doesn't work
},
change() {
console.log(this.state) // Doesn't work
},

})
</script>

{{ $this->form }}

</x-filament-panels::page>
I can't understand how I can access the field state from alpine... What if I want to change the state of another_text_input each time my_text_input state changes, for example?
16 Replies
ralphjsmit
ralphjsmit23h ago
Ah! This works just the same as sharing any other Livewire state with JS, with the only difference that the LW property is also written/read by Filament in addition to your own reads/writes. Try
<div
x-data="{
my_text_input: $wire.entangle('my_text_input').live,
another_text_input: $wire.entangle('another_text_input').live
}
x-init="..."
>
</div>
<div
x-data="{
my_text_input: $wire.entangle('my_text_input').live,
another_text_input: $wire.entangle('another_text_input').live
}
x-init="..."
>
</div>
See https://livewire.laravel.com/docs/alpine#sharing-state-using-wireentangle Also, I would personally not recommend creating individual properties for all of them, but just to add public ?array $data = null and then $form->statePath('data'), then you will only have just one property on your Livewire. And then in Alpine you do state: $wire.entangle('state').live. (You are also missing a mount() method that includes a $this->form->fill() but perhaps you just omitted that for simplicity)
charlie
charlieOP23h ago
Thank you but what I looking for is a way to interact with an existing TextInput or ColorPicker without extending it (if possible)
ralphjsmit
ralphjsmit23h ago
Yes, with what I shared you can
charlie
charlieOP23h ago
In my case I doesn't need any database connection, I try to avoid request and do all the reactive logic with Alpine only, without Livewire wait, I'll read your message again
ralphjsmit
ralphjsmit23h ago
If you update the my_text_input, then Alpine is entangled with the $my_text_input on the server. That means that if you update that property in Alpine, the $my_text_input property also gets updated on the server. In turn, your TextInput or ColorPicker is also entangled with $my_text_input, so if $my_text_input updates, your TextInput or ColorPicker also updates. And that also goes two-ways, if your TextInput or ColorPicker state updates, then the $my_text_input gets updated, Livewire/Alpine knows that it is entangled as well with your custom x-data and then it gets updated both You should try, but it might even work without the .live and without a server request
charlie
charlieOP23h ago
So what you say is I need to entangle myself the fields in a div? Like that?
<x-filament-panels::page>
<div
x-data="{
my_text_input: $wire.entangle('my_text_input').live,
another_text_input: $wire.entangle('another_text_input').live
}
x-init="..."
>
{{ $this->form }}
</div>

<script>
document.addEventListener('alpine:init', () => {
console.log('Alpine initialized'); // It works

Alpine.data('my_text_input', ({ state }) => ({
state,

init() {
console.log(this.state) // Doesn't work
},
onclick() {
console.log(this.state) // Doesn't work
},
change() {
console.log(this.state) // Doesn't work
},

})
</script>

</x-filament-panels::page>
<x-filament-panels::page>
<div
x-data="{
my_text_input: $wire.entangle('my_text_input').live,
another_text_input: $wire.entangle('another_text_input').live
}
x-init="..."
>
{{ $this->form }}
</div>

<script>
document.addEventListener('alpine:init', () => {
console.log('Alpine initialized'); // It works

Alpine.data('my_text_input', ({ state }) => ({
state,

init() {
console.log(this.state) // Doesn't work
},
onclick() {
console.log(this.state) // Doesn't work
},
change() {
console.log(this.state) // Doesn't work
},

})
</script>

</x-filament-panels::page>
ralphjsmit
ralphjsmit23h ago
Yeah for example You need to entangle it somehow It depends on what you want to do with it again after you got access to the values
ralphjsmit
ralphjsmit23h ago
Laravel
Properties | Laravel
A full-stack framework for Laravel that takes the pain out of building dynamic UIs.
ralphjsmit
ralphjsmit23h ago
Then you dont need a div
charlie
charlieOP23h ago
Ok, I thought it was already entangled by Filament. I cannot say I understand better 😅 , but thank you very much, I will explore all that To add a bit of context, what I'm trying to do is exactly that: https://filament-theme-generator.charlie-etienne.fr/ so update the code when the color changes, BUT in client only (since it doesn't need to call the server here)
LeandroFerreira
LeandroFerreira22h ago
maybe $watch ?
x-init="
console.log(my_text_input);
$watch('my_text_input', value => console.log(value))
"
x-init="
console.log(my_text_input);
$watch('my_text_input', value => console.log(value))
"
I think you can also use extraAlpineAttributes in the form fields like
TextInput::make('my_text_input')
->extraAlpineAttributes(['x-on:click' => 'console.log(my_text_input)'])
TextInput::make('my_text_input')
->extraAlpineAttributes(['x-on:click' => 'console.log(my_text_input)'])
charlie
charlieOP22h ago
Thank you @Leandro Ferreira , yeah I wanted to avoid extraAttributes cause I have a bunch of JS and I would prefer to extract it.
LeandroFerreira
LeandroFerreira22h ago
ok, I think you can also use an eventlistener like
x-data="{
my_text_input: $wire.entangle('my_text_input'),
clickListener() {
$el.addEventListener('click', () => {
if (event.target.id === 'my_text_input') {
console.log(this.my_text_input);
}
});
}
}"

x-init="clickListener()"
x-data="{
my_text_input: $wire.entangle('my_text_input'),
clickListener() {
$el.addEventListener('click', () => {
if (event.target.id === 'my_text_input') {
console.log(this.my_text_input);
}
});
}
}"

x-init="clickListener()"
charlie
charlieOP19h ago
oh, interesting, thanks Yeah, I did it!!! https://filament-theme-generator.charlie-etienne.fr/ Not even one server request! I don't know if it follows the best Alpine practices, but I manage to make it work and it's FAST Thanks to both of you @Leandro Ferreira and @ralphjsmit
LeandroFerreira
LeandroFerreira18h ago
Filament V4 will provide afterStateUpdatedJs https://x.com/leandrocfe/status/1816568005020516788
Leandro Ferreira (@leandrocfe) on X
In Filament V4, a new method called afterStateUpdatedJs will be introduced, enabling state updates on the client side using Javascript 🤯
From An unknown user
X
charlie
charlieOP18h ago
wow, this feature is pure gold

Did you find this page helpful?