Select dependiente desde Livewire
Reny Ramos • November 18, 2020
laravel livewire livewirev2 programmingEste tema, sobre select dependientes, estará divido en 2 partes, una donde dejare toda la fundación del mismo y mostrare la creación de este tipo de inputs sin ninguna librería Js, y el siguiente el cual continuara con lo que se creo acá y mostrara una tecnica que se puede utilizar para trabajar con Librerías JS como select2.
Livewire permite implementar select dependientes de forma muy sencilla, sin embargo, la utilización de librerías JS para la mejora del aspecto y nuevas funcionalidades a dichos elementos, complican en gran medida el trabajo de Livewire, debido a los cambios que realiza JS directamente sobre el html le hace imposible a Livewire llevar el control de los cambios en el DOM.
Para demostrar esto he decidido crear un proyecto sobre búsqueda de Digimons, a través de una api publica con la cual se debe seleccionar el LVL del digimon para luego poder seleccionar a un digimon que sea de ese lvl, algo bastante sencillo y directo.
Para comenzar crearemos un componente Livewire para la busqueda y un controlador con un único método __invoke
php artisan livewire:make Digimons.Search
php artisan make:controller DigimonSimpleSearch -i
Ademas de una única ruta en el archivo web.php
Route::get('/digimon-simple', DigimonSimpleSearchController::class)→name('search.simple');
El contenido del controlador sera muy sencillo, solamente retornara la vista.
public function __invoke(Request $request)
{
return view('digimons.search.simple');
}
Adicionalmente, tendremos 3 vistas, una dentro de digimon>search llamada simple.blade.php y una para un componente de base para layout dentro de componentes llamado app, las dos bastante sencillas.
app.blade tendrá el esqueleto normal de un layout, agregando bootstrap y el css y js de Livewire.
entro de simple.php tendremos un card el cual tendrá en el card body el componente Livewire para quedar así.
<x-app title='Busqueda sencilla'>
<x-slot name="body">
<div class="d-flex justify-content-center">
<div class="card col-6">
<div class="card-title">Busqueda sencilla</div>
<div class="card-body">
<livewire:digimons.search>
</div>
</div>
</div>
</x-slot>
</x-app>
De momento el componente Livewire sera muy sencillo, contando con lo siguiente.
public $lvls = [
'fresh',
'training',
'rookie',
'champion',
'ultimate',
'mega',
];
public $lvl, $digimon, $digimons = [];
public function render()
{
return view('livewire.digimons.search');
}
Tendremos entre las variables $lvls y $digimons, las cuales contendrán los listados que se utilizaran para rellenar las opciones de los select, ademas $lvl y $digimon, quienes tendrán las opciones seleccionadas, quedando la vista del Livewire de a siguiente manera.
<form>
<div class="row">
<div class="col-6">
<div class="form-group">
<label for="select">Select Lvl</label>
<div>
<select id="select" name="select" class="custom-select" wire:model='lvl'>
<option value="">Seleccione Lvl</option>
@foreach ($lvls as $item)
<option value="{{ $item }}">{{ $item }}</option>
@endforeach
</select>
</div>
</div>
</div>
<div class="col-6">
<div class="form-group">
<label for="select">Select</label>
<div>
<select id="select" name="select" class="custom-select" wire:model='digimon'>
@foreach ($digimons as $item)
<option value="{{ $item['name'] }}">{{ $item['name'] }}</option>
@endforeach
</select>
</div>
</div>
</div>
</div>
<div>
</div>
<div wire:loading.delay>
Loading content...
</div>
<div class="form-group row">
<div class="offset-4 col-8">
<button name="submit" type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
De momento solo el listado de lvls es funcional, ahora lo que toca es enlazar el cambio de lvl con el listado de digimons a travez de Lifecycle Hooks, tomaremos el update de $lvl para activarlo de la siguiente manera.
public function updatingLvl($value)
{
$request = Http::get(‘https://digimon-api.vercel.app/api/digimon/level/’ . $value);
$this->digimons = new \Illuminate\Support\Collection($request->json());
}
Utilizamos la librería Http de Laravel para hacer un request a la endpoint del api, y colocamos el resultado dentro de una colleccion lo cual nos ayudara mas adelante.
Ya con esto esta completamente funcional los dos select, de esta forma, haciendo una pequeña refactorizacion, y agregando una funcionalidad extra (avatar) la cual explotaremos en el post final, el componente de livewire quedaría de la siguiente manera
<?php
namespace App\Http\Livewire\Digimons;
use Illuminate\Support\Facades\Http;
use Livewire\Component;
class Search extends Component
{
public $lvls = [
'fresh',
'training',
'rookie',
'champion',
'ultimate',
'mega',
];
public $lvl, $digimon, $avatar, $baseUrl, $digimons;
public function mount()
{
$this->baseUrl = 'https://digimon-api.vercel.app/api/digimon/level/';
$this->digimons = new \Illuminate\Support\Collection([]);
}
public function render()
{
return view('livewire.digimons.search');
}
public function updatingLvl($value)
{
$request = Http::get($this->baseUrl . $value);
$this->digimons = new \Illuminate\Support\Collection($request->json());
$this->avatar = $this->digimons->first()['img'];
}
public function updatingDigimon($value)
{
$this->avatar = $this->digimons->where('name', $value)->first()['img'];
}
}
Por ultimo dejo el link al Repositorio, mas adelante estaré agregándole mas funcionalidades a medida de que cree nuevos posts.