I have a list of tasks that are each editable and have an image upload component. but if i upload an image in any of the components that aren’t the first in the list it still renders in the first component. Also i use the spatie mediaLibrary for my image uploads.
livewire components:
ShiftShow
<?php
namespace AppHttpLivewireAppShift;
use AppModelsCompany;
use AppModelsShift;
use LivewireComponent;
class ShiftShow extends Component
{
public Shift $shift;
public Company $company;
public $tasks;
public $return_link;
protected $listeners = ['pullTasks', 'refreshComponent' => '$refresh'];
public function mount()
{
$this->company = $this->shift->company;
$this->return_link = route('company.dashboard');
}
public function pullTasks()
{
$this->tasks = $this->shift->tasks()->get();
}
public function render()
{
$this->pullTasks();
return view('livewire.app.shift.shift-show')->layout('layouts.app', ['company' => $this->company, 'title' => 'Dienst']);
}
}
TaskItem
<?php
namespace AppHttpLivewireAppShift;
use AppEnumsTaskStatusEnum;
use AppModelsTask;
use AppTraitsTimetrait;
use LivewireComponent;
use LivewireWithFileUploads;
class TaskItem extends Component
{
use Timetrait, WithFileUploads;
public Task $task;
public $description;
public $status_item;
public $task_status;
public $status;
public $active;
public $file;
public $associated_file;
public function mount()
{
$this->active = $this->checkIfCurrent($this->task->shift);
$this->status_item = TaskStatusEnum::getValues();
$this->description = $this->task->description;
$this->task_status = $this->task->status;
$this->associated_file = $this->task->getMedia();
}
public function save()
{
$this->task->update([
'description' => $this->description,
'status' => $this->task_status,
'finished_at' => now(),
]);
if(!is_null($this->file))
{
$this->task
->addMedia($this->file)
->toMediaCollection();
$this->file = null;
$this->associated_file = $this->task->getMedia();
}
$this->emit('pullTasks');
$this->emit('refreshComponent');
}
public function render()
{
$this->status = $this->task->status;
return view('livewire.app.shift.task-item');
}
}
corresponding blade components
shiftshow blade
<div>
<a href="{{route('company.dashboard')}}" type="button" >
<div class="inline-flex lg:ml-7 mb-2 rounded-full bg-indigo-600 dark:bg-gray-500 p-2 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
</svg>
</div>
</a>
<x-base-container return_link="$return_link" >
<div class="border-b border-gray-200 bg-white dark:bg-gray-900 px-4 py-5 sm:px-6">
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">{{$shift->title}}</h3>
</div>
<ul role="list" class="divide-y divide-white/5">
@foreach($tasks as $i => $task)
<livewire:app.shift.task-item wire:key="task-{{$task->id}}" :task="$task">
@endforeach
</ul>
</x-base-container>
</div>
taskitem blade
<div x-data="{expanded: false}" x-on:click.outside="expanded == true ? expanded = false : expanded = false">
<li class="relative flex items-center space-x-4 py-4">
<div class="min-w-0 flex-auto" >
<div class="flex items-center gap-x-3" @if($active) x-on:click="expanded = ! expanded" @endif>
<div class="flex-none rounded-full p-1 {{$status === 'not_done' ?
'text-gray-500 bg-gray-100/10' : ($status === 'done' ? 'text-green-500 bg-green-100/10' : 'text-red-500 bg-red-100/10')}}">
<div class="h-2 w-2 rounded-full bg-current"></div>
</div>
<h2 class="min-w-0 text-sm font-semibold leading-6 dark:text-white">
<div class="flex gap-x-2">
<span class="truncate">{{$task->title}}</span>
</div>
</h2>
<div class="ml-auto" >
<svg x-show="expanded" class="h-5 w-5 flex-none text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 15.75l7.5-7.5 7.5 7.5" />
</svg>
<svg x-show="!expanded" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-5 w-5 flex-none text-gray-400">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
</svg>
</div>
</div>
</div>
</li>
@if($active)
<div class="lg:flex lg:flex-col" x-show="expanded" wire:key='task_item-{{$task->id}}'>
<div class="mr-auto mb-5">
<label for="location" class="block text-sm font-medium leading-6 dark:text-white text-gray-900">Status</label>
<select id="location" wire:model="task_status" name="location" class="mt-2 block w-full rounded-md border-0 py-1.5 pl-3 pr-10 dark:text-white dark:bg-gray-800 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-indigo-600 sm:text-sm sm:leading-6">
@foreach($status_item as $item)
<option value="{{$item}}">{{__('status.task.'.$item)}}</option>
@endforeach
</select>
</div>
<textarea wire:model='description' placeholder="Bijzonderdheden" name="" id="" cols="30" rows="10" class="dark:bg-gray-800 text-white resize-none w-full lg:w-64"></textarea>
@if(count($associated_file) == 0)
<label for="picture" class="px-4 py-2 dark:bg-gray-700 bg-gray-200 mr-auto rounded-md mt-2 flex w-fit">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 mr-2">
<path stroke-linecap="round" stroke-linejoin="round" d="M6.827 6.175A2.31 2.31 0 015.186 7.23c-.38.054-.757.112-1.134.175C2.999 7.58 2.25 8.507 2.25 9.574V18a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9.574c0-1.067-.75-1.994-1.802-2.169a47.865 47.865 0 00-1.134-.175 2.31 2.31 0 01-1.64-1.055l-.822-1.316a2.192 2.192 0 00-1.736-1.039 48.774 48.774 0 00-5.232 0 2.192 2.192 0 00-1.736 1.039l-.821 1.316z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 12.75a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zM18.75 10.5h.008v.008h-.008V10.5z" />
</svg>
Upload
</label>
@endif
<div wire:key='image_element-{{$task->id}}'>
@if($file)
<div class="flex">
<img src="{{ $file->temporaryUrl() }}" alt="" class="w-16 h-24 mt-2">
<span class="ml-2 mt-auto">{{$file->getFileName()}}</span>
</div>
@endif
@if(count($associated_file) > 0)
<div class="flex">
<img src="{{ $associated_file[0]->getUrl() }}" alt="" class="w-16 h-24 mt-2">
</div>
@endif
<input type="file" name="picture" id="picture" accept="image/*" wire:model="file" class="hidden">
</div>
<x-primary-button class="mr-auto mt-5 mb-2" wire:click="save" x-on:click="expanded = false">Opslaan</x-primary-button>
</div>
@endif
</div>
I tried adding extra wire keys to each component to try and force the image to show in the correct component but it still only renders in the first.
2
Answers
Problem is fixed after alot of searching i found that i needed to add
id="{{'picture-'.$task->id}}"
to the input the same to the label for to make this implementation work.you forget to add ":"