Can I fire $refresh from a Component method

I am deleting a model from a list. The list is provided to the livewire view through a computed property. When I run the killCo($id) function, the database IS updated but the item is not removed immediately from the list which gives the user a false indication that nothing happened. Of course, on a page refresh, the item is gone.

I am thinking that perhaps I could trigger the $refresh() helper after the delete but can’t find in the docs how to call that from the components.

Any help or ideas is appreciated.

Without more code it is difficult to see what is going wrong. You could look at the hydrate-method. Or maybe update or re-fetch the list after you delete an item?

Sorry for the delay but I was called out of town for bereavement.

I am SURE that I am doing this wrong and look forward to learning the right way.

I have a modal in a staff directory which allows the current user to set his/her status or current phone

@modal(['name' => 'quickset-modal'])
<form wire:submit.prevent="saveQuick">
    <div class="flex flex-col mb-4">
        <label class="tw-label" for="status">
            Status
        </label>
        <select id="status" name="status" class="tw-select"
                wire:model="status">
            <option value=''>Choose a status</option>
            <option value='available'>Available</option>
            <option value='away'>Away</option>
            <option value='dnd'>Do Not Disturb</option>
            <option value='out'>Out of Office</option>
        </select>
    </div>

    <div class="flex flex-col mb-4">
        <label class="tw-label" for="extension">
            Extension/Phone
        </label>
        <input id="extension" type="text" class="tw-input"
               wire:model="extension">
    </div>

    <div class="flex justify-center">
        <button type="submit"
                class="tw-button bg-blue-500 text-white hover:bg-blue-800">
            SAVE
        </button>
    </div>
</form>
@endmodal

Here’s my component

<?php

namespace App\Http\Livewire\Staff;

use App\User;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;

class CurrentStatus extends Component
{
    public $extension;
    public $status;

    public function mount()
    {
        $this->extension = Auth::user()->extension;
        $this->status = Auth::user()->status;
    }

    public function saveQuick()
    {
        $user = User::whereId(Auth::user()->id)->first();
        $user->extension = $this->extension;
        $user->status = $this->status;
        $user->save();

        $this->extension = $user->extension;
        $this->status = $user->status;

        $this->redirect('#');
    } // end function

    public function render()
    {
        return view('_livewire.staff.current-status');
    }
}

When the modal closes, the values are still the original values and don’t show the change until a page refresh. I am trying to figure out how to trigger that refresh.

I’m assuming that you mean the values on the page that has the modal isn’t updating, so this answer is for that.

Livewire is only controlling the modal, it’s not (at least in this component) controlling the rest of the page outside of the modal. So you are updating the user model in the database, but the page itself has no idea the database changed without getting that new information.

If the info you want updated outside of the modal isn’t already a livewire component, you can make it one, and have the modal tell it to refresh through events.

In your quickSave() method, add $this->emit('staffDirectoryRefresh');
Then in your other component register a listener that triggers the render method.
public $listeners = ['staffDirectoryRefresh' => 'render'] I don’t know if there’s a way built in to trigger a refresh on another component. If there is, I don’t know it, and this is how I did it.

Outside of your question and to make your life a little easier in the future, this line $user = User::whereId(Auth::user()->id)->first(); can be changed to $user = Auth::user() No need for an extra database call, Auth::user() already contains the user model you are asking for. Also you can take out $this->redirect('#');, it’s not serving you any purpose.

2 Likes

I am using a CSS only modal where the id of the modal is added at the end of the URL and only closes when that id is removed. That redirect removes the #quick_editor_modal from the URL

I am working on adding an emit as well … thanks

I changed my CurrentStatus component to this

<?php

namespace App\Http\Livewire\Staff;

use Illuminate\Support\Facades\Auth;
use Livewire\Component;

class CurrentStatus extends Component
{
    public function saveQuick()
    {
        Auth::user()->extension = $this->extension;
        Auth::user()->status = $this->status;
        Auth::user()->save();

        $this->redirect('#');
    } // end function

    public function render()
    {
        return view('_livewire.staff.current-status');
    }
}

It is called within another component

class="cursor-pointer text-silver-500"
    wire:click="clear"></font-awesome-icon>
</div>
{{-- CURRENT STATUS --}}
@livewire('current-status')
</div>

<div>
<div class="overflow-auto"
 style="padding-top: 250px;">
@foreach($users as $user)

When the modal closes, the CurrentStatus component still shows the old values until the page is refreshed. Since it is part of the component, do I still need an $emit???

Yeah. Even though it’s nested within another component, it’s still only updating itself and not the one it’s nested in. The parent component still needs something to trigger it to ask the server to rerender it. Depending on where in your code you are setting the $users variable determines what the listener should trigger.

I triggered refresh by modifying a variable in the component. Like I did on my Vue.js components. For example:

public $update; 

public function refreshComponent() {
    $this->update = !$this->update;
}

a call to refreshComponent will trigger a refresh on the component having this code.

1 Like

That works if you are doing it within the component, in which case you can just call $refresh in place of refreshComponent() and not need an extra property and method on every component.

If you want the method to be there, it can be left blank and no need for the extra property. Any call to a method is still going to have the component go through it’s request life cycle and re-render. That’s actually how $refresh works, it returns out of a method call without the method doing anything before it would normally check to see if the method you called exists.

this worked for me thanks

emit worked a treat for me - here a year on :slight_smile:

1 Like

I’m also wondering this, as i have the same problem with OP. I think a method like $this->refresh() is useful for this case, as we can trigger event from child component and let the parent listen and then refresh itself properly. But the trick with render is working here