rappasoft / laravel-livewire-tables

A dynamic table component for Laravel Livewire
https://rappasoft.com/docs/laravel-livewire-tables/v2/introduction
MIT License
1.74k stars 330 forks source link

[Bug]: "Uncaught Snapshot missing on Livewire component with id" on Mutate #1328

Closed AleAtSoftplace closed 1 year ago

AleAtSoftplace commented 1 year ago

What happened?

Hello everyone, I'm testing the dev-v3-master branch with Livewire 3, and I'm getting " Uncaught Snapshot missing on Livewire component with id" when Livewire mutates the page, crashing Livewire and forcing me to refresh the application page to make it work.

The full stack trace is the following: ` Uncaught Snapshot missing on Livewire component with id: hcMFVHZKwhk7elwW8KtM livewire.esm.js:1634:9 onMutate http://localhost:5173/vendor/livewire/livewire/dist/livewire.esm.js:1634 (Async: MutationCallback) js http://localhost:5173/vendor/livewire/livewire/dist/livewire.esm.js:1524 __require http://localhost:5173/vendor/livewire/livewire/dist/livewire.esm.js:8

http://localhost:5173/vendor/livewire/livewire/dist/livewire.esm.js:6075 ` From what I observed, the Div with the wire:id loses all the attributes expect for the wire:id of the component. BEFORE onMutate CALL ![before-mutate](https://github.com/rappasoft/laravel-livewire-tables/assets/118259009/f70811cd-4beb-4df6-a557-eddcea43aab6) AFTER onMutate CALL (exception gets thrown) ![after-mutate](https://github.com/rappasoft/laravel-livewire-tables/assets/118259009/69b87123-9956-4882-999b-8059ee04d7f7) ### How to reproduce the bug Render a datatable and trigger a Livewire mutation, even from other components ### Package Version dev-v3-master 4250511 ### PHP Version 8.1.x ### Laravel Version 10.21 ### Alpine Version 3.1.12, bundled with Livewire 3 ### Theme Tailwind 3.x ### Notes Full code of the Component: ``` class ShowList extends DataTableComponent { protected $model = Board::class; public function configure(): void { $this->setPrimaryKey('id'); $this->setDefaultSort('id', 'desc'); $this->setThAttributes(function (Column $column) { return ['class' => 'text-white']; }); // Takes a callback that gives you the current column. $this->setThSortButtonAttributes(function (Column $column) { return ['class' => 'text-white']; }); } public function columns(): array { return [ Column::make('ID', 'id') ->sortable(), Column::make('Nome', 'name') ->sortable(), Column::make('X', 'xSize') ->sortable(), Column::make('Y', 'ySize') ->sortable(), ComponentColumn::make('Edit', 'id') ->component('board.dt-edit') ->attributes(fn ($value, $row, Column $column) => [ 'id' => $value, ]), ]; } public function deleteBoard(Board $board): void { $this->dispatch('closeTab', tabName: "board.create_$board->id"); $this->dispatch('closeTab', tabName: "question.show-list_$board->id"); $this->dispatch('closeTab', tabName: "question.special-cells_$board->id"); $this->dispatch('closeTab', tabName: "question.preview_$board->id"); $board->delete(); } } ``` ### Error Message Uncaught Snapshot missing on Livewire component with id: 6dFukQtQSEvItPQ0z9mQ [livewire.esm.js:1634:9](http://localhost:5173/vendor/livewire/livewire/dist/livewire.esm.js) onMutate http://localhost:5173/vendor/livewire/livewire/dist/livewire.esm.js:1634 (Async: MutationCallback) js http://localhost:5173/vendor/livewire/livewire/dist/livewire.esm.js:1524 __require http://localhost:5173/vendor/livewire/livewire/dist/livewire.esm.js:8 http://localhost:5173/vendor/livewire/livewire/dist/livewire.esm.js:6075
lrljoe commented 1 year ago

How are you including the Livewire scripts please?

Did you previously publish the views for this package?

Looking at the "before" code, some elements appear to be missing.

AleAtSoftplace commented 1 year ago

How are you including the Livewire scripts please?

I am using the manual bundling mode with Vite. I am following the recommended setup in the second part of the paragraph, my code is exactly the same

Did you previously publish the views for this package?

I don't remember, but as of now they're not published.

Looking at the "before" code, some elements appear to be missing.

This is the full code of the table. Also note there are some empty blocks being put by Livewire https://pastebin.com/5xEXfnFK

lrljoe commented 1 year ago

In your view/blade, can you try wrapping the table component with a div with a wire:key

Is it after any lifecycle event (e.g. reorder the table)?

Does it happen if you aren't using the Vite dev server?

Just trying to narrow down my debugging etc!

AleAtSoftplace commented 1 year ago

In your view/blade, can you try wrapping the table component with a div with a wire:key

This is the setup. The father component renders many child component, and some of them are the Datatables.

@foreach($openTabs as $tab)
    <div x-show="'{{$tab}}' === activeTabName"
            wire:key="xShow-{{$tab}}"
    >
        <div wire:key="{{ $tab }}-wrapper">
            <livewire:dynamic-component  wire:key="tab-{{ $tab }}"
                            :is="(preg_replace('/_\d+/', '', $tab))"
                            :params="$this->getParams($tab)"
            />
        </div>
    </div>
@endforeach

Is it after any lifecycle event (e.g. reorder the table)?

After any Livewire event that triggers a Livewire refresh/render, even from a father component.

Does it happen if you aren't using the Vite dev server?

Just tested, yes. Also keep in mind that the setup with Livewire 2 and the latest release of the Datatables v2 was perfectly working. But to me it seems something that has to do with DOM-diffing or how re-renders are managed, Livewire is working perfectly in all the other views.

Also I'll be joining the Discord, so if you prefer I can jump in when I see you online :)

lrljoe commented 1 year ago

One key element that differs to v2 is that v3 injects some JS and CSS for the Alpine functions in use.

It doesn't seem that this is the issue however!

However! I did notice that your table is called table. Are all of them called table? The table name is used as a prefix for the wire key in numerous places, including the table itself.

I can see a wire:key='table-table' in your code dump, if they're all the same then Livewire will get grumpy!

If you add

public string $tableName = 'somethingUnique'

Or pass a unique tableName in as a parameter, does that sort it?

Otherwise I'll be on discord probably later today.

AleAtSoftplace commented 1 year ago

I can see a wire:key='table-table' in your code dump,

I don't know if it can help but the error I'm getting is in Javascript console, I'm not getting an Ignition page, so the error is in the frontend.

if they're all the same then Livewire will get grumpy!

It is the only table being shown in the project atm, despite that I changed the property you told me about but nothing changed. As of now, the wire:snapshot is showing "tableName":"boardShowList"

lrljoe commented 1 year ago

1) Has the wire:key also updated? Can you share an updated version of: image

2) Please can you also add the following to your table component:

    public array $boardShowList =[];

3) In the generated HTML in the head do you see

<head><!-- Rappasoft Table Styles -->
<link href="/rappasoft/laravel-livewire-tables/core.min.css" rel="stylesheet" />

and

<script  src="/rappasoft/laravel-livewire-tables/core.min.js"   ></script>
 </head>

4) Where is your app.js in relation to that?

5) Are you able to share your app.js?

I'm trying to rule out anything else that it could possibly be! But I'll be on Discord later no doubt!

AleAtSoftplace commented 1 year ago
  1. Has the wire:key also updated? Can you share an updated version of:

Yes, it has. wire:id keeps being a random string every time, but I'm guessing it's normal. Screenshot at 2023-09-01 17-05-22

2. Please can you also add the following to your table component:

Done, still nothing.

3. In the generated HTML in the head do you see

Yes, styles and JS files are being included. Full path is localhost/rappasoft/laravel-livewire-tables/core.min.js and localhost/rappasoft/laravel-livewire-tables/core.min.css

4. Where is your app.js in relation to that?

My app is just in http://localhost:80. Vite dev server in http://localhost:5173/

5. Are you able to share your app.js?

Sure. it's mostly importing plugins and assigning them.

import {Livewire, Alpine} from '../../vendor/livewire/livewire/dist/livewire.esm';

import * as te from 'tw-elements';
import {DataTable} from "simple-datatables"
import Sortable from 'sortablejs';
import SignaturePad from "signature_pad";
import flatpickr from "flatpickr";
import ApexCharts from 'apexcharts'
import sa2 from "sweetalert2"
import {FileUploadWithPreview} from 'file-upload-with-preview';
import Picker from 'vanilla-picker/csp';
import EasyMDE from "easymde";
import Swiper from "swiper"
import Pickr from '@simonwep/pickr';

/*window.Alpine = Alpine;
Alpine.plugin(yourCustomPlugin);*/
Livewire.start();

window.te = te;

window.DataTable = DataTable;

window.Sortable = Sortable;

window.SignaturePad = SignaturePad;

window.flatpickr = flatpickr;

window.FileUploadWithPreview = FileUploadWithPreview;

window.EasyMDE = EasyMDE;

window.Pickr = Pickr;

/*window.NiceSelect = ns.NiceSelect;*/
window.ApexCharts = ApexCharts;
window.sa2 = sa2;
window.Picker = Picker;
window.Swiper = Swiper;

I'm trying to rule out anything else that it could possibly be! But I'll be on Discord later no doubt!

I joined, I can't find any voice channel tho, am I missing something?

lrljoe commented 1 year ago

Can you share:

1) The name of the tab from the parent component 2) The current code of your Table Component.

Definitely seems that there's some wire:key clash or similar going on here, as Livewire is losing track of the component.

If you can share the resultant HTML of the first load (attach the page source as a file please), then I will be able to tell better!

AleAtSoftplace commented 1 year ago

I'm attaching the full page both before and after the mutation and the Datatable code plus the tab-swapper blade file. datatable_bug.zip

The parent component is called "tab-swapper".

I am gonna refer to some lines of the "before" file so you can understand better.

Tab-swapper starts at line 1033. For each open tab, an Alpine div gets rendered (for some animations, line 1073) and inside it the tag is invoked to render dinamically Livewire components (the datatable is getting rendered at line 1075) An event from both the Datatable or the TabSwapper parent component will cause the bug.

lrljoe commented 1 year ago

Is that the actual code for tab-swapper.blade.php?

If so, you'll have a variety of issues with how Livewire v3 behaves and your JS code, and that does explain the issue(s) you're having. Plus having a 15,000 line generated HTML is going to cause Livewire some pain in tracking anything!

The following will solve the immediate problem

Effectively, your JS code to set the Active Tab won't be running properly, therefore won't entangle correctly, and you'll end up with it not being able to find the component(s).

The rest is definitely beyond the scale of an issue here to be honest. If you jump on Discord then I'll give you a few pointers where I reasonably can, but also

lrljoe commented 1 year ago

To be honest, I'd probably remove your current tabs implementation, and use one of the existing components.

It's definitely related to how your Tabs are working.

I'm happy to recommend on Discord, but I'm not going to start cross-linking repos here.