TransWikia.com

¿Cómo puedo dibujar un arreglo como una tabla en javascript?

Stack Overflow en español Asked by Ray on December 6, 2020

Tengo el siguiente arreglo

const arr = ['t1', 't2', 't3', 't4', 't5', 't6', 't7','t8','t9'];

Quisiera mostrarlo de la siguiente manera, es decir, limitarlo a 4 columnas y N filas:

table {
  font-family: 'Verdana';
  padding: 25px;
}

td {
  border: 2px solid rgba(0, 0, 0, 0.08);
  color: rgba(0, 0, 0, 0.6);
  padding: 25px;
}
<table>
  <tbody>
    <tr>
      <td>t1</td>
      <td>t2</td>
      <td>t3</td>
      <td>t4</td>
    </tr>
    <tr>
      <td>t5</td>
      <td>t6</td>
      <td>t7</td>
      <td>t8</td>
    </tr>
    <tr>
      <td>t8</td>
    </tr>
  </tbody>
</table>

Estoy intentando esto pero lo que sucede es que me repite un montón de veces los elementos y no logro solucionarlo:

let cols = 4;
const arr = ['t1', 't2', 't3', 't4', 't5', 't6', 't7','t8','t9'];
const tBody = document.getElementById('table-content');


arr.forEach((row) => {
  let i = 0;
  const itemsToRender = arr.slice(i, cols);
  
  if (i === 0) {
      i = cols;
  } else {
      cols *= 2;
      i = cols / 2;
  }
    
  const newRow = tBody.insertRow();
  
  itemsToRender.forEach((col, index) => {
    const newCell = newRow.insertCell(index);
    const cellValue =  document.createTextNode(row);
    newCell.appendChild(cellValue);
  });
  
});
table {
  font-family: 'Verdana';
  padding: 25px;
}

td {
  border: 2px solid rgba(0, 0, 0, 0.08);
  color: rgba(0, 0, 0, 0.6);
  padding: 25px;
}
<table>
  <tbody id="table-content">
  </tbody>
</table>

2 Answers

Intentando con métodos de arreglos:

Al final, resultó más simple de lo que esperaba, como se está recorriendo el arreglo, elemento por elemento, no es necesario crear subarreglos, simplemente analizar en qué momento es necesario crear una fila.

O bien, se puede hacer un ciclo por filas a crear, usando arr.slice() para obtener los elementos correspondientes.

Nota: Revisa los comentarios al final del código javascript, son solo funciones de arreglos; un poco complicada la forma de obtener los fragmentos (chunks), pero se aplica la misma idea del ejemplo previo... en una sola línea.

const cols = 4;
const arr = ['t1', 't2', 't3', 't4', 't5', 't6', 't7','t8','t9'];
const tBody = document.getElementById('table-content');

// Contador de celdas y elemento de nueva fila
// se deben declarar fuera del ciclo
// para no sobrescribir en cada iteración
let col;
let newRow;
arr.forEach((row, index) => {
  // Crear fila al empezar
  // o cuando se completaron las columnas
  if(index == 0 || (col % cols) === 0) {
      newRow = tBody.insertRow();
      // Reiniciar contador de celdas
      col = 0;
  }
  const newCell = newRow.insertCell(col);
  newCell.innerText = row;
  col ++;  
});

// Otra opción, contando filas y usando array.slice
// Saber cuántas filas se van a mostrar
const rows = Math.ceil(arr.length / cols);
const tBody2 = document.querySelector('#table-content2');
for(let row = 0; row < rows; row ++) {
    let slc = row * cols;
    // Slice requiere posición inicial y final
    items = arr.slice(slc, slc + cols);
    newRow = tBody2.insertRow();
    items.forEach((item, col) => {
        const newCell = newRow.insertCell(col);
        newCell.innerText = item;
    });
}

// new Array - Arreglo con cantidad de filas necesarias
// .fill() - Inicializa cada fila
// .map() - Recorre cada "fila" y llena desde arreglo original
const chunks = new Array(Math.ceil(arr.length / cols)).fill().map((_, i) => arr.slice(i * cols, i * cols + cols));
console.log(chunks);

// Puedes recorrer chunks como filas:
chunks.forEach(items => {
    // Aquí agregas la fila
    // Recorres items para crear celdas
    items.forEach((item, col) => {
        // Aquí creas cada celda
    });
});
table {
  font-family: 'Verdana';
  padding: 25px;
}

td {
  border: 2px solid rgba(0, 0, 0, 0.08);
  color: rgba(0, 0, 0, 0.6);
  padding: 25px;
}
<table>
  <tbody id="table-content">
  </tbody>
</table>

<p>Llenar con array.slice()</p>
<table>
  <tbody id="table-content2">
  </tbody>
</table>

En lugar de recorrer el arreglo, es más fácil calcular cuántas filas se van a crear y hacer dos ciclos, uno para filas y otro para celdas, actualizando el índice cada que se crea una nueva celda.

let cols = 4;
const arr = ['t1', 't2', 't3', 't4', 't5', 't6', 't7','t8','t9'];
const tBody = document.getElementById('table-content');

// Obtener total de filas
let rows = Math.ceil(arr.length / cols);
// Iniciar con primer elemento
let index = 0;

// Ciclo para filas
for(let row = 0; row < rows; row++) {
    // Crear fila
    const newRow = tBody.insertRow();
    // Ciclo para columnas
    for(let col = 0; col < cols; col++) {
        // ¿Llegamos al final de arreglo?
        if(index >= arr.length) {
            // Fin del ciclo
            break;
        }
        // Crear celda
        const newCell = newRow.insertCell(col);
        newCell.innerText = arr[index];
        index ++;
    }
}
table {
  font-family: 'Verdana';
  padding: 25px;
}

td {
  border: 2px solid rgba(0, 0, 0, 0.08);
  color: rgba(0, 0, 0, 0.6);
  padding: 25px;
}
<table>
  <tbody id="table-content">
  </tbody>
</table>

Correct answer by Triby on December 6, 2020

Una solución más simple y elegante es hacer uso de recursión. De esta manera llamas la funcion con una versión más acotada del arreglo hasta que no haya elementos en el:

// Arreglo inicial
const arr = ["t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"];

// Elemento DOM donde van los resultados
const tbody = document.querySelector("tbody");


// Parametros: arreglo, cantidad de columnas y elemento DOM destino
function sliceAndDsiplay(arr, cols, targetElement) {
  if (arr.length === 0) {
    return arr;
  }

  const tr = document.createElement("tr");
  arr.slice(0, cols).forEach(item => {
    const td = document.createElement("td");
    td.textContent = item;
    tr.append(td);
  });
  targetElement.append(tr);
  
  // Llamada recursiva
  return sliceAndDsiplay(arr.slice(cols), cols, targetElement);
}

sliceAndDsiplay(arr, 4, tbody);
table {
  font-family: 'Verdana';
  padding: 25px;
}

td {
  border: 2px solid rgba(0, 0, 0, 0.08);
  color: rgba(0, 0, 0, 0.6);
  padding: 25px;
}
<table>
  <tbody>
  </tbody>
</table>

Answered by Juan Marco on December 6, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP