reload:fragment
Desde que agarré una filosofía servidor-céntrica para mis proyectos, he estado construyendo web apps con muy poco javascript, pero procurando mantener experiencias de usuario dinámicas y fluídas. Para lograrlo, uno de los patrones que más me gusta, es el que usan herramientas como HTMX o Alpine AJAX
Le llaman Hypermedia-Driven Application (HDA), que es como un punto intermedio entre una Multi-page Application (MPA) y una Single-Page Application (SPA). Éste tipo de aplicaciónes actualizan fragmentos específicos del HTML sin recargar la pagina completa, pero tampoco delegando lógica al frontend; Utilizan un set de atributos HTML personalizados que construyen llamadas AJAX internamente y reemplazan secciones del DOM con fragmentos actualizados desde el servidor
DHH, el creador de Ruby on Rails, lo llamó HTML over the wire y es la misma filosofía detrás de Livewire
El tema es que no siempre es necesario instalar un set completo de utilidades o framework para aplicar el concepto fundamental de éste patrón. A veces solo necesitamos "refrescar" un fragmento del DOM sin recargar la página
Para esos casos sencillos, escribí un event listener que aplica el concepto principal de HTML over the wire, pero de manera minimalista, sin requerir dependencias
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)
]);