4

I've made a multiple file-upload component using Laravel Livewire. After the upload is complete I want to display the uploaded files without reloading the page, like so:

<div class="grid grid-flow-col auto-cols-max gap-4 mb-5">
    @foreach ($files as $file)
        <livewire:file :file="$file"/>
    @endforeach
</div>

Uploading one or multiple files at once works fine. But while uploading when there are already files present in the loop, Livewire throws this error: Uncaught (in promise) TypeError: Cannot read properties of null (reading 'fingerprint').

After doing some research I came to the conclusion that this is caused because Livewire generates the same id as the first file:

<div class="grid grid-flow-col auto-cols-max gap-4 mb-5">               
    <div wire:id="eCHZ9wxyp7nxOC4o5uCC" class="file file-jpeg file-lg">
        <!-- content of existing file component -->
    </div>
                     
    <div wire:id="eCHZ9wxyp7nxOC4o5uCC" class="file file-jpeg file-lg">
        <!-- content of new file component, should have Unique wire:id -->
    </div>        
</div>

How to fix this issue?

Dirk Jan
  • 2,355
  • 3
  • 20
  • 38

3 Answers3

10

This issue first occurred in september 2020 and was dissolved (reference: https://github.com/livewire/livewire/issues/1686). The error occurred because the new file is not unique to the existing file. The solution mentioned on Github works but is outdated.

If you are on Laravel 7 or above, you can add :wire:key="$yourUniqueKey" to the livewire component inside the loop:

<div class="grid grid-flow-col auto-cols-max gap-4 mb-5">
    @foreach ($files as $file)
        <livewire:file :file="$file" :wire:key="$file->id"/>
    @endforeach
</div>

Reference: https://laravel-livewire.com/docs/2.x/nesting-components

Also check https://laravel-livewire.com/docs/2.x/troubleshooting#dom-diffing-issues, specifically this part:

The value you pass to wire:key must be entirely unique to that page. Meaning that you should prefix it, like wire:key="item-{{ $item->id }}", and avoid using $loop->index to track the individual elements where you can.

Dirk Jan
  • 2,355
  • 3
  • 20
  • 38
1

I solved the issue by passing time in the key variable

<div class="grid grid-flow-col auto-cols-max gap-4 mb-5">
    @foreach ($files as $file)
        <livewire:file :file="$file" :wire:key="time().$file->id"/>
    @endforeach
</div>
0

I have the same problem with multiple components and solve this adding strings to key id, in my case:

@foreach ($data1s as $data)

<livewire:data1 :data="$data" :wire:key="'data1'.$data->id"/>

@endforeach

@foreach ($data2s as $data)

<livewire:data2 :data="$data" :wire:key="'data2'.$data->id"/>

@endforeach