reload:fragment
Desde que agarré una filosofía servidor-céntrica para mis proyectos, he estado construyendo web apps con muy poco javascript, pero manteniendo experiencias de usuario dinámicas y fluídas
Una de las estrategias que más me gusta, es la que tienen herramientas como HTMX o Alpine AJAX; Le llaman Hypermedia-Driven Application (HDA), que es como el punto intermedio entre una Multi-page Application (MPA) y una Single-Page Application (SPA)
En ésta arquitectura la aplicación usa patrones que van de actualizar fragmentos específicos del DOM con llamadas AJAX a través de enlaces y formularios html, sin recargar la pagina completa, pero tampoco delegando logica al frontend
DHH (el creador de Ruby on Rails) lo llamó HTML over the wire y es la misma filosofía detrás de soluciones más chonchas como Hotwire y Livewire
El punto es que no siempre es necesario instalar el set completo de utilidades de un framework en tu proyecto para aplicar el concepto fundamental de ésta estrategia
A veces solo necesitas "refrescar" un fragmento del DOM sin recargar la página
Para esos casos sencillos, escribí éste script; Un event listener que aplica el concepto principal de HTML over the wire, sin implementar toda la arquitectura
window.addEventListener('reload:fragment', async function (event) {
const { element_id, url } = event.detail;
const oldElement = document.getElementById(element_id);
if (!oldElement) {
return;
}
try {
const response = await fetch(url);
if (!response.ok) throw new Error(response.status);
const html = await response.text();
const parser = new DOMParser();
const newDocument = parser.parseFromString(html, 'text/html');
const newElement = newDocument.getElementById(element_id);
if (newElement && oldElement) {
oldElement.replaceWith(newElement);
}
} catch (error) {
console.error(error);
}
});
El event listener recibe en el evento los parámetros element_id y url, realiza una llamada HTTP y parsea la respuesta como un documento html; Extrae el elemento que necesitamos "recargar" y lo reemplaza en el DOM
El "reload" del fragmento se ejecuta despachando el evento reload:fragment
window.dispatchEvent(new CustomEvent('reload:fragment', {
detail: {
element_id: 'product_index_table',
url: '/products/3429'
}
}));
O también desde un componente Livewire, que se ve así
$this->dispatch('reload:fragment', [
'element_id' => 'product_index_table',
'url' => route('products.index', $id)
]);