Renan Mougenot
Renan Mougenot

Reputation: 13

Rendering and Grouping using React Tables

I am creating a dynamic table using react based on objects.

The problem is that I am trying to render a new row for every three TD, but instead it is rendering all TDs in the same table row (tr).

How can I separate the TDs into az new TR after a group of 3 TDs have been filled?

Here is my code:

Component rendering table:

`export class Roster extends React.Component{

render(){
    return(
        <div id="tab">
            <table >
                <tbody>
                    <tr>
                        <td colSpan={3}>
                            <h4>Goalkeepers</h4>
                        </td>
                    </tr>
                </tbody>

                <Goalies/>
        </div>
    )
}

}`

Component looping through object:

`class Goalies extends React.Component{

getTable() {
    let td_array = [];
    let goal_object = {};

    Object.keys(goalies).forEach(function(key) {
        goal_object = (goalies[key]);
      });

    for(const checker in goal_object){
        td_array.push(<td key={checker}>{goal_object[checker].p_name} <br/> {goal_object[checker].city} <br/> {goal_object[checker].number}</td>);
    }

    return(
        <tr>
            {td_array}
        </tr>
    )
}

  render() {
    return (<tbody>{this.getTable()}</tbody>)
  }

}`

Objects:

export const def = { 1:{ p_name:"p1", number: 2, city: "city1" },

2:{
    p_name:"p2",
    number: 5,
    city: "city2"
},

3:{
    p_name:"p3",
    number: 3,
    city: "city3"
},

4:{
    p_name:"p4",
    number: 7,
    city: "city4"
},

5:{
    p_name:"p5",
    number: 15,
    city: "city5"
},

6:{
    p_name:"p6",
    number: 21,
    city: "city6"
}

}

I want to get:

td1 td2 td3
td4 td5 td6

instead, I am getting:

td1 td2 td3 td4 td5 td6

I tried using conditional statements, pushing into a new array...

Upvotes: 0

Views: 691

Answers (1)

tao
tao

Reputation: 90217

In order to achieve the layout you're after, the correct HTML markup would look like this:

<table>
  <thead>
    <tr>
      <th colspan="3">
        <h4>Goalkeepers</h4>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>td1</td>
      <td>td2</td>
      <td>td3</td>
    </tr>
    <tr>
      <td>td4</td>
      <td>td5</td>
      <td>td6</td>
    </tr>
  </tbody>
</table>

First, you'll want to group your items into arrays of n (3 in your case). I'd use a generator function:

function* toChunks(arr, n) {
  for (let i = 0; i < arr.length; i += n) {
    yield arr.slice(i, i + n)
  }
}
const rows = [...toChunks(items, 3)]

As an alternative, you could also use:

const chunk = (arr, n) =>
  [...Array.from({ length: Math.ceil(arr.length / n) }).keys()].map((key) =>
    arr.slice(key * n, (key + 1) * n)
  )
const rows = chunk(items, 3)

Given the above rows, your component would look like this:

const Goalies = ({ rows }) => (
  <tbody>
    {rows.map((row, rk) => (
      <tr key={rk}>
        {row.map((cell, ck) => (
          <td key={ck}>{cell.number}</td>
        ))}
      </tr>
    ))}
  </tbody>
)

Demo here


However, by looking at your data I think you shouldn't be using a <table> here at all. The layout you're after could easier be achieved with:

const Cells = ({ items }) => (
  <div className="myWrapper">
    {items.map((item, key) => (
      <div key={key}>{item.number}</div>
    ))}
  </div>
)

along with any of the following CSS models:

.myWrapper {
  display: flex;
  flex-wrap: wrap;
}
.myWrapper > * {
  width: calc(100%/3)
}

/* or alternatively: */
.myWrapper {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr))
}

Upvotes: 0

Related Questions