Learn Laravel Livewire Lifecycle Hooks with Example

A Life Cycle of application includes various changes the application has to go through in order to be completed. The Laravel Livewire provides 6 types of Life Cycle Hook methods so that developer can make use of these methods for various reason such as control DOM update when the value of property changes, Show a message to the client when some lengthy task is being performed, set or unset properties etc.

The Six Life Cycle Hook methods are:

  • mount: This is the first hook method to be executed and runs before the render() a method is called.
  • hydrate: Executes on every request to the server and before any changes to be performed such as updating, saving or any other action.
  • updating: Triggers before when any of the properties are to be updated.
  • updated: Triggers after component property updated.
  • updatingFoo: Executes before the property $foo is to be updated. Example: for property, $employee_name the method name will be updatingEmployeeName().
  • updatedFoo: Executes after the property $foo is to be updated. Example: for property, $employee_name the method name will be updatedEmployeeName().
Flowchart of Laravel Liveiwre Life Cycle Hooks
Flowchart of Laravel Livewire Life Cycle Hooks

In 6 Life Cycle Hook methods, there are 2 major hooks which are mount() and hydrate().

In this post, we’ll cover all the above hook methods by using an example of employees and through CRUD Operation you’ll learn how and at what instance the hook methods are triggered.
The trigger events are caught by a toaster notification which makes use clear to see which methods are being executed in the background.

Create Employee Model

Since our application does CRUD operation the data will be store in the MySQL database and below is the code for app\EmployeeModel.php.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;

class EmployeeModel extends Model
{
    protected $table="employees";
    protected $primaryKey = 'id';
    protected $fillable = ['employee_name', 'designation', 'salary'];
}
    

First, we’ll start with creating an EmployeesComponent by command php artisan make:livewire life-cycle-hook.employees-component.
When you run the command a new file EmployeesComponent is created at path app\Http\Livewire\LifeCycleHook\EmployeesComponent.php.

Here is the complete code of the EmployeesComponent.

<?php

namespace App\Http\Livewire\LifeCycleHook;

use App\EmployeeModel;
use Livewire\Component;
use Log;

class EmployeesComponent extends Component
{
    public $employees_list = [];
    public $life_cycle_info = [
        'hook' => "",
        'message' => "",
    ];

    public $employee_name = '';
    public $designation = '';
    public $salary = '';

    protected $listeners = [ 
        'load_employees' => 'loadEmployees',
        'remove_employee' => 'removeEmployee',
    ];

    public $component_id =  null;

    public $add_new_row =  false;
    
    public $new_employee_form =  [
        'employee_name' => '',
        'designation' => '',
        'salary' => '',
    ];

    public function mount(){
        $this->component_id = $this->id;

        $this->life_cycle_info['hook'] = "mount";
        $this->life_cycle_info['message'] = "Application is mounting...";

        
    }

    public function hydrate(){
        
        $this->emit('toastr-info', "Application is hydrating...");
        $this->emit('toastr-info', "Loading Employees...");

        $this->life_cycle_info['hook'] = "hydrate";
        $this->life_cycle_info['message'] = "Application is hydrating...";
        
    }

    public function saveForm(){
        try {
            EmployeeModel::create( $this->new_employee_form );

            foreach( $this->new_employee_form as &$item ){
                $item = '';
            }

            $this->emit('toastr-success', "New Employee created.");
            $this->add_new_row = false;

            $this->emit( 'load_employees' );

        } catch (\Throwable $th) {
            $this->emit('toastr-error', "Something went wrong.");
        }
    }

    public function loadEmployees(){
        $this->employees_list = EmployeeModel::orderBy('id', 'DESC')->get();
        $this->emit('toastr-success', "Loaded Employees.");
    }

    public function prepareForInlineEdit( $key, $id, $field ){
        $value = $this->employees_list[$key][$field];
        $this->employees_list[$key][$field] = '<input data-id='.$id.' data-key='.$key.' data-field=' . $field . ' type="text" wire:blur="$emit('field_value_changed')" value="'. $value . '" > ';
    }    

    public function removeEmployee( $key ){
        $this->employees_list[$key]->delete();
        unset( $this->employees_list[$key] );

        $this->emit('toastr-success', "Employee removed.");
    }    

    public function updatingEmployeeName( $value ){

        $this->emit('toastr-info', "Updating Employee Name.");

        $this->life_cycle_info['hook'] = "Updating";
        $this->life_cycle_info['message'] = "Employee Name";

        Log::info("Updating Employee Name");
    }

    public function updatedEmployeeName( $value ){
        $this->emit('toastr-success', "Updated Employee Name.");

        $this->life_cycle_info['hook'] = "Updated";
        $this->life_cycle_info['message'] = "Employee Name";

        $this->employees_list[ $value['key'] ]->employee_name = $value['value'];
        $this->employees_list[ $value['key'] ]->save();

        Log::info("Updated Employee Name");
    }
    
    public function updatingDesignation( $value ){
        $this->emit('toastr-info', "Updating Designation.");

        $this->life_cycle_info['hook'] = "Updating";
        $this->life_cycle_info['message'] = "Designation";

        Log::info("Updating Designation");
    }

    public function updatedDesignation( $value ){
        $this->emit('toastr-success', "Updated Designation.");

        $this->life_cycle_info['hook'] = "Updated";
        $this->life_cycle_info['message'] = "Designation";

        $this->employees_list[ $value['key'] ]->designation = $value['value'];
        $this->employees_list[ $value['key'] ]->save();

        Log::info("Updated Designation");
    }

    
    public function updatingSalary( $value ){
        $this->emit('toastr-info', "Updating Salary.");

        $this->life_cycle_info['hook'] = "Updating";
        $this->life_cycle_info['message'] = "Salary";

        Log::info("Updating Salary");
    }

    public function updatedSalary( $value ){
        $this->emit('toastr-success', "Updated Salary.");

        $this->life_cycle_info['hook'] = "Updated";
        $this->life_cycle_info['message'] = "Salary";

        $this->employees_list[ $value['key'] ]->salary = $value['value'];
        $this->employees_list[ $value['key'] ]->save();

        Log::info("Updated Salary");
    }

    public function render()
    {
        
        return view('livewire.life-cycle-hook.employees-list');
    }
}

Next is to create a template for EmployeesComponent at path resources\views\livewire\life-cycle-hook\employees-list.blade.php.

    <div class="container" >
    <h4>Employees List</h4>

    @if ( !empty( $life_cycle_info['hook'] ) )
        <div class="alert alert-info">
            <h4><strong>{{ $life_cycle_info['hook'] }}</strong>: {{ $life_cycle_info['message'] }}</h4>
        </div>        
    @endif

    <button type="button" class="btn btn-primary" style="margin-bottom: 5px;" wire:click="$set('add_new_row', true )" >Add New Employee</button>

    <table class="table table-bordered table-compact">
        <thead>
            <tr>
                <th>Sl.No</th>
                <th>Name</th>
                <th>Designation</th>
                <th>Salary</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>

            @if ( $add_new_row )
                    <tr>
                        <td>#</td>
                        <td> <input type="text" wire:model="new_employee_form.employee_name" value="" > </td>
                        <td> <input type="text" wire:model="new_employee_form.designation" value="" > </td>
                        <td> <input type="text" wire:model="new_employee_form.salary" value="" > </td>
                        <td>
                            <button type="button" wire:click="saveForm()" class="btn btn-success" >Save</button>
                            <button type="button" wire:click="$set('add_new_row', false )" class="btn btn-danger" >Remove</button>
                        </td>
                    </tr>
            @endif



            @if ( !empty( $employees_list ) )
                @foreach ( $employees_list  as $key => $employee )
                    <tr wire:key="{{ $loop->index }}" >
                        <td>{{ $loop->iteration }}</td>
                        <td> <span wire:click="prepareForInlineEdit( {{ $key }}, {{ $employee->id }}, 'employee_name' )" ><?php echo  $employee->employee_name; ?></span> </td>
                        <td> <span wire:click="prepareForInlineEdit( {{ $key }}, {{ $employee->id }}, 'designation' )" ><?php echo  $employee->designation; ?></span> </td>
                        <td> <span wire:click="prepareForInlineEdit( {{ $key }}, {{ $employee->id }}, 'salary' )" ><?php echo  $employee->salary; ?></span> </td>
                        <td>
                            <button type="button" wire:click="$emit('confirm_remove_employee', {{ $key }} )" class="btn btn-danger" >Delete</button>
                        </td>
                    </tr>
                @endforeach
            @endif
        </tbody>
    </table>
</div>

@push('scripts')
<script type="text/javascript">
    
    document.addEventListener("livewire:load", function(event) {
        window.livewire.emit('load_employees');


        window.livewire.hook('beforeDomUpdate', () => {
            window.livewire.emit('toastr-info', "DOM Updating....");
        });

        window.livewire.hook('afterDomUpdate', () => {
            window.livewire.emit('toastr-info', "DOM Updated.");
        });

    });

    window.livewire.on('field_value_changed', function () {
        
        let component = window.livewire.find( '{{ $component_id }}' );

        
        let element = event.target;
        let value = element.value;
        let key = element.dataset['key'];
        let id = element.dataset['id'];
        let field = element.dataset['field'];
        
        component.set(field, {
            'key' : key, 
            'id' : id, 
            "value" : value
        });
    });

    window.livewire.on( 'confirm_remove_employee', key => {
        
        let cfn = confirm("Confirm to remove ?");

        if( cfn ){
            window.livewire.emit('remove_employee', key ) 
        }

    } );


    window.livewire.on( 'toastr-success', message => toastr.success(message ) );

    window.livewire.on( 'toastr-info', message => toastr.info(message ) );
    
    window.livewire.on( 'toastr-error', message => toastr.error(message ) );

</script>
@endpush

When DOM loads the event window.livewire.emit('load_employees'); is triggered and the list of employees is loaded in DOM.

You can also use trigger javascript before and after the DOM update using the below snippet.

window.livewire.hook('beforeDomUpdate', () => {
    window.livewire.emit('toastr-info', "DOM Updating....");
});

window.livewire.hook('afterDomUpdate', () => {
    window.livewire.emit('toastr-info', "DOM Updated.");
});

The javascript event function field_value_changed is used to update the value of the individual columns. The field name which is passed as an argument and in component with method name updated event is emitted. That method will retrieve the object from $this->employees_list the array and updates the specific field and then saves it into the database.

I have also created toastr event for notification so that I can run javascript functions inside Livewire components.

window.livewire.on( 'toastr-success', message => toastr.success(message ) );

window.livewire.on( 'toastr-info', message => toastr.info(message ) );

window.livewire.on( 'toastr-error', message => toastr.error(message ) );

To run the above events in Livewire component use $this->emit( 'toastr-success', 'A Custom Message Here...' ).

Set Up route and base view

Since our application has a single view I’ll only specify a single route.

// Life Cycle Hook
Route::group(['prefix' => "employee"], function () {
        Route::get('/list', function() {
            return view('base', []);
        });
});

And the final step is to create a base.blade.php view at path resources\views\base.blade.php.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Laravel Livewire</title>
    @livewireStyles
    @livewireScripts
    <link rel="stylesheet" href="{{ url('assets/css/bootstrap.min.css') }}">
    <link rel="stylesheet" href="{{ url('assets/plugins/toastr/toastr.min.css') }}">

    @stack('styles')
</head> 
<body>
    @livewire('life-cycle-hook.employees-component') 
    
    @yield('content')

    <script src="{{ url('assets/js/jquery.min.js') }}" ></script>
    <script src="{{ url('assets/js/popper.min.js') }}" ></script>
    <script src="{{ url('assets/js/bootstrap.min.js') }}" ></script>
    <script src="{{ url('assets/plugins/toastr/toastr.min.js') }}" ></script>

    @stack('scripts')
</body>
</html>

Image Output

Final Output - Learn Laravel Livewire Life Cycle Hooks with Example
Final Output – Learn Laravel Livewire Life Cycle Hooks with Example

Video Output

Related Posts

Summary
Review Date
Reviewed Item
Learn Laravel Livewire Life Cycle Hooks with Example
Author Rating
51star1star1star1star1star
Software Name
Laravel Livewire
Software Name
Windows Os, Mac Os, Ubuntu Os
Software Category
Web Development