0

The object:

let skillObj1 = {
      levels: [1, 4, 5, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 22, 25, 29, 30, 32, 34, 35, 38],
      skills: [['axe', 'dagger', 'flail', 'polearm', 'spear', 'sword', 'archery', 'whip', 'evaluation', 'enhanced damage', 'staff', 'parry', 'rescue', 'recall'], ['dirt kicking'], ['hand to hand', 'second attack'],
      ['fast healing'], ['kick'], ['trip'], ['shield block'], ['dual wield', 'bash'], ['dodge'], ['haggle', 'lunge'], ['lash', 'disarm'], ['crush', 'warcry', 'meditation'],
      ['shield cleave', 'berserk'], ['third attack'], ['recovery'], ['dual parry', 'pugil'], ['counter'], ['ground control', 'defend'],
      ['fourth attack'], ['battle tactics'], ['enhanced damage II'], ['enlist'], ['block retreat']]
    };

The loop I'd like to be using, but obviously is incorrect:

tableData(props) {
    let data = '';
    for (var i = 0; i < this.props.levels.length; i++) {
      data.concat('<tr><td>Level ' + props.levels[i] + '</td>');
      for (var j = 0; j < props.skills[i].length; j++) {

        if (j % 2 === 0) {
          data.concat('<td>' + props.skills[i][j] + '</td</tr>');
          if (j !== props.skills[i].length - 1) { data.concat('<tr><td></td>');}
        } else {
          data.concat('<td>' + props.skills[i][j] + '</td>');
          if (j === props.skills[i].length - 1) {data.concat('<td></td></tr>');}
        }

      }
    }
    return data;
  };

My Render:

render() {
  return (
    <Table striped bordered hover variant="dark">
      <thead>
        <tr>
          <th><strong>Your list of skills:</strong></th>
          <th></th>
          <th></th>
        </tr>
      </thead>
      <tbody>
      {this.tableData}
      </tbody>
    </Table>
  );
  }

What I'm trying to accomplish:

I want to make a table with 3 columns, so 3 <td> per row. In the first <td> will be the level that the ability is gained. That will only be shown in the first row where the abilities for that level begin. All consecutive rows will have the first <td> blank until reaching the next level's entries. The actual abilities will be in only the 2nd and 3rd columns/ <td>s.

Kinda like this, sorry if it's a bad example:

|-----|-----|-----|
|Lvl1 | axe |sword|
|-----|flail|-----|
|Lvl2 |kick |trip |
|-----|punch|smell|
|-----|slap |-----|
|Lvl5 |-----|-----|

Edit:

I am seeing a lot of people using the .map() and .filter() methods to handle similar things, but my problem is that I have several conditions that I'm not sure how to handle.

If I try to just print an array of <td> it works fine with .map() but either my JavaScript/jsx skill is just really bad right now, or there's a better way to deal with the conditions so it prints in the format I'm looking for.

Edit2

Now I'm attempting to get something like this to work in the render:

let levels = this.props.skills.levels;
let skills = this.props.skills.skills;
{levels.map(function(obj, i) {
    return (
        <tr><td>Level {obj}</td>
        skills[i].map(function(obj2, j) {
            if (j % 2 === 0) {
                <TableData skill={obj2[i][j]} /></tr>
                if (j !== obj2[i].length - 1) { <tr><TableData /> }
            } else {
                <TableData skill={obj2[i][j]} /></td>;
                if (j === props.skills[i].length - 1) {<TableData /></tr>}
            }
        });
    )
)}

Edit 3

I thought perhaps a ternary operator might be appropriate. I'm still getting a lot of jsx errors because the jsx elements are not closed "properly" even though the purpose of the operator is to close them.

{levels.map(function(obj, i) {
    return (<tr><td>Level {obj}</td>
            skills[i].map(function(obj2, j) {
              (j % 2 === 0) ?
                (j !== obj2[i][j].length - 1) ? (<TableData skill={obj2[i][j]} /></tr><tr><TableData />) : (<TableData skill={obj2[i][j]} /></tr>)
                : (j === obj2[i].length - 1) ? (<TableData skill={obj2[i][j]} /></td><TableData /></tr>) : (<TableData skill={obj2[i][j]} /></td>);
            });
          )
  )}

Edit 4 Getting Closer

  tableData(props) {
    let levels = this.props.skills.levels;
    let skills = this.props.skills.skills;
    let data = [];
for (var i = 0; i < levels.length; i++) {
      //<tr>beginning
      data.push(<Level level={i} key={i * 100} />);
      for (var j = 0; j <= skills[i].length; j++) {

        if (j % 2 === 0) {
          data.push(<TableData skill={skills[i][j]} key={i + j} />); //</tr> end
          if (j !== skills[i].length - 1) { data.push(<TableData key={(i + j) * 200} />);}//<tr> beginning
        } else {
          data.push(<TableData skill={skills[i][j]} key={i + j} />);
          if (j === skills[i].length - 1) {data.push(<TableData key={(i + j) * 100} />)} //</tr> end
        }

      }
    }
    return data;
  };

With this function, I am able to print everything in table data tags. However, I still can't place the table row tags where they need to go. If I don't close the tags I get a jsx error even if the end result theoretically should be correct.

8
  • Is each array in skills supposed to go with the level? Commented Sep 6, 2020 at 0:23
  • @Yatrix Yes, the index of each level corresponds to the index of the array inside the skills array. So level 1 at index 0 corresponds to ['axe', 'dagger', 'flail',...] which is also index 0 of skills. Commented Sep 6, 2020 at 0:39
  • So in the first <td> is the lvl, in the second td there are the skills but what should be in the third td ? Commented Sep 6, 2020 at 1:06
  • 1
    Something like that codesandbox.io/s/headless-cdn-vgqfx ? Commented Sep 6, 2020 at 1:43
  • 1
    Happy if I could help :). I posted my answer, so you'll can mark it as a solution Commented Sep 6, 2020 at 2:16

1 Answer 1

1

In my opinion the best way is to structure the data first and render it later, so you dont have to mess around with closing tags etc. You could use a for loop and iterate over every 2 item to create the table.

<div className="App">
      <table>
        <tbody>
          {levels.map((item, i) => {
            var skl = [];
            for (let j = 0; j < skills[i].length; j = j + 2) {
              if (j < 2) {
                skl.push(
                  <tr>
                    <td>Level {item}</td>
                    <td>{skills[i][0]}</td>
                    <td>{skills[i][1]}</td>
                  </tr>
                );
              } else {
                skl.push(
                  <tr>
                    <td></td>
                    <td>{skills[i][j]}</td>
                    <td>{skills[i][j + 1]}</td>
                  </tr>
                );
              }
            }
            return (
              <React.Fragment>
                {skl.map((item) => {
                  return item;
                })}
              </React.Fragment>
            );
          })}
        </tbody>
      </table>
    </div>

https://codesandbox.io/s/headless-cdn-vgqfx

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

Comments

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.