Definir y escuchar eventos personalizados en Laravel Livewire
Índice de contenido
- Propiedad "Refresh"
- Comunicación entre componentes
- Eventos hacia JavaScript
- Livewire 2 vs Livewire 3: cambios importantes
- Cómo emitir eventos personalizados en Livewire
- Ejemplo real con CRUD (add, update, delete)
- Manejando varios eventos en un mismo componente
- Errores comunes que he visto (y he sufrido)
- Escuchar eventos desde JavaScript (toasts, modales, alertas)
- NO se puede inyectar JavaScript mediante eventos de Laravel Livewire
Lo siguiente que vamos a hacer sería definir un evento es decir despachar un evento similar a lo que ya hicimos con el de car que tenemos aquí despachar un evento con el parámetro Cuando hacemos alguna de las operaciones tipo CRUD de eliminar actualizar o crear así que luego esto lo vamos a escuchar desde acá y vamos a mostrar el toas ese viene siendo el sentido así que si tienes el mismo problema que yo al menos de momento comenta esto por favor ya esto lo resolvemos en las siguientes clases y hacemos los detalles finales para que no te dé un error ahí que es una sección que me aparece a mí entonces bueno vamos allá.
Nos quedamos en que ya conocemos el JavaScript de Livewire, lo cual, es una pieza fundamental para el uso de los eventos personalizados que ocurren en el cliente y servidor.
Los eventos en Livewire sirven para comunicar que “algo ocurrió” dentro de un componente. Puede ser que se añadió un producto al carrito, que se actualizó un post, o que el usuario eliminó un registro.
A nivel práctico, los uso cuando quiero que la UI reaccione automáticamente a acciones del backend: mostrar un toast, refrescar componentes, o actualizar otro componente que no está directamente conectado.
Propiedad "Refresh"
Entonces, ¿qué es lo que quiero hablar sobre refresh? Ya aclarado un poco eso, ya que a lo que queremos llegar es a recargar ese componente, para ello, tenemos una propiedad refresh en Laravel Livewire según hablamos anteriormente. La idea es que, al suceder los cambios en alguno e los componentes hermanos, notifiquemos al componente padre y este, actualice su estado mediante la propiedad refresh:
class General extends Component
{
***
protected $listeners = ['stepEvent'];
class Person extends Component
{
***
function submit()
{
***
$this->dispatch('stepEvent', 3);Comunicación entre componentes
En Livewire, un componente puede decirle a otro:
"Hey, acabo de crear un item, reacciona como necesites".
Este flujo se vuelve muy claro cuando haces CRUD. En mi caso, cuando agrego o modifico un producto en el carrito, disparo:
$this->dispatch("itemAdd", $post);https://www.desarrollolibre.net/blog/laravel/laravel-livewire-introduction-to-javascript
Eventos hacia JavaScript
Aquí Livewire brilla. Desde JS puedes escuchar eventos así:
Livewire.on('itemAdd', (params) => {
toast('Item agregado: ' + params[0].title, options);
});Esta conexión es la que hace posible mostrar toasts, abrir modal, o ejecutar cualquier lógica del frontend sin tocar AJAX ni escribir boilerplate.
Livewire 2 vs Livewire 3: cambios importantes
Este es el punto donde muchos se pierden (yo incluido al principio). Si vienes de Livewire 2, cambia bastante.
De emit() a dispatch()
Antes (v2):
$this->emit('evento');Ahora (v3):
$this->dispatch('evento');Funcionalmente es lo mismo: lanzar un evento. Solo cambia el nombre.
De $listeners a #[On]Antes (v2):
protected $listeners = ['evento' => 'método'];Ahora (v3):
#[On('evento')]
public function método() { ... }Cómo emitir eventos personalizados en Livewire
Emitir eventos en Livewire 3 es tan fácil como llamar a dispatch() dentro de cualquier método del componente.
$this->dispatch("itemAdd", $post);Cuando hago CRUD del carrito, disparo distintos eventos:
$this->dispatch("itemChange", $post);
$this->dispatch("itemDelete");Es útil pasar el post completo porque luego lo uso para el toast:
toast('Item actualizado: ' + params[0].title, options)Ejemplo real con CRUD (add, update, delete)
Aquí un ejemplo idéntico al que uso yo:
public function add($post, $count = 1)
{
if ($count <= 0) {
$this->dispatch("itemDelete");
return;
}
if (Arr::exists($cart, $post['id'])) {
$cart[$post['id']][1] = $count;
$this->dispatch("itemChange", $post);
} else {
$cart[$post["id"]] = [$post, $count];
$this->dispatch("itemAdd", $post);
}
}Este patrón hace muy legible el flujo de acciones.
Cómo escuchar eventos con #[On] en tus componentes
En Livewire, escuchar eventos es tan fácil como colocar el atributo encima del método.
#[On('itemAdd')]
public function actualizarCarrito($post)
{
// Actualizo tabla, total, o lo que necesite
}Manejando varios eventos en un mismo componente
Puedes escuchar tantos como quieras:
#[On('itemAdd')]
#[On('itemChange')]
#[On('itemDelete')]
public function refreshCart()
{
$this->loadCart();
}Errores comunes que he visto (y he sufrido)
- No usar #[On] correctamente.
- Tener un return antes del dispatch.
- Un typo en el nombre del evento (“itemAddd”).
- Ejecutar dispatch desde un componente sin estar montado correctamente.
- Tener secciones vivas en el layout que no son compatibles (a mí me pasó; terminé comentándolas para evitar errores mientras lo resolvía).
Escuchar eventos desde JavaScript (toasts, modales, alertas)
Esta parte es clave cuando quieres feedback instantáneo en UI.
Configuración de toast-me
Yo lo instalo así:
npm i toast-meLuego, en resources/js/app.js:
import toast from 'toast-me';
window.toast = toast;
const options = {
position: 'bottom'
};
Livewire.on('evento'): ejemplo completo
Livewire.on('itemAdd', (params) => {
toast('Item agregado: ' + params[0].title, options)
})
Livewire.on('itemChange', (params) => {
toast('Item actualizado: ' + params[0].title, options)
})
Livewire.on('itemDelete', () => {
toast('Item eliminado del carrito', options)
})El:
window.toast = toastSe configura si quieres emplear en cualquier otra parte lo pudieras hacer desde el objeto window o mejor dicho ya lo tienes configurado en el objeto window y ya lo pudieras emplear en cualquier parte así que coloco todas igual a todas coloco aquí una constante y esta var a ser para manejar la posición:
const options = {
position:'bottom'
}Por lo demás, puedes emplearlo en base a los eventos de Livewire, por ejemplo:
resources/js/app.js
Livewire.on('itemAdd', (params) => {
toast('Item add to cart: ' + params[0].title, options)
})Desde los componentes:
$this->dispatch("itemAdd",$post);NO se puede inyectar JavaScript mediante eventos de Laravel Livewire
Livewire no permite ejecutar JavaScript desde eventos como wire:click, wire:change, etc.; este bloqueo es por cuestiones de seguridad, es decir, una vez cargada la página, en navegador NO permite
Ejemplo claro:
<div class="mt-5">
@if ($buy)
<h1>HELLO!!!!</h1>
<script>
alert()
</script>
@else
****
<button class="btn btn-success mb-3" wire:click="readyBuy">
{{ __('Buy') }}
</button>Por ejemplo, si cambiamos el valor de $buy mediante un evento de Livewire:
function readyBuy()
{
$this->buy = true;
}Esto NO funciona, el alert es ignorado por el navegador por lo comentado; lo que debes de hacer es cargar siempre el JS y mediante un evento de Livewire:
function readyBuy()
{
$this->buy = true;
}Pero si intento insertar ese script desde un evento de Livewire, como al hacer clic en un botón, no funciona. El navegador no lo ejecuta por cuestiones de seguridad.
¿Por qué no se puede inyectar JS desde eventos?
Los navegadores modernos bloquean la inyección dinámica de JavaScript por seguridad. Aunque puedas "engañarte" usando la consola del navegador, no es lo mismo que inyectarlo desde un evento dentro del ciclo de renderizado del navegador. El navegador lo bloquea, porque esto podría ser usado para inyectar scripts maliciosos.
Que ejecutamos desde el servidor:
function readyBuy()
{
$this->buy = true;
+ $this->dispatch('load-payments', [
+ 'price' => $this->price,
+ ]);
}Y definimos en el cliente:
<script>
Livewire.on('load-payments', async (data) => {
alert()
})
</script> Siguiente paso aprende el funcionamiento de las peticiones para sincronizar propiedades y eventos.
Acepto recibir anuncios de interes sobre este Blog.
Vamos a conocer como crear eventos personalizados en Laravel Livewire y escucharlos en el cliente mediante JavaScript.