404 because you are still trying to show the deleted member?
Error 404 on parent when removing child in a loop using dispatch
Hello, i'm having a problem when deleting a child in a loop, I throw the dispatch to the parent to delete the item, but after deleting it, throws 404.
This is the [show-team.blade.php] which is the team card (the child component)
<?php
use function Livewire\Volt\{state, mount, computed, emit, refresh, on, uses};
use App\Actions\Jetstream\AddTeamMember;
use App\Events\TeamDeleted;
use App\Events\TeamMemberDeleted;
use App\Models\Brief;
use App\Models\User;
use App\Models\Team;
use Mary\Traits\Toast;
uses([Toast::class]);
state(['brief', 'isAdmin', 'crud', 'briefTimeHasFinished', 'editModal' => false]);
state(['team'])->reactive();
$sortedTeamMembers = computed(function () {
$teamMembers = $this->team->users()->get();
$teamMembers = $teamMembers->sortBy(function ($member) {
if ($member->pivot->role === 'owner') {
return [0, $member->first_name];
} elseif ($member->pivot->role === 'participant') {
return [1, $member->first_name];
} else {
return [2, $member->first_name];
}
});
return $teamMembers;
});
$addTeamMember = function () {
if (!$this->isOnAnyBriefTeam) {
$this->team->users()->attach(auth()->user()->id, ['role' => 'participant']);
$this->isOnAnyBriefTeam = true;
$this->dispatch('add-member');
}
};
$removeTeamMember = function ($userId) {
$teamUser = $this->team->users()->where('user_id', $userId)->first();
if ($teamUser->pivot->role !== 'owner') {
$this->team->users()->detach($userId);
$user = User::find($userId);
// event(new TeamMemberDeleted($this->team, $user));
$this->dispatch('remove-member');
}
};
$setNewOwner = function () {
$user = auth()->user();
$teamUser = $this->team
->users()
->where('user_id', $user->id)
->first();
$newOwner = $this->team->users()->first();
if ($teamUser->pivot->role === 'owner') {
$this->team->users()->updateExistingPivot($newOwner->id, ['role' => 'owner']);
}
};
$leaveTeam = function () {
$this->setNewOwner();
$this->team->users()->detach(auth()->user()->id);
$this->isAlreadyOnTeam = false;
$this->dispatch('remove-member');
};
$isAlreadyOnTeam = computed(function () {
return $this->team
->users()
->where('user_id', auth()->user()->id)
->exists();
});
$isFinalist = computed(function () {
return $this->team->finalist;
});
$isWinner = computed(function () {
return $this->team->winner;
});
$isOnAnyBriefTeam = computed(function () {
$teamIds = $this->brief->teams()->pluck('id');
$userInTeam = DB::connection('mysql')
->table('team_user')
->where('user_id', auth()->user()->id)
->whereIn('team_id', $teamIds)
->exists();
return $userInTeam;
});
$deleteTeam = function () {
$this->dispatch('team-deleted', $this->team->id);
};
$currentRouteIsEdit = computed(function () {
return ($this->crud && auth()->user()->role === 'ADMIN') || auth()->user()->role === 'MANAGER';
});
?>
<div x-data="{ open: false }" @mouseenter="open = true" @mouseleave="open = false"
class="relative flex flex-col justify-evenly w-[30%] bg-shakers-red rounded-xl p-4 @if ($this->currentRouteIsEdit) cursor-pointer @endif">
@unless (!$this->currentRouteIsEdit || !auth()->user()->role === 'ADMIN' || !auth()->user()->role === 'MANAGER')
<div x-show="open" x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="transform opacity-0 -translate-y-2"
x-transition:enter-end="transform opacity-100 translate-y-0" x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="transform opacity-100 translate-y-0"
x-transition:leave-end="transform opacity-0 -translate-y-2"
class="absolute -top-4 flex items-center justify-center w-full p-2 rounded-lg">
<button wire:click="openEditTeamModal" class="bg-white p-2 rounded-lg">
<x-heroicon-c-pencil-square class="size-10 text-black" />
</button>
</div>
@endunless
<x-mary-modal wire:model="editModal">
<x-slot:actions>
<x-mary-button icon="o-x-mark" spinner wire:click='closeEditTeamModal'
class="absolute text-black bg-white rounded-full top-5 right-5 btn-sm hover:bg-slate-200" />
</x-slot:actions>
<livewire:create-team-form :$brief />
</x-mary-modal>
<x-mary-modal wire:model="editModal">
<x-slot:actions>
<x-mary-button icon="o-x-mark" spinner wire:click='closeEditTeamModal'
class="absolute text-black bg-white rounded-full top-5 right-5 btn-sm hover:bg-slate-200" />
</x-slot:actions>
<livewire:edit-team-form :$brief :$team />
</x-mary-modal>
@if ($this->currentRouteIsEdit)
<div class="absolute -top-5 -right-5">
<x-mary-button icon="o-x-mark" wire:confirm="Estas seguro que quieres eliminar este team?" spinner
wire:click='deleteTeam' class="text-black bg-white rounded-full btn-sm hover:bg-slate-200" />
</div>
@endif
<div class="flex items-center justify-between">
<h6>EQUIPO</h6>
<x-team-diamonds-form />
</div>
<h4>{{ $team->name }}</h4>
<ul class="px-8 py-4 w-[100%] list-disc">
@foreach ($this->sortedTeamMembers as $member)
@if (auth()->user()->role == 'ADMIN' || auth()->user()->role == 'MANAGER')
<div class="flex items-center w-full gap-x-2" x-data="{ showButton: false }">
@if ($member->pivot->role === 'owner')
<li class="uppercase text-lg mb-[2px] flex items-center gap-x-2" @mouseover="showButton = true"
@mouseout="showButton = false">
{{ $member->first_name . ' ' . $member->last_name }}
<x-icons.userLeaderIcon class="size-5" />
</li>
@else
<li class="text-xl font-thin tracking-tight uppercase text-shakers-white"
@mouseover="showButton = true" @mouseout="showButton = false">
{{ $member->first_name . ' ' . $member->last_name }}
@if ($this->currentRouteIsEdit)
<x-mary-button id="trash"
wire:confirm="Estas seguro que quieres eliminar este miembro del equipo?"
wire:click="removeTeamMember({{ $member->id }})"
class="text-white border-none bg-transparent shadow-none hover:bg-transparent hover:border-none hover:translate-x-0.5 transition ease-in-out"
x-show="showButton">
<x-icons.trashIcon class="size-5" />
</x-mary-button>
@endif
</li>
@endif
</div>
@else
<div class="flex items-center w-full gap-x-2" x-data="{ showButton: false }">
@if ($member->pivot->role === 'owner')
<li class="uppercase text-lg mb-[2px] flex items-center gap-x-2">
{{ $member->first_name . ' ' . $member->last_name }}
<x-icons.userLeaderIcon class="size-5" />
@if ($this->currentRouteIsEdit)
<x-mary-button id="trash"
wire:confirm="Estas seguro que quieres eliminar este miembro del equipo?"
wire:click="removeTeamMember({{ $member->id }})"
class="text-white border-none bg-transparent shadow-none hover:bg-transparent hover:border-none hover:translate-x-0.5 transition ease-in-out"
x-show="showButton">
<x-icons.trashIcon class="size-5" />
</x-mary-button>
@endif
</li>
@else
<li class="text-xl font-thin tracking-tight uppercase text-shakers-white">
{{ $member->first_name . ' ' . $member->last_name }}
@if ($this->currentRouteIsEdit)
<x-mary-button id="trash"
wire:confirm="Estas seguro que quieres eliminar este miembro del equipo?"
wire:click="removeTeamMember({{ $member->id }})"
class="text-white border-none bg-transparent shadow-none hover:bg-transparent hover:border-none hover:translate-x-0.5 transition ease-in-out"
x-show="showButton">
<x-icons.trashIcon class="size-5" />
</x-mary-button>
@endif
</li>
@endif
</div>
@endif
@endforeach
</ul>
@if ($this->isAlreadyOnTeam)
@unless ($this->briefTimeHasFinished)
<x-mary-button
class="flex items-center justify-center px-4 mt-4 font-thin text-center text-white transition ease-in-out rounded-full gap-x-2 hover:translate-y-1"
wire:confirm="Seguro que quieres abandonar el equipo?" wire:click="leaveTeam">Abandonar
<x-heroicon-s-arrow-left-end-on-rectangle class="size-6" />
</x-mary-button>
@endunless
@elseif(!$this->isOnAnyBriefTeam)
@unless ($this->briefTimeHasFinished)
<x-mary-button class="btn" wire:confirm="Estas seguro que quieres unirte a este equipo?"
wire:click="addTeamMember"><span class="flex items-center justify-center">Unirse
<x-heroicon-s-arrow-right-end-on-rectangle class="size-6" />
</span>
</x-mary-button>
@endunless
@endif
</div>
Edit.blade livewire component (parent component)
<?php
use function Livewire\Volt\{state, rules, mount, on, computed, uses};
use App\Models\Client;
use App\Models\Brief;
use App\Models\Icon;
use App\Livewire\Forms\BriefForm;
use Livewire\Volt\Component;
use Illuminate\Support\Collection;
use Illuminate\Support\Carbon;
use App\Models\Team;
use App\Events\TeamIsWinner;
use App\Events\TeamIsFinalist;
use App\Actions\Briefs\GetStatusesAction;
use Mary\Traits\Toast;
uses([Toast::class]);
state(['brief', 'title' => '', 'client_id' => null, 'context' => '', 'problem' => '', 'objective' => '', 'deadline' => null, 'status' => '', 'icon_id' => null, 'materials_url' => null, 'teams', 'crud' => 'edit', 'client_searchable_id' => null, 'clientSearchable' => collect(), 'icons' => collect(), 'statuses' => []]);
mount(function (Brief $brief) {
$action = new GetStatusesAction();
$this->statuses = $action->handle();
$this->status = $this->brief->status;
$this->title = $this->brief->title;
$this->client_id = $this->brief->client_id;
$this->context = $this->brief->context;
$this->problem = $this->brief->problem;
$this->objective = $this->brief->objective;
$this->deadline = $this->brief->deadline;
$this->icon_id = $this->brief->icon_id;
$this->materials_url = $this->brief->materials_url;
$this->teams = $this->brief->teams;
$this->search();
$this->icons = Icon::all();
});
on([
'team-deleted' => function ($teamId) {
$team = Team::find($teamId);
$team->delete();
// $this->teams = Brief::find($this->brief->id)->teams;
},
]);
$search = function (string $value = '') {
$selectedOption = Client::where('id', $this->client_searchable_id)->get();
$this->clientSearchable = Client::query()
->where('name', 'like', "%$value%")
->orderBy('name')
->get()
->merge($selectedOption); // <-- Adds selected option
};
?>
<div>
<div class="flex flex-wrap gap-10 py-12 border-b border-white/10">
@if ($this->teams->isEmpty())
<h2 class="w-full text-3xl font-semibold text-center text-shakers-white">NO HAY EQUIPOS TODAVÍA</h2>
@else
@foreach ($teams as $team)
<livewire:teams.show-team
:key="$team->id"
:team="$team"
:brief="$brief"
:isAdmin=true
:crud="$crud" />
@endforeach
@endif
</div>
</div>
Tried to isolate as much as I could, this is the edit view where the $brief comes from, the edit view url it looks for the $brief->id (briefs/edit/2), and the 'teams' comes from $brief->teams (as you can see on mount $this->teams = $this->brief->teams
This is the edit.blade.phpview where the edit livewire component is rendered
<x-layouts.site :brief="$brief">
<div class="mx-auto p-4 sm:p-6 lg:p-8 w-[60vw]">
<livewire:edit :$brief crud="edit" />
</div>
</x-layouts.site>
Thank you guys for the interest & help on this, i'll continue to isolate more and more once I have more time. I'll add also now the network errors, because the team gets deleted, but it does a second network update where it fails. That's where I guess it's looking for the team id that just got deleted. 🫶
Please or to participate in this conversation.