1

I try to make function that get an array of object and according to object in the array generate a table with dynamic rowspan. I tried many solutions but none of them helped.

I tried this code,but I did not continue it because the beginning did not work well

 const returnTabel = state => {
return state.map((item, index) => {
  return (
    <tr key={index}>
      {Object.keys(item).map((key, index) => {
        if (Array.isArray(item[key])) {
          return item[key].map((object, index) => {
            return Object.keys(object).map((i, index) => {
              if (Array.isArray(object[i])) {
              } else {
                return (
                  <tr>
                    <td>{object[i]}</td>
                  </tr>
                );
              }
            });
          });
        } else {
          return (
            <td rowSpan={2} key={index}>
              {item[key]}
            </td>
          );
        }
      })}
    </tr>
  );
});};

Here is my data:

 const state = [
{
  name: 'Bill',
  info: [
    {
      hobby: 'Practice',
      field: [
        { type: 'Swim', hours: '6' },
        { type: 'Run', hours: '7' }
      ]
    },
    {
      hobby: 'Listen to music',
      field: [
        { type: 'Jazz', hours: '3' },
        { type: 'Electronic music', hours: '3' },
        { type: 'Hip hop', hours: '3' }
      ]
    }
  ],
  student: 'No'
},
{
  name: 'John',
  info: [
    {
      hobby: 'Practice',
      field: [
        { type: 'Swim', hours: '1' },
        { type: 'Run', hours: '2' }
      ]
    }
  ],
  student: 'Yes'
}]

I want to make this table with my data

enter image description here

3
  • 2
    tried many solutions. Could you show us? Commented May 8, 2021 at 12:29
  • @Keith I added.But it does not really work .. Commented May 8, 2021 at 12:45
  • Best suggestion is treat this as an array mapping exercise outside of React. Then once you can map it in javascript alone pass it to the react render Commented May 8, 2021 at 12:55

1 Answer 1

1

You can simplify the render mapping if you map the data to rows that look like:

[{"txt":"Bill","rowSpan":5},{"txt":"Practice","rowSpan":2},{"txt":"Swim"},{"txt":"6"},{"txt":"No","rowSpan":5}]
//OR
[null,{"txt":"Listen to music","rowSpan":3},{"txt":"Jazz"},{"txt":"3"},null]
//OR
[null,null,{"txt":"Run"},{"txt":"7"},null]

Then the render simplifies down to:

  return (
    <table border="1">
      {rows.map(cells =>  (
          <tr>
            {cells.map(cell => cell && <td rowSpan={cell.rowSpan}>{cell.txt}</td>)}
          </tr>
        )
      )}
    </table>
  );

Working example

const data=[{name:"Bill",info:[{hobby:"Practice",field:[{type:"Swim",hours:"6"},{type:"Run",hours:"7"}]},{hobby:"Listen to music",field:[{type:"Jazz",hours:"3"},{type:"Electronic music",hours:"3"},{type:"Hip hop",hours:"3"}]}],student:"No"},{name:"John",info:[{hobby:"Practice",field:[{type:"Swim",hours:"1"},{type:"Run",hours:"2"}]}],student:"Yes"}];

const rowData = data.reduce((a, { name, info, student }) => {
  const rowSpan = info.reduce((a, { field }) => a + field.length, 0);

  let [firstCell, lastCell] = [name, student].map(txt => ({ txt, rowSpan }));

  info.forEach(({ hobby, field }, i) => {
    const rowSpan = field.length;

    let hobCell = { txt: hobby, rowSpan };

    field.forEach((f, j) => {
      const fieldCells = Object.values(f).map(txt => ({ txt }));

      if (j > 0) {
        hobCell = firstCell = lastCell = null;
      }
      const row = [firstCell, hobCell, ...fieldCells, lastCell];
      a.push(row);
    });
  });

  return a;
}, []);

console.log( rowData)

const Table = () => {
  const [rows] = React.useState(rowData);

  return (
    <table border="1">
      {rows.map((cells,i) =>  (
          <tr key={i}>
            {cells.map((cell,j) => cell && <td key={`${i}-${j}`} rowSpan={cell.rowSpan}>{cell.txt}</td>)}
          </tr>
        )
      )}
    </table>
  );
};
// Render it
ReactDOM.render(
  <Table />,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Sign up to request clarification or add additional context in comments.

3 Comments

All the point that the information appears in the table together will be found as one object ..
I mean that all the information that appears in the table as a single row that splits into several rows should appear as an object in the array I receive
I still don't understand the problem. If you need to edit or something you can include indexing detail in the rows objects that make it simple to use find() on the master data

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.