0

I am trying to create dynamic table based on input (number of rows and number of columns) with header, and store its value in list of dictionary variable where keys will be header data and values will be row data.

problem: My row part works fine, but when i try to have +1 row, which i want to consider for header, I am facing issue when my rowValue is more than 1 to understand better, follow the below sandbox link

https://codesandbox.io/s/serene-dhawan-6xod9?file=/src/demo.js

   // let rowVariable = 1;
    // rowVariable = rowValue + rowVariable
    let table = [];
    // Outer loop to create parent
     // for (let i = 0; i < rowVariable ; i++) { or
    // for (let i = 0; i < rowValue ; i++) {
    for (let i = 0; i < rowValue +1 ; i++) {

above for loop which is on line number 77 in sandbox, if i remove +1 from rowValue, code works fine for row part and i dont have any row for header, but with the +1 i get header(on default row) but when i increase the rowValue, I get multiple rows.

I am not able to debug what is causing this issue. Thanks for the HELP.

CODE:

import React, { Fragment, useState, useRef, useEffect } from "react";
// Material-ui imports
import { fade, withStyles } from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableContainer from "@material-ui/core/TableContainer";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import InputBase from "@material-ui/core/InputBase";
import TextField from "@material-ui/core/TextField";
const useStyles = makeStyles({
  table: {
    minWidth: 650
  }
});
const BootstrapInput = withStyles((theme) => ({
  root: {
    "label + &": {
      marginTop: theme.spacing(3)
    }
  },
  input: {
    borderRadius: 4,
    position: "relative",
    backgroundColor: theme.palette.common.white,
    border: "1px solid #ced4da",
    fontSize: 16,
    width: "60%",
    padding: "5px 6px",
    transition: theme.transitions.create(["border-color", "box-shadow"]),
    "&:focus": {
      boxShadow: `${fade(theme.palette.primary.main, 0.25)} 0 0 0 0.2rem`,
      borderColor: theme.palette.primary.main
    }
  }
}))(InputBase);

export default function DataTabelVariable(props) {
  // Table
  const classes = useStyles();
  const [rowValue, setRowValue] = useState(0);
  const [columnsValue, setColumnsValue] = useState(0);
  const [tableCellsData, setTableCellsData] = useState();
  const [tableArrayData] = useState([[]]);
  const ref = useRef(null);

  const getUniqueKeyFromArrayIndex = (rowNum, columnNum) => {
    return `${rowNum}-${columnNum}`;
  };

  const onChangeHandler = (e) => {
    setTableCellsData({
      ...tableCellsData,
      [e.target.name]: e.target.value
    });
    let [row, col] = e.target.name.split("-");
    row = parseInt(row);
    col = parseInt(col);

    if (!tableArrayData[row]) {
      tableArrayData[row] = [];
      tableArrayData[row].push([]);
    }
    tableArrayData[row][col] = e.target.value;
    props.value(tableArrayData);
  };

  const generateTable = () => {
    // let rowVariable = 1;
    // rowVariable = rowValue + rowVariable
    let table = [];
    // Outer loop to create parent
     // for (let i = 0; i < rowVariable ; i++) { or
    // for (let i = 0; i < rowValue ; i++) {
    for (let i = 0; i < rowValue +1 ; i++) {
      let children = [];
      //Inner loop to create children
      for (let j = 0; j < columnsValue; j++) {
        children.push(
          <td>
            <BootstrapInput
              name={getUniqueKeyFromArrayIndex(i, j)}
              onChange={onChangeHandler}
            />
          </td>
        );
      }
      table.push(
        <TableRow key={i}>
          <TableCell>{children}</TableCell>
        </TableRow>
      );
    }
    return table;
  };

  return (
    <Fragment>
      <div>
        <h5>Select Row number and Columns number</h5>
        <div className={"rowColumnsNumber"} style={{ marginTop: 20 }}>
          <TextField
            id="Row-number"
            label="Row(s)"
            type="number"
            InputLabelProps={{ shrink: true }}
            inputProps={{ min: "0", max: "1000", step: "1" }}
            onChange={(e) => setRowValue(e.target.value)}
            variant="outlined"
          />
          <TextField
            id="Columns-number"
            label="Columns(s)"
            type="number"
            inputProps={{ min: "0", max: "1000", step: "1" }}
            InputLabelProps={{ shrink: true }}
            onChange={(e) => setColumnsValue(e.target.value)}
            variant="outlined"
          />
        </div>
        <br />
        <div className={"TableContainer"}>
          <TableContainer component={Paper}>
            <Table className={classes.table} aria-label="simple table">
              <TableBody ref={ref}>{generateTable()}</TableBody>
              {/* <TableBody> {generateTable()}</TableBody> */}
            </Table>
          </TableContainer>
        </div>
      </div>
    </Fragment>
  );
}

1 Answer 1

1

In the above code you are setting the value of rowValue and columnsValue in lines 112 and 121 respectively as string not integer. The reason is e.target.value will give you a string like "1" not integer 1. Due to this the condition in for loop is true as it will compare the value of i with ASCII value of "1" (which is 49). So you have to convert the value of e.target.value to int using parseInt(e.target.value,10) and it will work as expected.

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.