Laravel Livewire 'wire:click' not functioning on Table Component

54 views Asked by At

I am building a base layout for listing the records using Laravel Livewire.

<div class="card shadow" x-data="{ table:@entangle('table').live }">
    <div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
        <div class="m-0 font-weight-bold text-primary">Details</div>
        <div class="dropdown no-arrow">
            <a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                <i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
            </a>
            <div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink">
                <template x-for="column in table.columns">
                    <div class="dropdown-item form-group">
                        <div class="custom-control custom-checkbox" x-id="['checkbox']">
                            <input :id="$id('checkbox')" class="custom-control-input" type="checkbox" x-model="table.columns.find(x => x.label === column.label).visible">
                            <label class="custom-control-label" :for="$id('checkbox')" x-text="column.label"></label>
                        </div>
                    </div>
                </template>
            </div>
        </div>
    </div>
    <div class="card-body">   
        <div class="table-responsive">
            <table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
                <thead>
                    <tr>
                        @foreach ($table->columns as $column)
                            <th x-show="table.columns.find(x => x.label == `{{ $column['label'] }}`).visible" data-orderable="true">{{ $column['label'] }}</th>
                        @endforeach
                    </tr>
                </thead>
                <tbody>
                    @forelse ($data as $collection)
                        <tr>
                            @foreach ($table->columns as $row)                             
                                <td class="align-middle" x-show="table.columns.find(x => x.label == `{{ $row['label'] }}`).visible">
                                    @if (is_array($row['options']))
                                        @isset($row['options']['_action'])

                                            {{-- Blade Component: Table Action --}}

                                        @endisset

                                        {{-- Some code... --}}

                                    @else

                                        {{-- Display data here.... --}}

                                    @endif
                                </td>
                            @endforeach
                        </tr>
                    @empty
                    @endforelse
                </tbody>
            </table>
        </div>
    </div>
</div>

table-action.blade.php

<div class="d-flex align-content-center flex-wrap" role="group" aria-label="Basic example">
    @foreach ($row['options']['_action'] as $action)
        @php
            $tag = isset($action['href']) ? 'a' : 'button';

            $classes = [
                'm-1 btn btn-sm',
                'btn-icon-split' => $action['icon'] ?? false,
                'btn-primary' => $action['color'] === 'primary',
                'btn-danger' => $action['color'] === 'danger',
                'btn-success' => $action['color'] === 'success',
            ];
        @endphp
        @if(!isset($action['can']) || Gate::allows($action['can'], $collection))
            <{{ $tag }} {{ (new \Illuminate\View\ComponentAttributeBag($action))->class($classes)->except(['can', 'color', 'icon', 'label']) }}>
                @isset($action['icon'])
                    <span class="icon"><i class="fas fa-sm {{ $action['icon'] }}"></i></span>
                @endisset
                @isset($action['label'])
                    <span class="text">{{ $action['label'] }}</span>
                @endisset
            </{{ $tag }}>
        @endif
    @endforeach
</div>

Assuming the array for $row['options']['_action']:

$options = [
    '_action' => [
        [
            "label" => "Edit",
            "can" => "update",
            "icon" => "fa-edit",
            "color" => "primary",
            "href" => route('example.edit', [ 'record' => '_data:id' ]),
        ],

        [
            "label" => "Delete",
            "can" => "delete",
            "icon" => "fa-trash",
            "color" => "danger",
            "type" => "button",
            "wire:click" => "delete(_data:id)",
            "wire:confirm" => "Are you sure you want to delete this record?"
        ]
    ],
];

Here, _data:id is equivalent to $collection->id which is handled separately on the loop statement above.

Now, when I click the action button, wire:click and wire:confirm are both not working.

Let's demonstrate my issue in the short:

Button:

<button type="button" wire:click="test()" wire:confirm="Are you sure?" x-bind:click="console.log('Button clicked!')">Button</button>

Table:

<div>
    {{-- Working here. --}}
    <table>
        {{-- Working here. --}}
        <tbody>
            {{-- Working here. --}}
            <tr>
                {{-- Working here. --}}
                <td>
                    {{-- Not working here... --}}
                </td>
            </tr>
        </tbody>
    </table>
</div>

Even, alpine x-bind:click="console.log('Button clicked!')" is running before the button is clicked. Also, I tried moving the Blade component to the Livewire component but my issues were not resolved.

Could anyone identify the issue I'm currently encountering?

UPDATE:

After removing id="dataTable" attribute from the table, I figured out the issue, which is Bootstrap DataTables with jQuery. It seems that DataTables only allows inline event handling via onclick attribute, which complicates integration with Livewire/Alpine Directives like wire:click and wire:confirm. I've implemented the following solution as a temporary workaround.

Instead of:

[
    "wire:click" => "delete(_data:id)",
    "wire:confirm" => "Are you sure?"
]

Add:

[
    "onclick" => "confirm('Are you sure?') && Livewire.find('" . $this->getId() . "').delete('_data:id')",
]

However, I am looking for more options or best practices to address this issue more effectively.

0

There are 0 answers