Having trouble using api with datatable


Topic: Having trouble using api with datatable

robnewton pro asked 11 months ago

I am trying to get information from an api to display on a datatable and I'm having some trouble. I'm using axios to get the data from the api, and then I took the response and put it into a state object (it's already in the JSON format). I then ran a function that mapped the information and put them in the format that the rows sections of the data variable would use, then pushed it to a new state. I logged the second state object and it comes back exactly how I want it. The columns appear but not the rows, and I'm not getting an error. Below is an example of my page using an open source api. Any help would be appreciated.
import React, { Component } from 'react';

import { MDBDataTable, Row, Col, Card, CardBody } from 'mdbreact';

import axios from 'axios';

const url = 'http://jsonplaceholder.typicode.com/posts';




class TableSectionInbound extends Component {

  constructor(props) {

    super(props);

    this.state= {

      posts: [],

      isLoading:true,

      tableRows: [],

    };

  }




  componentWillMount=async() => {

    await axios.get(url)

      .then(response => response.data)

      .then(data => {

         // console.log(data);

         // if (err) throw err;

         this.setState({ posts: data })

      })

      .then(async() => {

         this.setState({ tableRows:this.assemblePosts(), isLoading:false })

         console.log(this.state.tableRows);

      });

  }




  assemblePosts= () => {

    let posts =this.state.posts.map((post) => {

      return (

        {

          number: post.id,

          title: post.title,

          user: post.userId,

          body: post.body,

        }

      )

    });

    return posts;

  }





  render() {

    const data = {

      columns: [

        {

          label:'#',

          field:'number',

        },

        {

          label:'Title',

          field:'title',

        },

        {

          label:'User ID',

          field:'user',

        },

        {

          label:'Body',

          field:'body',

        },

      ],

      rows:this.state.tableRows,

    }




    return (

      <RowclassName="mb-4">

        <Col md="12">

          <Card>

            <CardBody>

              <MDBDataTable

                striped

                bordered

                hover

                data={data}

              />

            </CardBody>

          </Card>

        </Col>

      </Row>

    )

  }

}




export default TableSectionInbound;




Jakub Mandra staff premium answered 11 months ago

Hey, I found out what is wrong. Datatable has no componentDidUpdate lifecycle method in mdbreact v.4.7.0   Please update mdbreact to the newest version and everything will work fine.   Regards

robnewton pro commented 11 months ago

That did the thing. It works now. Thank you for all your help.


Jakub Mandra staff premium commented 11 months ago

I'm glad i could help, shame that took so long :)


Jakub Mandra staff premium answered 10 months ago

Ok, what kind of data do you provide form your redux store?

To use search, component needs to filter out what you are searching for (String value). We implemented toString() method on ech row key.

So app wont break with data like this: 

rows: [
{
id: 12,
name: 'name',
category: 'category',
average: 'average',
createdAt: 'createdAt',
updatedAt: 'updatedAt',
userId: 'userId'
},
{
id: 1,
name: 'john',
category: 'category',
average: 'average',
createdAt: 'createdAt',
updatedAt: 'updatedAt',
userId: 'userId'
}
]


Maybe you have empty keys inside row's objects?

When I used this object my app has broken: 

rows: [
{
id: 12,
name: 'name',
category: 'category',
average: 'average',
createdAt: undefined,
updatedAt: 'updatedAt',
userId: 'userId'
},

Jakub Mandra staff premium answered 11 months ago

Hey, You should not use componentWillMount. Regarding to React documentation setState wont trigger the extra render. That's why your view does not change ('columns' are there from the beginning of the components life, so they appear). Use componentDidMount - it is recommended to do API calls within this method.   We already support the API data source. Just pass the url as data property. But it has to have the proper structure. More in the documentation     Regards

robnewton pro commented 11 months ago

Thank you for the response. I have now changed componentWillMount to componentDidMount and removed all the async functions and awaits. I'm still having the same problem though. I'm still getting the logged version of what I want, but the rows still don't show. I do know about the API data source, but the API I am using has a different format. The way I'm doing it is pretty much just reformatting it for use with the data variable though.


Jakub Mandra staff premium answered 11 months ago

Code above works fine on my localhost with componentDidMount. Now the problem is, that your component does not rerender... To be sure, table structure appears with column names as you described?   I made an experiment and added: <button onClick={this.buildRows}>Assemble</button> buildRows = () => this.setState({ tableRows: this.assemblePosts() });

robnewton pro commented 11 months ago

Correct, the table structure appears with all the correct column names, but no rows appear. I just tested your experiment, added multiple console.log()'s in to make sure it was working correctly, and while the button and setting of the state work, nothing is being posted to the table still. While waiting for a response I have tested a few other things too. I tried using the forEach() method and instead of setting the rows object to to this.state.tableRows, I made it an empty array that I am using .push() to push the data to it. It's pretty much the same concept, and it also doesn't work. If this ends up not working and I switch to a basic table, would it be possible to add pagination and a search bar to it? If so, how would I go about doing that?


Jakub Mandra staff premium commented 11 months ago

There is complex logic behind those functionalities, that is why we built dedicated component.


sedonawebservices pro answered 10 months ago

My Datatable works great, except when I click in the search bar, the component breaks. Is there a recommended implementation for lifecycles?


import React, {Component} from "react";
import { DataTable, Container, Row, Col, Card, CardBody } from "mdbreact";
import {connect} from 'react-redux'
import {topics} from '../store'

class TopicsPage extends Component {
constructor(props) {
super(props)
}

componentDidMount() {
this.props.fetchTopics()
}

render() {
const {topics} = this.props
const data = {
columns: [
{
label: "Id",
field: "id",
sort: "asc",
width: 150
}, {
label: "Name",
field: "name",
sort: "asc",
width: 150
},
{
label: "Category",
field: "category",
sort: "asc",
width: 270
},
{
label: "Average",
field: "average",
sort: "asc",
width: 270
},
{
label: "createdAt",
field: "createdAt",
sort: "asc",
width: 270
},
{
label: "updatedAt",
field: "updatedAt",
sort: "asc",
width: 270
},
{
label: "userId",
field: "userId",
sort: "asc",
width: 270
}
],
rows: topics
}
return (
<Container className="mt-3">
<Row className="py-3">
<Col md="12">
<Card>
<CardBody>
<DataTable striped bordered hover data={data} />
</CardBody>
</Card>
</Col>
</Row>

</Container>
)
}
}

const mapProps = state => {
return {
topics: state.topics
}
}

const mapDispatch = dispatch => ({
fetchTopics() { dispatch(topics()) }
})

export default connect(mapProps, mapDispatch)(TopicsPage)


Jakub Mandra staff premium commented 10 months ago

Your code looks properly. 

Can you provide error msg?

Does that error occur already after clicking or writing?


sedonawebservices pro commented 10 months ago

Hi. The error happens only after typing. Right away, I get a blank white screen.


sedonawebservices pro answered 10 months ago

Regarding previous comment, here is an error message I see in Javascript console, when I start to type in Search bar:

 

mdbreact.js:8117 Uncaught TypeError: Cannot read property 'toString' of null
at mdbreact.js:8117
at Array.filter (<anonymous>)
at t.<anonymous> (mdbreact.js:8115)
at getStateFromUpdate (react-dom.development.js:11427)
at processUpdateQueue (react-dom.development.js:11488)
at updateClassInstance (react-dom.development.js:13270)
at updateClassComponent (react-dom.development.js:14860)
at beginWork (react-dom.development.js:15716)
at performUnitOfWork (react-dom.development.js:18750)
at workLoop (react-dom.development.js:18791)
at HTMLUnknownElement.callCallback (react-dom.development.js:147)
at Object.invokeGuardedCallbackDev (react-dom.development.js:196)
at invokeGuardedCallback (react-dom.development.js:250)
at replayUnitOfWork (react-dom.development.js:17998)
at renderRoot (react-dom.development.js:18909)
at performWorkOnRoot (react-dom.development.js:19812)
at performWork (react-dom.development.js:19722)
at flushInteractiveUpdates$1 (react-dom.development.js:19992)
at batchedUpdates (react-dom.development.js:2259)
at dispatchEvent (react-dom.development.js:5105)
at interactiveUpdates$1 (react-dom.development.js:19978)
at interactiveUpdates (react-dom.development.js:2267)
at dispatchInteractiveEvent (react-dom.development.js:5081)
(anonymous) @ mdbreact.js:8117
(anonymous) @ mdbreact.js:8115
getStateFromUpdate @ react-dom.development.js:11427
processUpdateQueue @ react-dom.development.js:11488
updateClassInstance @ react-dom.development.js:13270
updateClassComponent @ react-dom.development.js:14860
beginWork @ react-dom.development.js:15716
performUnitOfWork @ react-dom.development.js:18750
workLoop @ react-dom.development.js:18791
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
replayUnitOfWork @ react-dom.development.js:17998
renderRoot @ react-dom.development.js:18909
performWorkOnRoot @ react-dom.development.js:19812
performWork @ react-dom.development.js:19722
flushInteractiveUpdates$1 @ react-dom.development.js:19992
batchedUpdates @ react-dom.development.js:2259
dispatchEvent @ react-dom.development.js:5105
interactiveUpdates$1 @ react-dom.development.js:19978
interactiveUpdates @ react-dom.development.js:2267
dispatchInteractiveEvent @ react-dom.development.js:5081
index.js:1452 The above error occurred in the <t> component:
in t (at DatabasePage.js:60)
in div (created by t)
in t (at DatabasePage.js:59)
in div (created by t)
in t (at DatabasePage.js:58)
in div (created by t)
in t (at DatabasePage.js:57)
in div (created by t)
in t (at DatabasePage.js:56)
in div (created by t)
in t (at DatabasePage.js:55)
in DatabasePage (created by Connect(DatabasePage))
in Connect(DatabasePage) (created by Route)
in Route (at Routes.js:137)
in Switch (at Routes.js:135)
in div (at Routes.js:57)
in Router (at Routes.js:56)
in Routes (created by Connect(Routes))
in Connect(Routes) (at App.js:38)
in main (at App.js:37)
in div (at App.js:35)
in App (created by Connect(App))
in Connect(App) (at src/index.js:15)
in Provider (at src/index.js:14)

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
function.console.(anonymous function) @ index.js:1452
logCapturedError @ react-dom.development.js:16489
logError @ react-dom.development.js:16524
update.callback @ react-dom.development.js:17499
callCallback @ react-dom.development.js:11592
commitUpdateEffects @ react-dom.development.js:11632
commitUpdateQueue @ react-dom.development.js:11622
commitLifeCycles @ react-dom.development.js:16779
commitAllLifeCycles @ react-dom.development.js:18160
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
commitRoot @ react-dom.development.js:18365
completeRoot @ react-dom.development.js:19894
performWorkOnRoot @ react-dom.development.js:19817
performWork @ react-dom.development.js:19722
flushInteractiveUpdates$1 @ react-dom.development.js:19992
batchedUpdates @ react-dom.development.js:2259
dispatchEvent @ react-dom.development.js:5105
interactiveUpdates$1 @ react-dom.development.js:19978
interactiveUpdates @ react-dom.development.js:2267
dispatchInteractiveEvent @ react-dom.development.js:5081
mdbreact.js:8117 Uncaught TypeError: Cannot read property 'toString' of null
at mdbreact.js:8117
at Array.filter (<anonymous>)
at t.<anonymous> (mdbreact.js:8115)
at getStateFromUpdate (react-dom.development.js:11427)
at processUpdateQueue (react-dom.development.js:11488)
at updateClassInstance (react-dom.development.js:13270)
at updateClassComponent (react-dom.development.js:14860)
at beginWork (react-dom.development.js:15716)
at performUnitOfWork (react-dom.development.js:18750)
at workLoop (react-dom.development.js:18791)
at renderRoot (react-dom.development.js:18876)
at performWorkOnRoot (react-dom.development.js:19812)
at performWork (react-dom.development.js:19722)
at flushInteractiveUpdates$1 (react-dom.development.js:19992)
at batchedUpdates (react-dom.development.js:2259)
at dispatchEvent (react-dom.development.js:5105)
at interactiveUpdates$1 (react-dom.development.js:19978)
at interactiveUpdates (react-dom.development.js:2267)
at dispatchInteractiveEvent (react-dom.development.js:5081)
(anonymous) @ mdbreact.js:8117
(anonymous) @ mdbreact.js:8115
getStateFromUpdate @ react-dom.development.js:11427
processUpdateQueue @ react-dom.development.js:11488
updateClassInstance @ react-dom.development.js:13270
updateClassComponent @ react-dom.development.js:14860
beginWork @ react-dom.development.js:15716
performUnitOfWork @ react-dom.development.js:18750
workLoop @ react-dom.development.js:18791
renderRoot @ react-dom.development.js:18876
performWorkOnRoot @ react-dom.development.js:19812
performWork @ react-dom.development.js:19722
flushInteractiveUpdates$1 @ react-dom.development.js:19992
batchedUpdates @ react-dom.development.js:2259
dispatchEvent @ react-dom.development.js:5105
interactiveUpdates$1 @ react-dom.development.js:19978
interactiveUpdates @ react-dom.development.js:2267
dispatchInteractiveEvent @ react-dom.development.js:5081


sedonawebservices pro answered 10 months ago

Yes Jakub, some of my data is "null". So I will try replacing the null values with an empty string.


sedonawebservices pro answered 10 months ago

Thanks, that fixed it. I adjusted the database models so that any null values are retrieved as blank strings.


Jakub Mandra staff premium commented 10 months ago

Glad I could help.

We will add this 'restriction' to the documentation.

 

Looks like my comment has been deleted Oo


Hello I am Having the same issue. When I try to input in the search form I get the same toString error. Here is my code below:

import React from "react";
import { MDBDataTable } from 'mdbreact';
 import datetime from 'node-datetime';

class TransactionList extends React.Component {
 render() {
  const transactions = this.props.allTransactions;
const data = {
  columns: [
    {
      label: 'Agent Name',
      field: 'agentName',
      sort: 'asc',
      width: 150
    },
    {
      label: 'Driver Name',
      field: 'driverName',
      sort: 'asc',
      width: 150
    },
    {
      label: 'Agent Phone Number',
      field: 'agentNumber',
      sort: 'asc',
      width: 150
    },
    {
      label: 'Vehicle Number',
      field: 'vehicleNumber',
      sort: 'asc',
      width: 150
    },
    {
      label: 'Date',
      field: 'date',
      sort: 'asc',
      width: 150
    },
    {
      label: 'Time',
      field: 'time',
      sort: 'asc',
      width: 150
    },
  ],
  rows: transactions.map(transaction => {
    return {
      agentName: transaction.agentName,
      driverName: transaction.driverName,
      agentNumber: `${0}${transaction.agentNumber}`,
      vehicleNumber: transaction.vehicleNumber,
      date: datetime.create(transaction.date).format('m/d/y'),
      time: datetime.create(transaction.date).format('H:M:S')
    }
  })
}

return (
  <div class="col-md-9">
    <div class="panel panel-default my-auto" id="transaction">
      <div class="panel-heading main-color-bg">
        <h3 class="panel-title">All Transactions</h3>
      </div>
      <div className="panel-body">
  <MDBDataTable
    striped
    bordered
    small
    data={data}
    /> 
      </div>
    </div>
  </div>
    );
   }
 }

 export default TransactionList;

Jakub Mandra staff premium answered 6 months ago

Hey @valentineEzeh,

To use search, the component needs to filter out what you are searching for (String value). We implemented toString() method on each row key.

So the app won't break with data like this (numbers allowed):

rows: [
  {
    id: 12,
    name: 'name',
    category: 'category',
    average: 'average',
    createdAt: 'createdAt',
    updatedAt: 'updatedAt',
    userId: 'userId'
  },
  {
    id: 1,
    name: 'john',
    category: 'category',
    average: 'average',
    createdAt: 'createdAt',
    updatedAt: 'updatedAt',
    userId: 'userId'
  }
]

Maybe you have empty keys inside row's objects?

Check this example, because createdAt: undefined the app brokes when search is used:

rows: [
  {
    id: 12,
    name: 'name',
    category: 'category',
    average: 'average',
    createdAt: undefined,
    updatedAt: 'updatedAt',
    userId: 'userId'
  },

Best,

Jakub


Group pro premium answered 5 months ago

How to implement click event on data table row const row = [

{
    sl: 'Tiger Nixon',
    emp_name: 'System Architect',
    movementType: 'Edinburgh',
    applicationDate: '61',
    fromDate: '2011/04/25',
    toDate: '$320',
    reason: '$320',
    address: '$320',
    status: "completed",
    clickEvent: handleRowClick
},

]


Jakub Mandra staff premium answered 5 months ago

Hi,

The simples example could be:

import React from 'react';
import { MDBDataTable } from 'mdbreact';

class DatatablePage extends React.Component {
  state = {
    data: {
      columns: [
        {
          label: 'Name',
          field: 'name',
          sort: 'asc',
          width: 150
        },
        {
          label: 'Position',
          field: 'position',
          sort: 'asc',
          width: 270
        },
        {
          label: 'Office',
          field: 'office',
          sort: 'asc',
          width: 200
        },
        {
          label: 'Age',
          field: 'age',
          sort: 'asc',
          width: 100
        },
        {
          label: 'Start date',
          field: 'date',
          sort: 'asc',
          width: 150
        },
        {
          label: 'Salary',
          field: 'salary',
          sort: 'asc',
          width: 100
        }
      ],
      rows: [
        {
          name: 'Tiger Nixon',
          position: 'System Architect',
          office: 'Edinburgh',
          age: '61',
          date: '2011/04/25',
          salary: '$320',
          clickEvent: e => this.handleClick(e, 'Tiger Nixon')
        },
        {
          name: 'Garrett Winters',
          position: 'Accountant',
          office: 'Tokyo',
          age: '63',
          date: '2011/07/25',
          salary: '$170',
          clickEvent: e => this.handleClick(e, 'Garret Winters')
        }
      ]
    }
  }

  handleClick = (e, data) => {
    console.log('event target:', e.target, 'data:', data);
  }

  render() {
    return (
      <MDBDataTable
        striped
        bordered
        hover
        data={this.state.data}
      />
    );
  }
}

export default DatatablePage;

Best,

Jakub


Please insert min. 20 characters.
Status

Answered

Specification of the issue
  • User: Pro
  • Premium support: No
  • Technology: React
  • MDB Version: 4.7.0
  • Device: MacBook Pro
  • Browser: Google Chrome
  • OS: macOS High Sierra 10.13.2
  • Provided sample code: No
  • Provided link: No