skip to Main Content

I have a below input with nested array of objects.

summary is parent array of objects and run_type is nested one.

let input = {
      "summary": [
          {
              "name": "Release",
              "run_type": [
                {
                  "environment": "6nc",
                  "type": "QA1"
                },
                {
                  "environment": "3nc",
                  "type": "QA2"
                }
              ]
          }
      ]
  }

I want to display a table like this. Name field has rowspan of 2 since there are 2 run_type for each summary

------------------------------------
   Name    | Environment | RunType |
------------------------------------
  Release  |     6nc     |  QA1    |
           |     3nc     |  QA2    |
------------------------------------

To display a table like this statically, i can do this way

<table>
  <thead>
    <tr>
      <th>Vertical</th>
      <th>Environment</th>
      <th>RunType</th>
    </tr>
  </thead>
  <tbody>
  <tr>
    <td rowspan="2">Release</td>
    <td>6nc</td>
    <td>QA1</td>
  </tr>
  <tr>
    <td>3nc</td>
   <td>QA2</td>
  </tr>
  </tbody>
</table>

can someone please let me know how to dynamically show this table. I tried using this way but was unsuccessful. the problem is that i am able to rowspan Name column into 2 rows but all other columns are not being placed as two rows within that same Name section

<table>
  <thead>
    <tr>
      <th>Vertical</th>
      <th>Environment</th>
      <th>RunType</th>
    </tr>
  </thead>
  <tbody>
     {input?.summary?.map((project, indx) => {
       return (
         <tr>
           <td rowspan="2">{project?.name}</td>
             {project?.run_type?.map((runType, indx) => {
                return (
                  <>
                    <td>{runType.environment}</td>
                    <td>{runType.type}</td>
                  </>
                );
             })}
         </tr>
       );
     })}
  </tbody>
</table>

3

Answers


  1. You need a <tr> per run_type, so the inner loop should generate the <tr>, not the outer. As the <td> with rowspan should only be created for the first row of the project, use a conditional expression with indx==0 to generate it:

    input.summary?.map((project) =>
        project.run_type?.map((runType, indx, {length}) =>
            <tr>
               {indx == 0 ? <td rowspan={length}>{project.name}</td> : ''}
               <td>{runType.environment}</td>
               <td>{runType.type}</td>
            </tr>
        )
    )
    
    Login or Signup to reply.
  2. The problem arises from the fact that you’re using a single <tr> element to iterate through both the run_type environments and types. This leads to an incorrect rendering of the table structure.

    Here’s how you can modify your code to achieve this:

      <tbody>
        {input?.summary?.map((project, projectIndex) => (
          <>
            {project?.run_type?.map((runType, runTypeIndex) => (
              <tr key={`${projectIndex}-${runTypeIndex}`}>
                {runTypeIndex === 0 ? (
                  <td rowspan={project.run_type.length}>{project.name}</td>
                ) : null}
                <td>{runType.environment}</td>
                <td>{runType.type}</td>
              </tr>
            ))}
          </>
        ))}
      </tbody>
    
    Login or Signup to reply.
  3. I would transform the data into a matrix of text and row-span information first.

    Now you can use the matrix to just render the <tbody>.

    let input = {
      "summary": [{
        "name": "Release",
        "run_type": [{
          "environment": "6nc",
          "type": "QA1"
        }, {
          "environment": "3nc",
          "type": "QA2"
        }]
      }]
    };
    
    const tableData = input.summary.flatMap(({ name, run_type }) => {
      return run_type.map(({ environment, type }, index) => {
        const row = [];
        if (index === 0) {
          row.push({ text: name, rowSpan: run_type.length });
        }
        row.push({ text: environment });
        row.push({ text: type });
        return row;
      });
    });
    
    document.querySelector('.data tbody').insertAdjacentHTML('afterbegin', `
      ${tableData.map(row =>
        `<tr>${row.map(col =>
          `<td rowSpan=${col.rowSpan ?? 1}>${col.text}</td>`)
        .join('')}</tr>`)
      .join('')}
    `);
    table.data {
      border-collapse: collapse;
    }
    
    table.data, .data th, .data td {
      border: thin solid grey;
    }
    
    .data th, .data td {
      padding: 0.5rem;
    }
    
    .data th {
      background: rgba(0, 0, 0, 0.125);
    }
    <table class="data">
      <thead>
        <tr>
          <th>Name</th>
          <th>Environment</th>
          <th>RunType</th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search