Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bvfi-dev's avatar

bvfi-dev liked a comment+100 XP

5mos ago

Livewire FormObject isDirty() equivalent?

One clean approach is to store a snapshot of the form state after preFillEntry() and compare against it later. Instead of manually coding this in every FormObject, you can abstract it once in a base Form class:

public array $original = [];

public function snapshot(): void { $this->original = $this->toArray(); }

public function isDirty(array $only = []): bool { $current = $this->toArray();

if ($only) {
    $current = Arr::only($current, $only);
    $original = Arr::only($this->original, $only);
} else {
    $original = $this->original;
}

return $current !== $original;

}

Then call $this->form->snapshot() after preFillEntry() in mount().

Now every FormObject automatically gets a reusable isDirty() without repeating logic and you can even check only specific fields.

bvfi-dev's avatar

bvfi-dev wrote a reply+100 XP

5mos ago

Livewire FormObject isDirty() equivalent?

Yea, that actually makes sense, I can just abstract and extend that, then use it instead of the form with a snapshot. Thank you for the idea

bvfi-dev's avatar

bvfi-dev started a new conversation+100 XP

5mos ago

Livewire FormObject isDirty() equivalent?

Im trying to use FormObjects for all my livewire components to reduce duplicate code, but I keep running into an issue where I need to check if the model was changed, like when in an edit form and checking if the initial state and save state are different, so that I can save on my API calls. In my Livewire Form, I have:

public function preFillEntry(User $entry):void
	{
		$entry->loadMissing('contact');
		$this->email = $entry->email;
		$this->first_name = $entry->first_name;
		$this->last_name = $entry->name;

which I call in my mount() method in my Component like so:

$this->form->preFillEntry($entry);

And then in my save() method, Id like to check if a couple of properties have changed, but of course I cant use isDirty(), so Im looking into alternatives and whats the best and optimal way around this issue?

I know i can just make an array in the FormObject, with the original state and then compare this in a custom isDirty() function that I call in the save method, but Im not sure if this is the most efficient way of doing it, since this will get very repetitive if i start introducing it in all my FormObjects

bvfi-dev's avatar

bvfi-dev wrote a reply+100 XP

5mos ago

Flash messages in Livewire

The thing with flash messages is you have to consider 2 scenarios when using Livewire:

  • One where you want instant notifications as soon as the button is clicked
  • One where there is a redirect in the session

I like making my stuff custom so that I always have 100% control over it, and also from my experience you need separate handles for both. I have for example an instant flash notification that appears on a click of a button that I call via Livewire's dispatch().

However If I redirect it would disappear so I need a session flash for after the session has been redirected and depending on your scenario you need to use one of these options.

Lets say I have a Livewire Index component and within it, I have create modal. What I would do on submitting the form is show a flash notification and make the modal not show -> User clicks "Submit" modal closes, notification is shown with results success/fail. This creates a smooth UI experience. However If I were to want to redirect to the edit page after submitting the create form, I would need a session flash notification.

The instant notification banner I make like so:

  1. In my default app layout, I insert the livewire component:
@stack('modals')
@livewire('components.notification-manager')

Then my component is like:

This way I can have multiple notifications stack on each other, I can give custom timeouts, I set the type, etc

Now from anywhere in the Livewire Component I can call:

$this->dispatch('show-banner', message: 'Success message' , type: 1);

And this will make the notification appear The frontend:

<div class="w-full fixed mx-auto top-2 right-4 flex flex-col space-y-2" style="z-index: 9999 !important;">
    @foreach ($banners as $banner)
        <div wire:key="banner-{{ $banner['key'] }}" x-data="{ show: true }" x-init="setTimeout(() => show = false, {{ $banner['timeout'] }})" x-show="show"
             x-on:click="show = false"
...

You can use alpineJs to make it appear from top with smooth transitions and animations and you also need to display the $banner['message']

And depending on type I give it a different background color.

With session banner just make a blade component: , put it in your app layout, or the main html file you want it to be used, and have the html like so:

@props(['style' => session('flash.bannerStyle', 'success'), 'message' => session('flash.banner')])

<div x-data="{{ json_encode(['show' => true, 'style' => $style, 'message' => $message]) }}"
    :class="{ 'bg-green-500': style == 'success', 'bg-red-700': style == 'danger', 'bg-yellow-500': style == 'warning', 'bg-gray-500': style != 'success' && style != 'danger' && style != 'warning'}"
            style="display: none;"
            x-show="show && message"
            x-on:banner-message.window="
                style = event.detail.style;
                message = event.detail.message;
                show = true;
            ">
...

Remember to use x-text="message" to display the message in a <p> or something, and don't forget the x-on:click="show = false" so that the notification can be closed.

Now anywhere in your livewire components you can do:

return redirect()->route('route.name')
				->with('flash.banner', $message)
				->with('flash.bannerStyle', 'success');

And when you return, the banner will pop out. I dont have full code for you, because mine has a lot more code in it and It took me a long time to figure it out. Im giving you an idea and more than a start to learn how the notifications should work