Задать вопрос
@supeeeee_r_man
Начинающий веб-разработчик

Как вывести вложенные данные в виде таблицы с объединёнными ячейками?

Есть массив следующего вида:
"clouds": [{
      "cloud": "cloud",
      "shards": [{
          "repository_size_gb": 3071,
          "repository": "VBR",
          "jobs": [{
              "job": "VBR1",
              "job_description": "Каждый день инкремент, хранить 6 точек",
              "backup_name": "VBR-NORD-152-Getblogger01",
              "backup_size_gb": 616,
            },{
              "job": "VBR2",
              "job_description": "Каждый день инкремент, хранить 6 точек",
              "backup_name": "VBR-NORD-152-Getblogger01",
              "backup_size_gb": 616,
            },{
              "job": "VBR3",
              "job_description": "Каждый день инкремент, хранить 6 точек",
              "backup_name": "VBR-NORD-152-Getblogger01",
              "backup_size_gb": 616,
            }]
        }]
    }]

Надо отобразить его содержимое в виде таблицы:

2iIdB.png
Всё, что пришло в голову на данный момент - это:

return (
  <table>
    <tbody>
      <tr>
        {header.map((el, i) => <th key={i}> <FormattedMessage id={el.title}/> </th>)}
      </tr>
    </tbody>
    <tbody>
      {this.props['vmBackup'].map((el, i) => (
        <tr key={i}>
          {header.map((col, j) => (
            <td className={col.right ? cellClsRight : cellCls} key={i + ':' + j}>
              <span> {el[col.col]} </span>
            </td>
          ))}
        </tr>
      ))}
    </tbody>
  </table>
)

И выводится:

7xDpM.png
  • Вопрос задан
  • 3102 просмотра
Подписаться 6 Простой 3 комментария
Помогут разобраться в теме Все курсы
  • Нетология
    Frontend-разработка на React
    10 недель
    Далее
  • Академия Эдюсон
    React-разработчик + ИИ
    2 месяца
    Далее
  • Яндекс Практикум
    React-разработчик
    3 месяца
    Далее
Решения вопроса 1
0xD34F
@0xD34F Куратор тега React
Вариант раз - для обработки каждого из уровней вложенности пишем отдельный цикл, объединённые ячейки создаются в зависимости от равенства индексов элементов вложенных массивов нулю:

const tableData = useMemo(() => (
  DATA.flatMap(({ cloud, shards }) =>
  shards.flatMap((shard, iShard) =>
  shard.jobs.map((job, iJob) => [
    {
      rowspan: !iShard && !iJob && shards.reduce((acc, n) => acc + n.jobs.length, 0),
      text: cloud,
    },
    {
      rowspan: !iJob && shard.jobs.length,
      text: shard.repository,
    },
    {
      rowspan: !iJob && shard.jobs.length,
      text: shard.repository_size_gb,
    },
    { text: job.job },
    { text: job.job_description },
    { text: job.backup_name },
    { text: job.backup_size_gb },
  ])))
), [ DATA ]);

<tbody>{tableData.map(row => (
  <tr>{row.map(({ text, rowspan }) => (rowspan !== false &&
    <td rowSpan={rowspan}>
      {text}
    </td>))}
  </tr>))}
</tbody>

Вариант два - в описания столбцов, после которых строка таблицы должна разделиться, добавляем свойство, указывающее откуда брать вложенные данные, получаем их посредством рекурсии:

const tableData = useMemo(() => (
  (function createTableData(arr, iCol) {
    return arr.flatMap(n => {
      const row = [];

      for (let i = iCol; i < HEADERS.length; i++) {
        const header = HEADERS[i];

        row.push({ text: n[header.key] });

        if (header.split) {
          const innerRows = createTableData(n[header.split], i + 1);
          row.forEach(cell => cell.rowspan = innerRows.length);
          return [ row.concat(innerRows.shift()), ...innerRows ];
        }
      }

      return [ row ];
    });
  })(DATA, 0)
), [ DATA, HEADERS ]);

<tbody>{tableData.map(row => (
  <tr>{row.map(({ text, rowspan }) => (
    <td rowSpan={rowspan}>
      {text}
    </td>))}
  </tr>))}
</tbody>
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 4
miraage
@miraage
Старый прогер
- напишите функцию, которая перегонит данную структуру в нормальную матрицу
- отрендерите простую таблицу без лишней логики
- оберните транфсормацию в useMemo, если будут проседания по производительности (optional)

Посыл в том, что UI layer не должен страдать из-за того, что данные не в том формате.
Ответ написан
@szubtsovskiy
Вам поможет rowSpan. В примере я засунул данные в state, но вы продолжайте брать из props:

render() {
    return (
      <table>
        <tbody>
          <tr>
            {new Array(8).fill(0).map((el, i) => <th key={i}>TEXT</th>)}
          </tr>
        </tbody>
        <tbody>
          {this.state['vmBackup']['clouds'].flatMap(cloud => {
            return cloud.shards.map(shard => {
              const jobCount = shard['jobs'].length;
              return shard['jobs'].map((job, i) => {
                if (i == 0) {
                  return (
                    <tr key={i}>
                      <td rowSpan={jobCount}>{cloud['cloud']}</td>
                      <td rowSpan={jobCount}>{shard['repository']}</td>
                      <td rowSpan={jobCount}>{shard['repository_size_gb']}</td>
                      <td>{job['job']}</td>
                      <td>{job['job_description']}</td>
                      <td>{job['backup_name']}</td>
                      <td>{job['backup_size_gb']}</td>
                      <td>5</td>
                    </tr>
                  )
                } else {
                  return (
                    <tr key={i}>
                      <td>{job['job']}</td>
                      <td>{job['job_description']}</td>
                      <td>{job['backup_name']}</td>
                      <td>{job['backup_size_gb']}</td>
                      <td>5</td>
                    </tr>
                  )
                }              	
              })
            })
          })}
        </tbody>
      </table>
    )
  }
Ответ написан
mrerberg
@mrerberg
Yep
Можно воспользоваться <template>. Создаете 'компонент', потом уже с помощью js подставляете данные
Ответ написан
Комментировать
@AShvejnov
Есть куча готовых jQuery плагинов/компонентов, которые рисуют всевозможные таблички. Большинство из них как раз на входе умеют принимать данные в JSON-е, то бишь, в виде массива как у вас. Поищите просто наиболее подходящее готовое решение (гугл -> "jQuery data grids") и не тратьте время на изобретение велосипеда.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы