Sistema de Templates en JavaScript: Separa Lógica de Presentación como un Profesional
¿Tu código JavaScript mezcla lógica de negocio con HTML? ¿Cambiar el diseño significa modificar múltiples funciones? Descubre el poder de los templates para crear código mantenible y flexible.
❌ El Problema: HTML Incrustado en Lógica
Antes tenía HTML mezclado con mi lógica JavaScript, creando un caos de mantenimiento:
// ❌ HTML incrustado en la lógica - difícil de mantener
async lista(page = 1, filtro = '') {
const response = await fetch(`${this.server}/api/productos?page=${page}`);
const data = await response.json();
// HTML directamente en el método
tbody.innerHTML = data.items.map(item => `
<tr data-line_id="${item.producto}">
<td>${item.producto}</td>
<td>${item.descripcion}</td>
<td>${item.unidadMedida}</td>
<td>${new Intl.NumberFormat('es-PY').format(item.precioUnitario)}</td>
<td>${item.afectacionIva}</td>
</tr>
`).join('');
// Mismo HTML repetido en otro método
tbody.innerHTML = data.items.map(item => `
<tr data-line_id="${item.producto}">
<td>${item.producto}</td>
<td>${item.descripcion}</td>
<td>${item.unidadMedida}</td>
<td>${new Intl.NumberFormat('es-PY').format(item.precioUnitario)}</td>
<td>${item.afectacionIva}</td>
</tr>
`).join('');
}
Problemas: Código duplicado, cambios tediosos, difícil reutilización y mezcla de responsabilidades.
✅ La Solución: Sistema de Templates Centralizado
Implementé un sistema donde cada clase define sus templates de forma organizada:
// ✅ ModeloBase.js - Maneja la lógica, usa templates
export default class ModeloBase {
constructor(recurso) {
this.recurso = recurso;
this.template = null; // Template por defecto
}
setTemplate(template) {
this.template = template;
}
async lista(page = 1, filtro = '') {
const response = await fetch(`${this.server}/api/${this.recurso}?page=${page}`);
const data = await response.json();
// ✅ Lógica limpia - solo usa el template
if (this.template) {
tbody.innerHTML = data.items.map(item => this.template(item)).join('');
}
}
}
// ✅ Producto.js - Define SU template específico
import ModeloBase from './ModeloBase.js';
export class Producto extends ModeloBase {
constructor() {
super('productos');
// ✅ Template centralizado y reutilizable
this.setTemplate(item => `
<tr data-line_id="${item.producto}">
<td data-field="producto">${item.producto}</td>
<td data-field="descripcion">${item.descripcion}</td>
<td data-field="unidadMedida">${item.unidadMedida}</td>
<td data-field="precioUnitario">
${new Intl.NumberFormat('es-PY', {
minimumFractionDigits: 0
}).format(item.precioUnitario)}
</td>
<td data-field="afectacionIva">${item.afectacionIva}</td>
</tr>
`);
}
}
🎯 Flexibilidad en Acción: Múltiples Templates
Puedes definir diferentes templates para diferentes contextos:
// ✅ Producto con múltiples vistas
export class Producto extends ModeloBase {
constructor() {
super('productos');
// Template para vista de tabla
this.tableViewTemplate = item => `
<tr data-line_id="${item.producto}">
<td>${item.producto}</td>
<td>${item.descripcion}</td>
<td>${this.formatearPrecio(item.precioUnitario)}</td>
</tr>
`;
// Template para vista de cards
this.cardViewTemplate = item => `
<div class="card" data-line_id="${item.producto}">
<h3>${item.descripcion}</h3>
<p>Precio: ${this.formatearPrecio(item.precioUnitario)}</p>
<button onclick="seleccionarProducto(${item.producto})">
Seleccionar
</button>
</div>
`;
// Template para vista móvil
this.mobileViewTemplate = item => `
<div class="mobile-item">
<strong>${item.descripcion}</strong>
<small>${this.formatearPrecio(item.precioUnitario)}</small>
</div>
`;
}
formatearPrecio(precio) {
return new Intl.NumberFormat('es-PY', {
minimumFractionDigits: 0
}).format(precio);
}
cambiarVista(tipoVista) {
switch(tipoVista) {
case 'tabla':
this.setTemplate(this.tableViewTemplate);
break;
case 'cards':
this.setTemplate(this.cardViewTemplate);
break;
case 'mobile':
this.setTemplate(this.mobileViewTemplate);
break;
}
this.lista(1, ''); // Recargar con nuevo template
}
}
📊 Comparación: Antes vs Ahora
| Aspecto | Antes (HTML en lógica) | Ahora (Sistema de Templates) |
|---|---|---|
| Cambios de diseño | Modificar múltiples métodos | Cambiar un solo template |
| Reutilización | Código duplicado | Templates reutilizables |
| Mantenibilidad | Frágil y propenso a errores | Robusto y organizado |
| Responsabilidades | Mezcladas | Separadas claramente |
| Flexibilidad | Rígido | Múltiples vistas fácilmente |
🚀 Casos de Uso Avanzados
Template con Lógica Condicional
// ✅ Template inteligente con condiciones
this.setTemplate(item => `
<tr data-line_id="${item.producto}" class="${item.stock === 0 ? 'sin-stock' : ''}">
<td>${item.producto}</td>
<td>${item.descripcion}</td>
<td>
${item.stock === 0
? '<span class="agotado">Agotado</span>'
: `<span class="disponible">${item.stock} unidades</span>`
}
</td>
<td>${this.formatearPrecio(item.precioUnitario)}</td>
</tr>
`);
Template con Componentes Reutilizables
// ✅ Templates que usan componentes
export class Producto extends ModeloBase {
constructor() {
super('productos');
this.setTemplate(item => this.productoTemplate(item));
}
productoTemplate(item) {
return `
<tr data-line_id="${item.producto}">
<td>${this.formatoCodigo(item.producto)}</td>
<td>${this.formatoDescripcion(item.descripcion)}</td>
<td>${this.formatoPrecio(item.precioUnitario)}</td>
<td>${this.formatoStock(item.stock)}</td>
</tr>
`;
}
formatoPrecio(precio) {
return `<span class="precio">${new Intl.NumberFormat('es-PY').format(precio)}</span>`;
}
formatoStock(stock) {
const clase = stock === 0 ? 'agotado' : stock < 10 ? 'poco-stock' : 'disponible';
return `<span class="${clase}">${stock} unidades</span>`;
}
}
📈 Beneficios del Sistema de Templates
| ✅ Separación de Concerns | Lógica y presentación claramente separadas |
| ✅ Mantenibilidad | Cambios de diseño en un solo lugar |
| ✅ Reutilización | Templates compartidos entre componentes |
| ✅ Testing | Puedes testear templates independientemente |
| ✅ Flexibilidad | Múltiples vistas sin cambiar lógica |
| ✅ Colaboración | Designers y developers trabajan separadamente |
Conclusión
Los templates no son solo para frameworks modernos. En JavaScript vanilla, un sistema de templates bien diseñado puede transformar tu código de caótico a profesional, permitiéndote escalar tu aplicación manteniendo el código limpio y mantenible.
Los templates no son solo para frameworks modernos. En JavaScript vanilla, un sistema de templates bien diseñado puede transformar tu código de caótico a profesional, permitiéndote escalar tu aplicación manteniendo el código limpio y mantenible.
Comentarios
Publicar un comentario