Como Crear un CRUD con Node JS (19.4.2) y Bootstrap 5 – Parte 4

Demo

En la anterior parte de este tutorial, realizamos la conexión a la base de datos para que nuestro sistema CRUD pueda llevar acabo las operaciones Crear, Leer, Actualizar y Eliminar. Asimismo creamos ciertos elementos necesarios para que nuestro proyecto funcione correctamente como el controlador, el modelo y realizamos ciertos cambios en el archivo principal de nuestro proyecto, me refiero al archivo app.js, en este cuarta parte vamos a continuar con el tutorial Como Crear un CRUD con Node JS (19.4.2) y Bootstrap 5, vamos con ello.

Partes


Antes de continuar con este Post, te invito a leer los siguientes artículos:

Asimismo, te invito a escuchar el Podcast: “Porque Todo Desarrollador Debes Ser Autodidacta“¿ Porqué Es Importante Saber Programar en la Ciberseguridad ?” (Anchor Podcast): 

Spotify: Sound Cloud: Apple Podcasts Anchor Podcasts

Bien ahora continuemos con el Post: Como Como Crear un CRUD con Node JS (19.4.2) y Bootstrap 5 – Parte 4.

Rutas (Backend)

Las rutas backend son esenciales para que el sistema CRUD sepa con que controlador, modelo, campos, tabla, etc. debe de trabajar. Creo un directorio con el nombre routes y dentro de el creo un archivo con el nombre productos.js:

/crud-nodejs19-bootstrap5  
├── /config 
├── /controllers  
├── /models 
├── /node_modules 
├── /routes 
    ├── productos.js // Creo y abro este archivo 
├── app.js // Abro este archivo 
├── package.json  
├── package-lock.json

Abro el archivo productos.js y dentro de el agrego lo siguiente (He colocado comentarios para explicar que hace ciertas partes del código): 

const express = require('express')
const router = express.Router()
const productoController =   require('../controllers/productos'); 

// Multer (Subida de imágenes de los productos)
const multer = require('multer'); 
var img;
const storage = multer.diskStorage({
  destination: 'uploads/',
  filename: function(req, file, callback) {

    const img_nombre = file.originalname;  
    // Reemplazamos los espacios en blanco del nombre de la imagen con guiones 
    const img_nuevo_nombre = img_nombre.replace(/\s+/g,'-'); 

    // Para evitar que los achivos se reemplazen entre si, le asignamos al nombre de la
    // imagen, la hora, tiempo, etc., actual 
    const img = Date.now() + '-' + img_nuevo_nombre;     

    callback(null, img);
  }
}); 
var upload = multer({ storage: storage }) 

// Ruta para listar todos los productos 
router.get('/', productoController.findAll);

// Ruta para crear un nuevo producto 
router.post('/', upload.single('img'), productoController.create);

// Ruta para leer un producto por su ID 
router.get('/:id', productoController.findById);

// Ruta para actualizar un producto por su ID 
router.post('/:id', upload.single('img'), productoController.update);

// Ruta para eliminar un producto por su ID 
router.post('/eliminar/:id', productoController.delete); 

module.exports = router

En el código anterior puedes ver que cada tarea CRUD (Create, Read, Update, y Delete) tiene una ruta independiente. Cada una de estas rutas las usaremos dentro de la vista HTML que crearemos con Bootstrap 5, por ejemplo al formulario para crear un nuevo producto, le asignaremos la ruta router.post(‘/’, upload.single(‘img’), productoController.create);

Vistas HTML (Bootstrap 5)

Dentro del archivo app.js llamo a path y lo coloco dentro de una variable llamada path. También instancio el directorio CSS y JS de Bootstrap 5 para poder acceder a sus hojas de estilos CSS y a sus archivos JavaScript. (Solo usaré bootstrap.min.css y bootstrap.min.js, pero si se requiere usar otro de sus archivos, ya lo dejamos configurado).

Rutas (Frontend)

También defino todas las rutas para las vistas HTML del sistema CRUD: 

// Bootstrap 5 (CSS y JS) 
app.use("/css",express.static(path.join(__dirname, "node_modules/bootstrap/dist/css")))
app.use("/js",express.static(path.join(__dirname, "node_modules/bootstrap/dist/js")))

// Rutas Front 
app.get('/', (req,res) => {
  var message = req.flash('message');  
  res.render('index', {
    data: message, // Mensaje para cada tarea realizada 
  })
})
app.get('/crear', (req,res) => {  
  res.render('crear')
})
app.get('/leer', (req,res) => {  
  res.render('leer')
})
app.get('/actualizar', (req,res) => {  
  res.render('actualizar')
})

El código completo del archivo app.js se veria asi: 

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const path = require("path") // Path 

const session = require('express-session');
app.use(session({secret: 'mySecret', resave: false, saveUninitialized: false})); 

const flash = require('express-flash'); 
app.use(flash());

// EJS template engine 
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "/views"));

// Puerto 
const port = process.env.PORT || 3000;

// Peticiones de tipo application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }))

// Peticiones de tipo application/json
app.use(bodyParser.json())

// Bootstrap 5 (CSS y JS) 
app.use("/css",express.static(path.join(__dirname, "node_modules/bootstrap/dist/css")))
app.use("/js",express.static(path.join(__dirname, "node_modules/bootstrap/dist/js")))

// Rutas Front 
app.get('/', (req,res) => {
  var message = req.flash('message');  
  res.render('index', {
    data: message, // Mensaje para cada tarea realizada 
  })
})
app.get('/crear', (req,res) => {  
  res.render('crear')
})
app.get('/leer', (req,res) => {  
  res.render('leer')
})
app.get('/actualizar', (req,res) => {  
  res.render('actualizar')
})

// Ruta Productos 
const ruta_productos = require('./routes/productos');
const con = require('./config/db');

// Usamos un Middleware 
app.use('/api/v1/productos', ruta_productos)

// Directorio de las imágenes 
app.use("/uploads",express.static(path.join(__dirname, "uploads")))

// Escuchamos las peticiones en el puerto establecido 
app.listen(port, () => {
  console.log(`La Aplicación está funcionando en el puerto ${port}`);
});

Ahora creo un directorio con el nombre views y dentro de el creo 4 archivos con la extensión ejs, esta extension es del motor de plantillas EJS que instale en la primera parte de este tutorial y alli explico porque uso EJS en ves de un archivo HTML normal. Los archivos que creo son: actualizar.ejscrear.ejsindex.ejs y leer.ejs

/crud-nodejs19-bootstrap5  
├── /config 
├── /controllers  
├── /models 
├── /node_modules 
├── /routes 
├── /views. 
    ├── actualizar.ejs // Archivo HTML para actualizar un producto 
    ├── crear.ejs // Archivo HTML para crear un producto 
    ├── index.ejs // Archivo HTML para la vista principal 
    ├── leer.ejs // Archivo HTML para leer un producto  
├── app.js // Abro este archivo 
├── package.json  
├── package-lock.json 

Nota: Para la tarea Eliminar, usaré la vista principal, no necesito crear una vista aparte para ello. Al menos para este proyecto eliminaremos los registros desde la vista principal por medio de un botón. Si tu proyecto requiere crear una vista para eliminar, puedes crearla, no hay problema.

Ahora pasaré a crear las vistas HTML.

Vista Principal (Listar todos los Registros)

Dentro de esta vista mostraré una tabla HTML con clases de Bootstrap 5 y en ella listo todos los productos. Abro el archivo index.ejs y le agrego lo siguiente:

<a href="/crear" class="btn btn-success mt-4 ml-3"> Crear </a>
<section class="example mt-4">

  <div class="table-responsive" id="tabladatos">
    <!-- Tabla HTML -->
  </div>

</section>

Puedes ver en el código anterior que he colocado una botón al inicio, este botón es para la tarea crear y cuando es presionado, envia al usuario a la vista crear.ejs en donde hay un formulario para crear un nuevo producto.

Para llamar a todos los registros desde la base de datos, coloco el siguiente código JavaScript antes de la etiqueta de cierre </body>:

<!-- Código Para Mostrar la Tabla con los datos -->
  <script type="text/javascript">
      fetch("http://localhost:3000/api/v1/productos").then(response => {
          if(response.ok) {
              return response.json();
          }
      }).then(data => {
          if(data) {
              console.log(data); 

              const ar = data; 
                let result = `<table class='table table-striped table-bordered table-hover text-center'><thead>
                              <tr>
                                <th>Nombre</th>
                                <th>Precio</th>
                                <th>Stock</th>
                                <th>Imagen</th>
                                <th>Acciones</th>
                              </tr>
                              </thead><tbody>`;
                ar.forEach((elem) => {
                    result += `<tr>
                        <td class=v-align-middle>${elem.nombre}</td>
                        <td class=v-align-middle>${elem.precio}</td>
                        <td class=v-align-middle>${elem.stock}</td>
                        <td class=v-align-middle><img src=http://localhost:3000/uploads/${elem.img} class=img-fluid style=max-width:50px></td>
                        <td class=v-align-middle>

                          <form action="http://localhost:3000/api/v1/productos/eliminar/${elem.id}" method="POST" onsubmit="return confirmarEliminar()">        

                            <a href="/leer?id=${elem.id}" class="btn btn-dark">Detalles</a>

                            <a href="/actualizar?id=${elem.id}" class="btn btn-primary">Editar</a>

                            <button type="submit" class="btn btn-danger">Eliminar</button>

                          </form>  

                        </td>
                      </tr>`
                      

                });
                result += `</tbody></table>`;
                document.getElementById("tabladatos").innerHTML = result;
             
           
           };

          }
      ).catch(err => console.error(err));      
    </script>

    <!-- Código Para eliminar un producto  -->
    <script type="text/javascript">
      function confirmarEliminar()
      {
      var x = confirm("Estas seguro de Eliminar?");
      if (x)
        return true;
      else
        return false;
      }
  </script>

</body>

Si voy a la ruta http://localhost:3000, puedo ver la vista HTML con la tabla creada con Bootstrap 5 que muestra todos los registros de la tabla productos: 

Bien hasta aquí hemos creado las rutas para nuestro CRUD, también hemos creado la primera vista HTML en donde listamos todos los registros de la tabla productos y agregamos ciertas configuraciones al archivo app.js

Ten Paciencia, lo que quiero es que conozcas bien como se crea este proyecto y no llenarte el capitulo de mucho contenido porque te puedes marear y no tendrás un óptimo aprendizaje. 

Nota (s)

  • En la siguiente parte y última, terminaremos de crear las vistas y realizaremos ciertas configuraciones adicionales.
  • No olvides que debemos usar la Tecnología para hacer cosas Buenas por el Mundo. 

 

Síguenos en nuestras Redes Sociales para que no te pierdas nuestros próximos contenidos.