0

I'm getting data from backend in a dynamic manner which is based in user selection. Now, I need to display that data in the table. Can anyone help me with it?

For ex : I will get data like this from backend for the first time when user selects only 2 fields

{
 "result":[
  {
   "c3":"test_customer1",
   "penddel":"3029"
  },
  {
   "c3":"test_customer2",
   "penddel":"7976"
  },     
 ]
}

And when second time when user selects more fields data comes for that fields For ex:

{
 "result":[
  {
   "c3":"test_customer1",
   "penddel":"3029"
   "c5":"testc1"
  },
  {
   "c3":"test_customer2",
   "penddel":"7976"
   "c5":"testc2"
  },     
 ]
}

So everytime data comes based on the user selection of fields, need to display this data dynamically in table

4 Answers 4

4

You can fetch the data as normal and then just use object keys to pull the headings from the result.

We can then use this array to render the table headings.

Once the table headings are rendered we can then map the data and iterate through each item whilst mapping the previous heading array to render each value.

Using React Class API

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      data: null,
    };
    
    this.fetchData = this.fetchData.bind(this);
  }
  
  componentDidMount() {
    this.fetchData();
  }
  
  fetchData() {
    return new Promise(resolve => resolve({
      "result": [{
          "id": "1",
          "name": "john",
          "age": "35"
        },
        {
          "id": "2",
          "name": "johnson",
          "age": "25"
        }
      ]
    })).then((response) => {
      this.setState({ data: response.result });
    });
  }
  
  render() {
    const { data } = this.state;

    if (!data) {
      return <div>Loading...</div>;
    }

    const headings = Object.keys(data[0]);
    
    return (
      <table className="table">
        <thead className="thead-dark">
          <tr>
            {headings.map((heading) => <th>{heading}</th>)}
          </tr>
        </thead>
        <tbody>
          {data.map((row) => (
            <tr>
              {headings.map((heading) => <td>{row[heading]}</td>)}
            </tr>
          ))}
        </tbody>
      </table>
    );
  }
};

ReactDOM.render(
  <App /> ,
  document.getElementById('root')
);
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" />
<div id="root" class="p-3"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>

Using React Functional Component + React Hooks

const App = () => {
  const [data, setData] = React.useState(null);

  React.useEffect(() => {
    const fetch = () => {
      return new Promise(resolve => resolve({
        "result": [{
            "id": "1",
            "name": "john",
            "age": "35"
          },
          {
            "id": "2",
            "name": "johnson",
            "age": "25"
          }
        ]
      })).then((response) => {
        setData(response.result);
      });
    };
    
    fetch();
  }, []);
  
  if (!data) {
    return <div>Loading...</div>;
  }

  const headings = Object.keys(data[0]);

  return (
    <table className="table">
      <thead className="thead-dark">
        <tr>
          {headings.map((heading) => <th>{heading}</th>)}
        </tr>
      </thead>
      <tbody>
        {data.map((row) => (
          <tr>
            {headings.map((heading) => <td>{row[heading]}</td>)}
          </tr>
        ))}
      </tbody>
    </table>
  );
};

ReactDOM.render(
  <App /> ,
  document.getElementById('root')
);
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" />
<div id="root" class="p-3"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>

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

9 Comments

Is there a way to write this without using hooks as I'm not using hooks in my project. It is throwing error Hooks can only be used inside of the body of the function component.
@Kalyan Updated the solution with an example using the React Class API
[1]: i.sstatic.net/xdggE.png I made changes accordingly,this is how i am getting the data..
@Kalyan Please update your question with a JSON representation of the data you fed to the code.
I have updated the JSON according to the screenshot. Please check it and also do you know the reason why I'm getting data like in the screenshoot I pasted above.
|
2

You will probably want to store the object you are getting from your backend in a useState hook. You will also want to track how many fields the user has selected with a useState hook. Something like this:

const [data, setData] = useState(null); // no initial data
const [fields, setFields] = useState(2); // 2 initial fields selected

Now you can update the fields state with a method within your function that gets called every time the value changes. Then you want to query your backend with a useEffect hook and pass in the new field value from the backend.

const updateFields = (event) => {
  setFields(event.target.value);
}

useEffect(() => {
  axios.get(`backend/api/?fields=${fields}`)
    .then(res => {
      setData(res.body);
    })
});

As per the comment, if you're not using hooks, you can use ComponentDidMount instead of useEffect and create a similar update method.

const updateFields = (event) => {
  this.setState({ fields: event.target.value });
}

componentDidMount() {
  axios.get(`backend/api/?fields=${fields}`)
    .then(res => {
      this.setState({ data:  res.data });
  })
}

Now you can return JSX that has a field to set the field number as well as map through the data object to set a dynamic table of values. If you're not using hooks, place the this keyword to reference state (i.e. this.data instead of data).

return (
  <input onChange={(e) => updateFields(e)} />

  <table>
    <thead>
      {Object.keys(data[0]).map((el) => {
        <th key={el}>{el}</th>
      })
    </thead>
    <tbody>
      {data.map((el, i) => {
        {Object.keys(data[i]).map((elKey) => <td key={elKey}>{el[elKey]}</td>)}
      }
    </tbody>
  </table>
</div>
);

These are two great resources for understanding more about querying data:

https://reactjs.org/docs/hooks-effect.html

https://alligator.io/react/axios-react/

And this is a good resource for understanding more about mapping over objects in React:

https://reactjs.org/docs/lists-and-keys.html

3 Comments

Is there a way to do it without using hooks as I'm not using it in my project. If I write this using hooks I need to change the code I already wrote. I'm using class and state variables
@Kalyan I updated the code for without hooks. I am assuming you already have state variables declared, so I did not update the initial hooks code snippet.
I have update the code as per your answer, now getting table heading & data but there is a problem like under one heading column the entire table data is coming and other headings don't have any data. Please check the below link...
0

How about conditionally rendering the cells? Like:

data.map(item => (
    {item.age? <td>{item.age}</td>: null}
))

1 Comment

everytime the data which comes changes based on the user input so I can't use the above stated
0

Every time user selects fields, store the field name in a variable. Ex:

const Header = [{"title":"Name","index":"name"}]

Make sure the key matches with the array index which you get from server(API).

Then create anew component for rendering table and pass data and headers to that as props

Then extract the headers to an array and before rendering data, just check if the specific value exists

const viewTable = (props) => { 
    const index = []; 
    const header = props.header.map((heading) => { 
        index.push(heading.index); 
        return <th key={heading.index}>{heading.title}</th> 
    }); 

    const tableData = props.data.map((data, key) => { 
        return <tr>
             {index.map(key => {
                 if (index.indexOf(key) > -1) {
                     return <td>{row[key]}</td>;
                 }
             })}
          </tr>
    }) ; 

    return ( 
        <table cellSpacing={30} cellPadding={5}> 
            <thead> 
                <tr> 
                    {header} 
                </tr> 
            </thead> 
            <tbody> 
                {tableData} 
            </tbody> 
        </table> 
    ); 
} 

export default viewTable;

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.