Versión MVC con formulario para agregar productos
Versión MVC con formulario para agregar productos
Aquí tienes la versión completa con formulario para ingresar nuevos productos:
📁 ESTRUCTURA DEL PROYECTO
mi-app-mvc/ ├── models/ │ └── Producto.js ├── controllers/ │ └── productoController.js ├── views/ │ ├── index.ejs │ └── crear.ejs ├── public/ │ └── (archivos estáticos) └── app.js
📄 CÓDIGO COMPLETO
1️⃣ models/Producto.js (Modelo - Datos)
class Producto { constructor() { this.productos = [ { id: 1, nombre: 'Laptop', precio: 1000 }, { id: 2, nombre: 'Mouse', precio: 25 }, { id: 3, nombre: 'Teclado', precio: 50 } ]; this.contadorId = 4; } // Obtener todos obtenerTodos() { return this.productos; } // Obtener por ID obtenerPorId(id) { return this.productos.find(p => p.id === id); } // Crear nuevo producto crear(nombre, precio) { const nuevoProducto = { id: this.contadorId++, nombre: nombre.trim(), precio: parseFloat(precio) }; this.productos.push(nuevoProducto); return nuevoProducto; } } module.exports = new Producto();
2️⃣ controllers/productoController.js (Controlador)
const Producto = require('../models/Producto'); class ProductoController { // GET /productos - API: Devolver JSON con todos obtenerTodosJSON(req, res) { const productos = Producto.obtenerTodos(); res.json({ success: true, cantidad: productos.length, productos: productos }); } // GET /productos/:id - API: Devolver JSON de un producto obtenerUnoJSON(req, res) { const id = parseInt(req.params.id); const producto = Producto.obtenerPorId(id); if (!producto) { return res.status(404).json({ error: 'Producto no encontrado' }); } res.json(producto); } // GET / - Renderizar vista con todos los productos renderizarVista(req, res) { const productos = Producto.obtenerTodos(); res.render('index', { productos, mensaje: null, error: null }); } // GET /crear - Mostrar formulario para crear producto mostrarFormulario(req, res) { res.render('crear', { error: null, datos: null }); } // POST /crear - Procesar formulario y guardar producto guardarProducto(req, res) { const { nombre, precio } = req.body; // Validaciones if (!nombre || !precio) { return res.render('crear', { error: '❌ Todos los campos son obligatorios', datos: { nombre, precio } }); } if (nombre.trim().length < 3) { return res.render('crear', { error: '❌ El nombre debe tener al menos 3 caracteres', datos: { nombre, precio } }); } if (isNaN(precio) || parseFloat(precio) <= 0) { return res.render('crear', { error: '❌ El precio debe ser un número mayor a 0', datos: { nombre, precio } }); } // Crear producto const nuevoProducto = Producto.crear(nombre, precio); // Redirigir a la página principal con mensaje de éxito const productos = Producto.obtenerTodos(); res.render('index', { productos, mensaje: `✅ ${nuevoProducto.nombre} agregado correctamente`, error: null }); } } module.exports = new ProductoController();
3️⃣ app.js (Configuración principal)
const express = require('express'); const path = require('path'); const productoController = require('./controllers/productoController'); const app = express(); const PORT = 3000; // ============ CONFIGURAR EJS ============ app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views')); // ============ MIDDLEWARES ============ app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Para procesar formularios app.use(express.static('public')); app.use('/css', express.static('node_modules/bootstrap/dist/css')); app.use('/js', express.static('node_modules/bootstrap/dist/js')); // ============ RUTAS ============ // API REST app.get('/productos', productoController.obtenerTodosJSON); app.get('/productos/:id', productoController.obtenerUnoJSON); // Vistas web app.get('/', productoController.renderizarVista); app.get('/crear', productoController.mostrarFormulario); app.post('/crear', productoController.guardarProducto); // ============ INICIAR SERVIDOR ============ app.listen(PORT, () => { console.log(`=================================`); console.log(`🚀 Servidor MVC corriendo en http://localhost:${PORT}`); console.log(`📦 API: http://localhost:${PORT}/productos`); console.log(`🎨 Web: http://localhost:${PORT}`); console.log(`➕ Formulario: http://localhost:${PORT}/crear`); console.log(`=================================`); });
4️⃣ views/index.ejs (Lista de productos)
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Mi Tienda MVC</title> <link rel="stylesheet" href="/css/bootstrap.min.css"> </head> <body> <div class="container mt-5"> <h1 class="text-center">📦 Mi Tienda de Productos</h1> <!-- Mostrar mensajes --> <% if (mensaje) { %> <div class="alert alert-success alert-dismissible fade show" role="alert"> <%= mensaje %> <button type="button" class="btn-close" data-bs-dismiss="alert"></button> </div> <% } %> <% if (error) { %> <div class="alert alert-danger alert-dismissible fade show" role="alert"> <%= error %> <button type="button" class="btn-close" data-bs-dismiss="alert"></button> </div> <% } %> <div class="row mt-4"> <div class="col-md-8 offset-md-2"> <div class="card"> <div class="card-header d-flex justify-content-between align-items-center"> <h3 class="mb-0">Productos disponibles</h3> <a href="/crear" class="btn btn-success btn-sm">➕ Nuevo Producto</a> </div> <div class="card-body"> <% if (productos.length === 0) { %> <div class="alert alert-info">No hay productos disponibles</div> <% } else { %> <ul class="list-group"> <% productos.forEach(producto => { %> <li class="list-group-item d-flex justify-content-between align-items-center"> <div> <strong><%= producto.nombre %></strong> - $<%= producto.precio %> </div> <a href="/productos/<%= producto.id %>" class="btn btn-sm btn-primary">Ver</a> </li> <% }) %> </ul> <% } %> </div> </div> </div> </div> <!-- Info de arquitectura --> <div class="row mt-4"> <div class="col-md-8 offset-md-2"> <div class="alert alert-info"> <strong>📐 Arquitectura MVC con Formulario</strong><br> ✅ Modelo: Producto.js (datos)<br> ✅ Vista: index.ejs y crear.ejs (interfaz)<br> ✅ Controlador: productoController.js (lógica) </div> </div> </div> </div> <script src="/js/bootstrap.min.js"></script> </body> </html>
5️⃣ views/crear.ejs (Formulario para crear productos)
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Agregar Producto</title> <link rel="stylesheet" href="/css/bootstrap.min.css"> </head> <body> <div class="container mt-5"> <div class="row"> <div class="col-md-6 offset-md-3"> <div class="card"> <div class="card-header"> <h3 class="mb-0">➕ Agregar Nuevo Producto</h3> </div> <div class="card-body"> <!-- Mostrar errores --> <% if (error) { %> <div class="alert alert-danger"> <%= error %> </div> <% } %> <!-- Formulario --> <form action="/crear" method="POST"> <div class="mb-3"> <label for="nombre" class="form-label">Nombre del producto *</label> <input type="text" class="form-control" id="nombre" name="nombre" value="<%= datos ? datos.nombre : '' %>" required> <div class="form-text">Mínimo 3 caracteres</div> </div> <div class="mb-3"> <label for="precio" class="form-label">Precio *</label> <input type="number" class="form-control" id="precio" name="precio" step="0.01" value="<%= datos ? datos.precio : '' %>" required> <div class="form-text">Ingrese un número mayor a 0</div> </div> <div class="d-flex justify-content-between"> <button type="submit" class="btn btn-primary">💾 Guardar Producto</button> <a href="/" class="btn btn-secondary">❌ Cancelar</a> </div> </form> </div> </div> <!-- Botón volver --> <div class="text-center mt-3"> <a href="/" class="btn btn-link">← Volver a la lista de productos</a> </div> </div> </div> </div> <script src="/js/bootstrap.min.js"></script> </body> </html>
🚀 CÓMO EJECUTAR
# 1. Instalar dependencias npm install express ejs bootstrap # 2. Crear estructura de carpetas mkdir models controllers views public # 3. Crear los archivos con el código anterior # 4. Ejecutar node app.js
🎯 FUNCIONALIDADES INCLUIDAS
| Función | Método | URL | Descripción |
|---|---|---|---|
| Ver productos | GET | / | Lista todos los productos (HTML) |
| Ver API | GET | /productos | Lista todos (JSON) |
| Ver API uno | GET | /productos/1 | Ver un producto (JSON) |
| Mostrar formulario | GET | /crear | Muestra el formulario |
| Guardar producto | POST | /crear | Procesa el formulario |
✨ VALIDACIONES DEL FORMULARIO
✅ Todos los campos son obligatorios
✅ El nombre debe tener al menos 3 caracteres
✅ El precio debe ser un número mayor a 0
📸 VISTA PREVIA DE LAS PÁGINAS
Página principal (/)
Lista de productos
Botón "Nuevo Producto"
Mensajes de éxito/error
Formulario (/crear)
Campos: Nombre y Precio
Validaciones en vivo
Botón Guardar y Cancelar
¡Listo! Ahora puedes agregar productos desde el formulario
Comentarios
Publicar un comentario