Material-table: How to refresh remote data programmatically

Created on 27 Mar 2019  路  15Comments  路  Source: mbrn/material-table

Help me pls,

I have bind data to MaterialTable with remote feature without problems.
But now i want to be able to refresh this data with a trigger. I don't know if it is possible?

I know how to do it when data is an array. (with state)
but when data is a promise ....

Thks,

async fetchUsers(query){
 let datas = await fetch("/datas")
 return {  data: datas, page: query.page, totalCount: datas.length}
}
refreshAllMyRemoteData(){
  // here i want to be able to refresh the data but i don't know how to do it :)
}
...

<MaterialTable
  data={this.fetchUsers}
  detailPanel={[
    {
      icon: 'person_add_disabled',
      render: rowData => {
        return (<div onClick={this.refreshAllMyRemoteData}>click-me</div>)
      },
    }
  ]}

Most helpful comment

Hi @billBeOK ,

Your requirement makes sense. I resolved it with tableRef with new version 1.28.0

import { Grid, MuiThemeProvider } from '@material-ui/core';
import { createMuiTheme } from '@material-ui/core/styles';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import MaterialTable from './material-table';

class App extends Component {
  tableRef = React.createRef();

  render() {
    return (
        <div style={{ maxWidth: '100%', direction }}>        
              <MaterialTable
                tableRef={this.tableRef}
                columns={[
                  {
                    title: 'Avatar',
                    field: 'avatar',
                    render: rowData => (
                      <img
                        style={{ height: 36, borderRadius: '50%' }}
                        src={rowData.avatar}
                      />
                    ),
                  },
                  { title: 'Id', field: 'id' },
                  { title: 'First Name', field: 'first_name' },
                  { title: 'Last Name', field: 'last_name' },
                ]}
                data={query =>
                  new Promise((resolve, reject) => {
                    let url = 'https://reqres.in/api/users?';
                    url += 'per_page=' + query.pageSize;
                    url += '&page=' + (query.page + 1);
                    fetch(url)
                      .then(response => response.json())
                      .then(result => {
                        resolve({
                          data: result.data,
                          page: result.page - 1,
                          totalCount: result.total,
                        })
                      });
                  })
                }
                title="Remote Data Example"
              />
          <button
            onClick={() => {
              this.tableRef.current.onQueryChange();
            }}
          >
            ok
          </button>
        </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
);

module.hot.accept();

All 15 comments

Hi @billBeOK ,

Your requirement makes sense. I resolved it with tableRef with new version 1.28.0

import { Grid, MuiThemeProvider } from '@material-ui/core';
import { createMuiTheme } from '@material-ui/core/styles';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import MaterialTable from './material-table';

class App extends Component {
  tableRef = React.createRef();

  render() {
    return (
        <div style={{ maxWidth: '100%', direction }}>        
              <MaterialTable
                tableRef={this.tableRef}
                columns={[
                  {
                    title: 'Avatar',
                    field: 'avatar',
                    render: rowData => (
                      <img
                        style={{ height: 36, borderRadius: '50%' }}
                        src={rowData.avatar}
                      />
                    ),
                  },
                  { title: 'Id', field: 'id' },
                  { title: 'First Name', field: 'first_name' },
                  { title: 'Last Name', field: 'last_name' },
                ]}
                data={query =>
                  new Promise((resolve, reject) => {
                    let url = 'https://reqres.in/api/users?';
                    url += 'per_page=' + query.pageSize;
                    url += '&page=' + (query.page + 1);
                    fetch(url)
                      .then(response => response.json())
                      .then(result => {
                        resolve({
                          data: result.data,
                          page: result.page - 1,
                          totalCount: result.total,
                        })
                      });
                  })
                }
                title="Remote Data Example"
              />
          <button
            onClick={() => {
              this.tableRef.current.onQueryChange();
            }}
          >
            ok
          </button>
        </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
);

module.hot.accept();

it's work like a charm !

Bravo

Help me please I am getting this this.tableRef.current.onQueryChange() undefined

I also had the error initially and then realized I missed tableRef = React.createRef(); right after class App extends Component {

Is there a way to change query before refreshing data?

In addition to having the search trigger on pressing the Enter key, I also added a "Clear" button with

clearSearchInput = () => {
        // clear value
        this.setState({
            value: '',
        })
        // refresh table
        this.tableRef.current.onQueryChange();
    }
this.tableRef.current.onQueryChange();

the ref and this.tableRef.current.onQueryChange() saved my life bro! It works with functional component too using useRef!

this.tableRef.current.onQueryChange();

the ref and this.tableRef.current.onQueryChange() saved my life bro! It works with functional component too using useRef!

Could you please share a functional component example?

this.tableRef.current.onQueryChange();

the ref and this.tableRef.current.onQueryChange() saved my life bro! It works with functional component too using useRef!

Could you please share a functional component example?

using mbrn's previous code but with hooks:

import { Grid, MuiThemeProvider } from '@material-ui/core';
import { createMuiTheme } from '@material-ui/core/styles';
import React, { useRef } from 'react';
import ReactDOM from 'react-dom';
import MaterialTable from './material-table';
const App = () => {
  tableRef = useRef();
    return (
        <div style={{ maxWidth: '100%', direction }}>        
              <MaterialTable
                tableRef={tableRef}
                columns={[
                  {
                    title: 'Avatar',
                    field: 'avatar',
                    render: rowData => (
                      <img
                        style={{ height: 36, borderRadius: '50%' }}
                        src={rowData.avatar}
                      />
                    ),
                  },
                  { title: 'Id', field: 'id' },
                  { title: 'First Name', field: 'first_name' },
                  { title: 'Last Name', field: 'last_name' },
                ]}
                data={query =>
                  new Promise((resolve, reject) => {
                    let url = 'https://reqres.in/api/users?';
                    url += 'per_page=' + query.pageSize;
                    url += '&page=' + (query.page + 1);
                    fetch(url)
                      .then(response => response.json())
                      .then(result => {
                        resolve({
                          data: result.data,
                          page: result.page - 1,
                          totalCount: result.total,
                        })
                      });
                  })
                }
                title="Remote Data Example"
              />
          <button
            onClick={() => tableRef.current.onQueryChange()}
          >
            ok
          </button>
        </div>
    );
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
); 

A quick edit, but I think you get the point.

this.tableRef.current.onQueryChange();

the ref and this.tableRef.current.onQueryChange() saved my life bro! It works with functional component too using useRef!

Could you please share a functional component example?

using mbrn's previous code but with hooks:

import { Grid, MuiThemeProvider } from '@material-ui/core';
import { createMuiTheme } from '@material-ui/core/styles';
import React, { useRef } from 'react';
import ReactDOM from 'react-dom';
import MaterialTable from './material-table';
const App = () => {
  tableRef = useRef();
    return (
        <div style={{ maxWidth: '100%', direction }}>        
              <MaterialTable
                tableRef={tableRef}
                columns={[
                  {
                    title: 'Avatar',
                    field: 'avatar',
                    render: rowData => (
                      <img
                        style={{ height: 36, borderRadius: '50%' }}
                        src={rowData.avatar}
                      />
                    ),
                  },
                  { title: 'Id', field: 'id' },
                  { title: 'First Name', field: 'first_name' },
                  { title: 'Last Name', field: 'last_name' },
                ]}
                data={query =>
                  new Promise((resolve, reject) => {
                    let url = 'https://reqres.in/api/users?';
                    url += 'per_page=' + query.pageSize;
                    url += '&page=' + (query.page + 1);
                    fetch(url)
                      .then(response => response.json())
                      .then(result => {
                        resolve({
                          data: result.data,
                          page: result.page - 1,
                          totalCount: result.total,
                        })
                      });
                  })
                }
                title="Remote Data Example"
              />
          <button
            onClick={() => tableRef.current.onQueryChange()}
          >
            ok
          </button>
        </div>
    );
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
); 

A quick edit, but I think you get the point.

When, I use the tableRef.current.OnQueryChange(), it throws an error saying _this.props.data is not a function.

Can Someone Help on it

Here's a screenshot

Damn Error!

this.tableRef.current.onQueryChange();

the ref and this.tableRef.current.onQueryChange() saved my life bro! It works with functional component too using useRef!

Could you please share a functional component example?

using mbrn's previous code but with hooks:

import { Grid, MuiThemeProvider } from '@material-ui/core';
import { createMuiTheme } from '@material-ui/core/styles';
import React, { useRef } from 'react';
import ReactDOM from 'react-dom';
import MaterialTable from './material-table';
const App = () => {
  tableRef = useRef();
    return (
        <div style={{ maxWidth: '100%', direction }}>        
              <MaterialTable
                tableRef={tableRef}
                columns={[
                  {
                    title: 'Avatar',
                    field: 'avatar',
                    render: rowData => (
                      <img
                        style={{ height: 36, borderRadius: '50%' }}
                        src={rowData.avatar}
                      />
                    ),
                  },
                  { title: 'Id', field: 'id' },
                  { title: 'First Name', field: 'first_name' },
                  { title: 'Last Name', field: 'last_name' },
                ]}
                data={query =>
                  new Promise((resolve, reject) => {
                    let url = 'https://reqres.in/api/users?';
                    url += 'per_page=' + query.pageSize;
                    url += '&page=' + (query.page + 1);
                    fetch(url)
                      .then(response => response.json())
                      .then(result => {
                        resolve({
                          data: result.data,
                          page: result.page - 1,
                          totalCount: result.total,
                        })
                      });
                  })
                }
                title="Remote Data Example"
              />
          <button
            onClick={() => tableRef.current.onQueryChange()}
          >
            ok
          </button>
        </div>
    );
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
); 

A quick edit, but I think you get the point.

When, I use the tableRef.current.OnQueryChange(), it throws an error saying _this.props.data is not a function.

Can Someone Help on it

Here's a screenshot

Damn Error!

Post your code?

Sry, I forgot in hurry

const colHeads = columns.map((cl)=>{
return cl==='kills'||cl==='rank'||cl==='wallet'
? {title:colValues[cl],field:cl,type:'numeric',editable: 'onUpdate'}
: {title:colValues[cl],field:cl,editable: 'never'}
});

const colData = players && players.map((pl,ind)=>{
    let cp={}
    columns && columns.map((cl,cind)=>{
        return cl==='srno'? cp[cl]=players.indexOf(pl)+1 : cp[cl]=pl[cl]
    })
    return cp;
})


const tRef = React.useRef();

const editF = {
    onRowAdd:null,
    onRowUpdate:(newData,oldData)=>
    new Promise((resolve,reject)=>{
        setTimeout(()=>{
        let data = colData;
        console.log(state)
        let inx = data.indexOf(oldData);
        newData['kills']=parseInt(newData['kills'])
        newData['wallet']=parseInt(newData['wallet'])
        newData['rank']=parseInt(newData['rank'])
        data[inx] = newData;
        resolve();
        },1000)
    }),
    onRowDelete : null
};

const tRF = ()=>{
    setState(state)
}
return(
    <React.Fragment>
        <div>
            <MaterialTable
                tableRef={tRef}
                title="Players"
                columns={colHeads}
                data={colData}
                editable={isEditing? editF : null}
            />
            <button
        onClick={() => {
          tRef.current.onQueryChange();
        }}
      >
        ok
      </button>
            <div hidden={!bttnname}>
                <button onClick={()=>tRF()}  className='waves-effect waves-light btn hoverable'>{bttnname}</button>
            </div>
        </div>
    </React.Fragment>
)

The data is displayed properly, But when I try to use state for data and use setState(), it causes another error so, I opted for this approach.

Sry, I forgot in hurry

const colHeads = columns.map((cl)=>{
return cl==='kills'||cl==='rank'||cl==='wallet'
? {title:colValues[cl],field:cl,type:'numeric',editable: 'onUpdate'}
: {title:colValues[cl],field:cl,editable: 'never'}
});

const colData = players && players.map((pl,ind)=>{
    let cp={}
    columns && columns.map((cl,cind)=>{
        return cl==='srno'? cp[cl]=players.indexOf(pl)+1 : cp[cl]=pl[cl]
    })
    return cp;
})


const tRef = React.useRef();

const editF = {
    onRowAdd:null,
    onRowUpdate:(newData,oldData)=>
    new Promise((resolve,reject)=>{
        setTimeout(()=>{
        let data = colData;
        console.log(state)
        let inx = data.indexOf(oldData);
        newData['kills']=parseInt(newData['kills'])
        newData['wallet']=parseInt(newData['wallet'])
        newData['rank']=parseInt(newData['rank'])
        data[inx] = newData;
        resolve();
        },1000)
    }),
    onRowDelete : null
};

const tRF = ()=>{
    setState(state)
}
return(
    <React.Fragment>
        <div>
            <MaterialTable
                tableRef={tRef}
                title="Players"
                columns={colHeads}
                data={colData}
                editable={isEditing? editF : null}
            />
            <button
        onClick={() => {
          tRef.current.onQueryChange();
        }}
      >
        ok
      </button>
            <div hidden={!bttnname}>
                <button onClick={()=>tRF()}  className='waves-effect waves-light btn hoverable'>{bttnname}</button>
            </div>
        </div>
    </React.Fragment>
)

The data is displayed properly, But when I try to use state for data and use setState(), it causes another error so, I opted for this approach.

It's hard to follow what your doing, but it seems like you don't need to use data in this manner in the first place. If you aren't dealing directly with remote data like in the previous example, you should fix your state problem. Good luck!

Sry, I forgot in hurry
const colHeads = columns.map((cl)=>{
return cl==='kills'||cl==='rank'||cl==='wallet'
? {title:colValues[cl],field:cl,type:'numeric',editable: 'onUpdate'}
: {title:colValues[cl],field:cl,editable: 'never'}
});

const colData = players && players.map((pl,ind)=>{
    let cp={}
    columns && columns.map((cl,cind)=>{
        return cl==='srno'? cp[cl]=players.indexOf(pl)+1 : cp[cl]=pl[cl]
    })
    return cp;
})


const tRef = React.useRef();

const editF = {
    onRowAdd:null,
    onRowUpdate:(newData,oldData)=>
    new Promise((resolve,reject)=>{
        setTimeout(()=>{
        let data = colData;
        console.log(state)
        let inx = data.indexOf(oldData);
        newData['kills']=parseInt(newData['kills'])
        newData['wallet']=parseInt(newData['wallet'])
        newData['rank']=parseInt(newData['rank'])
        data[inx] = newData;
        resolve();
        },1000)
    }),
    onRowDelete : null
};

const tRF = ()=>{
    setState(state)
}
return(
    <React.Fragment>
        <div>
            <MaterialTable
                tableRef={tRef}
                title="Players"
                columns={colHeads}
                data={colData}
                editable={isEditing? editF : null}
            />
            <button
        onClick={() => {
          tRef.current.onQueryChange();
        }}
      >
        ok
      </button>
            <div hidden={!bttnname}>
                <button onClick={()=>tRF()}  className='waves-effect waves-light btn hoverable'>{bttnname}</button>
            </div>
        </div>
    </React.Fragment>
)

The data is displayed properly, But when I try to use state for data and use setState(), it causes another error so, I opted for this approach.

It's hard to follow what your doing, but it seems like you don't need to use data in this manner in the first place. If you aren't dealing directly with remote data like in the previous example, you should fix your state problem. Good luck!

Really Thanks, for the quick reply. I'll go with it then!

Just a sidenote. If you want to trigger the data reload on the table from one of your action button handlers which holds some async functions, and you have a problem like your reference is null, than the following might help you:

// Example is for a functional component

const yourRef = React.createRef()

// ...

tableRef: {yourRef},
actions: {[
  rowData => ({
    // ...
    onClick: (event, rowData) => {
      const scopedRef = yourRef.current
      anAsyncFunction(/*...*/).then(() => scopedRef.onQueryChange())
    }
  })
]}

// ...
Was this page helpful?
0 / 5 - 0 ratings

Related issues

revskill10 picture revskill10  路  3Comments

lazeebee picture lazeebee  路  3Comments

Mihier-Roy picture Mihier-Roy  路  3Comments

roseak picture roseak  路  3Comments

terapepo picture terapepo  路  3Comments