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

bvfi-dev's avatar

bvfi-dev was awarded Best Answer+1000 XP

6mos ago

Collapsing a
section is laggy only in the initialization

I updated the child Blade component root to have:

<div wire:key="edit-course-form-root" class="grid grid-cols-1 gap-6"
		x-data="{
			statusId: $wire.entangle('courseForm.status_id'),
			ztComing: {{ (int) $ztCourseComingSoon }},
			hydrated: false,
			isComingSoon(){ return Number(this.statusId) === this.ztComing; }
		}" x-init="$nextTick(() => { hydrated = true })">

And then changed the Coming Soon section to have:

<div x-cloak x-show="hydrated && isComingSoon()"

Now when the Model has status Coming soon and I load the page, the Coming Soon section appears smoothly with animation, but changing it to Active still does the same, so Im thinking it has something to do with changing the Status for the first time. What I did was remove the .live from the select in the section when Coming Soon was active and that fixed the issue...Im not sure why .live would cause it to behave that way. I technically dont need the live for the edit form, but I need it for my create form.

bvfi-dev's avatar

bvfi-dev started a new conversation+100 XP

6mos ago

Reply doesn't appear

I replied to my own post about a significant update and I am unable to see what I have written, eventhough its mentioned that I have done it on the "Forums" frontpage. The related post is: Post

When I am in the post it says "2 Replies", however on the frontpage it says 3, which is correct if my Reply is included.

bvfi-dev's avatar

bvfi-dev wrote a reply+100 XP

6mos ago

Collapsing a
section is laggy only in the initialization

I updated the child Blade component root to have:

<div wire:key="edit-course-form-root" class="grid grid-cols-1 gap-6"
		x-data="{
			statusId: $wire.entangle('courseForm.status_id'),
			ztComing: {{ (int) $ztCourseComingSoon }},
			hydrated: false,
			isComingSoon(){ return Number(this.statusId) === this.ztComing; }
		}" x-init="$nextTick(() => { hydrated = true })">

And then changed the Coming Soon section to have:

<div x-cloak x-show="hydrated && isComingSoon()"

Now when the Model has status Coming soon and I load the page, the Coming Soon section appears smoothly with animation, but changing it to Active still does the same, so Im thinking it has something to do with changing the Status for the first time. What I did was remove the .live from the select in the section when Coming Soon was active and that fixed the issue...Im not sure why .live would cause it to behave that way. I technically dont need the live for the edit form, but I need it for my create form.

bvfi-dev's avatar

bvfi-dev wrote a reply+100 XP

6mos ago

Collapsing a
section is laggy only in the initialization

I use last Laravel 11 version, Livewire 3 installed with Jetstream 5. But this shouldn't influence the AlpineJS. I noticed that it kind of starts smooth, but then suddenly instantly opens down. I uploaded a video, at 0:15 I refresh the page:

Streamable URL

I cant figure out why it happens consistently only on the first try on the page, how can I even debug this, its literally just JS harmonicas.