5: Recorrer entradas con forEach en EJS

馃幆 Objetivo de esta parte

Aprender a recorrer arreglos en EJS usando forEach y mostrar cada entrada con estilos de Bootstrap.


1️⃣ La sintaxis correcta en EJS para forEach

En tus im谩genes veo que est谩s usando <% entries.forEach(function(entry){ %> y <% }) %> para cerrar.

馃摉 Reglas importantes de EJS para forEach:

SintaxisFunci贸n
<% codigo %>Ejecuta JavaScript (NO muestra nada)
<%= variable %>Muestra el valor en el HTML
<% entries.forEach(...) { %>Abre el bucle
<% }) %>Cierra el bucle

2️⃣ El index.ejs completo (seg煤n tus im谩genes)

Basado en tus capturas, este es el c贸digo correcto:

html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title><%= title %></title>
    <% include partials/head %>
</head>
<body class="container">
    <% include partials/header %>

    <% if(entries.length) { %>
        <% entries.forEach(function(entry){ %>
            <div class="panel panel-primary">
                <div class="panel-heading">
                    <%= entry.title %>
                    <div class="pull-right">
                        <%= entry.published %>
                    </div>
                </div>
                <div class="panel-body">
                    <%= entry.content %>
                </div>
            </div>
        <% }) %>
    <% } else { %>
        <p>No existen entradas</p>
        <a href="/new-entry">¡Agrega una!</a>
    <% } %>
</body>
</html>

3️⃣ Explicaci贸n l铆nea por l铆nea del c贸digo

L铆nea 11: Verificar si hay entradas

ejs
<% if(entries.length) { %>
  • entries viene de app.locals.entries (lo configuramos en routes/index.js)

  • entries.length es 0 si no hay entradas

  • Si hay entradas, ejecuta el c贸digo dentro del if

L铆nea 12: Recorrer cada entrada con forEach

ejs
<% entries.forEach(function(entry){ %>
  • forEach es un m茅todo de JavaScript para recorrer arreglos

  • entry es cada elemento del arreglo (cada mensaje)

  • El <% ... %> ejecuta c贸digo pero no muestra nada en pantalla

L铆neas 13-20: Mostrar cada entrada

ejs
<div class="panel panel-primary">
    <div class="panel-heading">
        <%= entry.title %>           <!-- Muestra el t铆tulo -->
        <div class="pull-right">
            <%= entry.published %>   <!-- Muestra la fecha -->
        </div>
    </div>
    <div class="panel-body">
        <%= entry.content %>         <!-- Muestra el contenido -->
    </div>
</div>

L铆nea 21: Cerrar el forEach

ejs
<% }) %>
  • Este %> ) cierra el bucle que abrimos con forEach

L铆neas 22-25: Si NO hay entradas

ejs
<% } else { %>
    <p>No existen entradas</p>
    <a href="/new-entry">¡Agrega una!</a>
<% } %>

4️⃣ Otra forma de escribir forEach (m谩s moderna)

EJS tambi茅n permite usar arrow functions (m谩s moderno):

ejs
<% entries.forEach(entry => { %>
    <div class="panel panel-primary">
        <div class="panel-heading">
            <%= entry.title %>
        </div>
        <div class="panel-body">
            <%= entry.content %>
        </div>
    </div>
<% }) %>

5️⃣ Formato de fecha mejorado

La fecha entry.published es un objeto Date. Podemos formatearla mejor:

ejs
<div class="pull-right">
    <%= entry.published.toLocaleDateString() %> 
    <!-- Muestra: 14/5/2024 -->
    
    O con hora:
    <%= entry.published.toLocaleString() %>
    <!-- Muestra: 14/5/2024, 15:30:45 -->
</div>

6️⃣ A帽adir un footer (opcional)

Si quieres agregar un footer como en tus im谩genes, crea views/partials/footer.ejs:

html
<!-- views/partials/footer.ejs -->
<footer class="text-center" style="margin-top: 50px; padding: 20px; border-top: 1px solid #ddd;">
    <p>&copy; 2024 - Mi GuestBook con Node.js y EJS</p>
</footer>

Y luego en index.ejs (antes de </body>):

ejs
<% include partials/footer %>

7️⃣ C贸digo completo de routes/index.js (recordatorio)

Aseg煤rate de que routes/index.js est茅 correcto:

javascript
module.exports = (app) => {
    let entries = [];
    app.locals.entries = entries;

    app.get('/', (req, res) => {
        res.render('index', {
            title: 'Inicio'
        });
    });

    app.get('/new-entry', (req, res) => {
        res.render('new-entry', {
            title: 'Nueva Entrada'
        });
    });

    app.post('/new-entry', (req, res) => {
        if (!req.body.title || !req.body.body) {
            res.status(400).send('Entradas deben tener un t铆tulo y un cuerpo');
            return;
        }

        let newEntry = {
            title: req.body.title,
            content: req.body.body,
            published: new Date()
        };

        entries.push(newEntry);
        res.redirect('/');
    });
};

8️⃣ Errores comunes y soluciones

Error 1: No se ven las entradas

ejs
<!-- ❌ MAL: El igual (=) hace que se muestre algo que no quieres -->
<%= entries.forEach(entry => { %>

<!-- ✅ BIEN: Sin igual, solo ejecuta el c贸digo -->
<% entries.forEach(entry => { %>

Error 2: Olvidar cerrar el forEach

ejs
<!-- ❌ MAL: Falta cerrar el bucle -->
<% entries.forEach(entry => { %>
    <%= entry.title %>
<!-- FALTA <% }) %> -->

<!-- ✅ BIEN: Siempre cerrar el bucle -->
<% entries.forEach(entry => { %>
    <%= entry.title %>
<% }) %>

Error 3: Confundir if con forEach

ejs
<!-- ❌ MAL: if no es para recorrer, solo para condicionar -->
<% if(entry in entries) { %>  <!-- Esto no recorre nada -->

<!-- ✅ BIEN: if para condici贸n, forEach para recorrer -->
<% if(entries.length > 0) { %>
    <% entries.forEach(entry => { %>
        <%= entry.title %>
    <% }) %>
<% } %>

9️⃣ Comparativa: for vs forEach en EJS

M茅todoC贸digoCu谩ndo usar
for cl谩sico<% for(let i=0; i<entries.length; i++) { %>Cuando necesitas el 铆ndice
forEach<% entries.forEach(entry => { %>Cuando solo necesitas el valor
for...of<% for(let entry of entries) { %>Alternativa moderna

Ejemplo con for cl谩sico:

ejs
<% for(let i = 0; i < entries.length; i++) { %>
    <div class="panel panel-primary">
        <div class="panel-heading">
            #<%= i+1 %> - <%= entries[i].title %>
        </div>
        <div class="panel-body">
            <%= entries[i].content %>
        </div>
    </div>
<% } %>

馃敓 Probar la aplicaci贸n

Paso 1: Asegurar estructura de archivos

text
views/
├── partials/
│   ├── head.ejs
│   └── header.ejs
├── index.ejs      (con el c贸digo de este tutorial)
└── new-entry.ejs

Paso 2: Iniciar servidor

bash
npm run dev

Paso 3: Probar el flujo completo

  1. Entrar a http://localhost:3000/ → Ve "No existen entradas"

  2. Click en "Write a GuestBook" o "/new-entry"

  3. Agregar t铆tulo y contenido

  4. Enviar

  5. Ver la entrada mostrada con el panel de Bootstrap


馃摑 Resumen de sintaxis EJS para este tutorial

Lo que quieres hacerC贸digo EJS
Mostrar variable<%= variable %>
Ejecutar JavaScript (if, for, forEach)<% codigo %>
Abrir un bucle forEach<% entries.forEach(entry => { %>
Cerrar un bucle forEach<% }) %>
Condici贸n if<% if(condicion) { %> ... <% } %>
Condici贸n if-else<% if(condicion) { %> ... <% } else { %> ... <% } %>
Incluir otro archivo EJS<% include partials/nombre %>

✅ Verifica que todo funcione

Prueba 1: ¿Se ven los mensajes?
→ Deber铆as ver cada entrada dentro de un panel panel-primary

Prueba 2: ¿La fecha aparece?
→ Deber铆as ver la fecha y hora en la esquina superior derecha

Prueba 3: ¿Funciona cuando no hay entradas?
→ Deber铆as ver "No existen entradas" y un enlace para agregar


馃殌 Pr贸xima parte: Mejoras y persistencia

¿Quieres que continuemos con:

  • Parte 6: Guardar entradas en un archivo JSON (para no perder datos al reiniciar)

  • Parte 7: Agregar mensajes flash (notificaciones de "Guardado exitoso")

  • Parte 8: Editar y eliminar entradas

Comentarios

Entradas m谩s populares de este blog

C贸mo Iniciar un Proyecto Node.js

9-Nuestra Primera Plantilla con EJS

Lista de tareas-routing y plantillas