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

text
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)

javascript
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)

javascript
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)

javascript
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)

html
<!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)

html
<!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

bash
# 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ónMétodoURLDescripción
Ver productosGET/Lista todos los productos (HTML)
Ver APIGET/productosLista todos (JSON)
Ver API unoGET/productos/1Ver un producto (JSON)
Mostrar formularioGET/crearMuestra el formulario
Guardar productoPOST/crearProcesa 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

Entradas más populares de este blog

Cómo Iniciar un Proyecto Node.js

8-Template Engines

6-Middleware?