Any help is appreciated. If I need to clarify more what I'm trying to do, let me know. I can't always put what I'm thinking into words :\
Dispatching an event to another component and rendering something inside/in place of that component?
Hopefully the title makes sense. If it doesn't, hopefully my explanation will be better.
I'm trying to work on the users' settings page where they can edit their profile and select some favorite movies from the db. I have it sort of working at the moment but not without a lot of struggling and am not sure if I'm doing it the best way and it still isn't fully correct (see screenshot lol).
I have the following Views and Components.
favorite-movie-card.blade.php
<div class="p-10 bg-zinc-800 rounded-sm shadow-lg border border-zinc-700 cursor-pointer group flex
justify-center items-center min-h-40"
x-data="{ showModal: false }"
@click="showModal = true">
@if(!$selectedMovie)
<x-icon-add class="w-8 h-8 stroke-zinc-700 stroke-2
drop-shadow-md
group-hover:stroke-zinc-300
transition-all ease-in-out
cursor-pointer"/>
@else
<img src="{{ $selectedMovie['poster_path'] }}"
alt="{{ $selectedMovie['title'] }}"
class="w-full h-full object-cover">
@endif
<template x-teleport="body">
<livewire:favorite-movie-modal x-show="showModal" @close="showModal = false"/>
</template>
</div>
FavoriteMovieCard.php
<?php
namespace App\Livewire;
use App\Models\Movie;
use Livewire\Attributes\On;
use Livewire\Component;
class FavoriteMovieCard extends Component
{
public int $movieId;
public Movie $selectedMovie;
#[On('movie-selected')]
public function setMovie(int $movieId): void
{
$this->movieId = $movieId;
$movie = Movie::findOrFail($movieId);
$this->selectedMovie = $movie;
}
public function render()
{
return view('livewire.favorite-movie-card');
}
}
favorite-movie-search.blade.php
<div class="relative" wire:submit.prevent="searchText">
<div class="relative">
<input
type="text"
placeholder="Search"
class="w-full text-sm border border-zinc-700 rounded-lg px-2 py-1 text-zinc-200 bg-zinc-900
focus:border-primary-500 focus:outline-none focus:ring-none focus:ring-primary-500"
wire:model.live.debounce.300ms="searchText"
wire:keydown.enter.prevent
>
@if(count($searchResults) > 0)
<div class="absolute left-0 right-0 top-full mt-1 bg-zinc-900 border border-zinc-700 rounded-lg
shadow-lg z-50 max-h-96 overflow-y-auto" id="favorite-movie-search-results">
{{--TODO: Modify to use ul>li --}}
<ul>
@foreach($searchResults as $searchResult)
<li
class="block px-4 py-2 hover:bg-zinc-800 border-zinc-800 text-zinc-200
text-sm cursor-pointer"
wire:click="selectMovie({{ $searchResult->id }})">
{{ $searchResult->title }} ({{ $searchResult->release_date->format('Y') }}) <span>{{
$searchResult->crew->first()->name ?? 'Unknown Director'
}}</span>
</li>
@endforeach
</ul>
</div>
@elseif($searchText && count($searchResults) === 0)
<div class="absolute left-0 right-0 top-full mt-1 bg-zinc-900 border border-zinc-700 rounded-lg
shadow-lg z-50 max-h-96 overflow-y-auto text-sm text-zinc-200">
<span class="block px-4 py-2 bg-zinc-800">No results found matching query</span>
<span class="inline-block px-4 py-2 text-xs text-zinc-400 font-thin">Need something added?</span>
<a href="{{ route('about.creating-data') }}" class="hover:text-primary-400
hover:underline text-xs" wire:navigate>Find out how</a>
</div>
@endif
</div>
</div>
FavoriteMovieSearch.php
<?php
namespace App\Livewire;
use App\Models\Movie;
use Livewire\Attributes\Validate;
use Livewire\Component;
class FavoriteMovieSearch extends Component
{
#[Validate('required')]
public string $searchText = '';
public $searchResults = [];
public function selectMovie(int $movieId): void
{
$this->dispatch('movie-selected', $movieId);
$this->reset('searchResults');
// $this->dispatch('close-modal');
}
public function updatedSearchText(string $value): void
{
$this->reset('searchResults');
$this->validate();
$wildcard = "%{$value}%";
$this->searchResults = Movie::select(['id', 'title', 'release_date'])->with([
'crew' => function ($query) {
$query->where('job', 'Director');
},
])->where('title', 'LIKE', $wildcard)->get();
}
public function render()
{
return view('livewire.favorite-movie-search');
}
}
For brevity, the favorite-movie-search is inside the favorite-movie-modal (not shown). I'm trying to dispatch an event from the Search to the Card so that the Card is replaced with the poster image from the movie. It kind of works, but...https://i.imgur.com/UgSUw1h.png.
I want it to just occupy the card slot that was clicked on, but am not sure how to do that. And one other obstacle is binding all of these to some sort of array of favorite movies that will be passed into my form. They aren't input elements so I can't just use $request->... to get the value.
Lastly, I'm passing the movie ID here which I think is best, but I'm passing the entire movie in some places too I believe. If I'm not doing it here, I'm doing it in a lot of other places and idk what is best; to pass the entire movie, regardless of what its passing to needs the entire Movie and its data, or to pass the ID and make the SQL query for the needed data in the passed-to component/View.
Any help here is appreciated!
Please or to participate in this conversation.