*React-table* second page not showing data - reactjs

I have a table which displays clinics. I have also a onPageChange prop which handles the pageIndex and then i fetch the data based on that page. Below is my table configuration
import 'react-table/react-table.css'
import React, { Component } from 'react';
import ClinicFormComponent from './newClinicForm';
import SearchFormComponent from '../search/searchForm';
import { connect } from 'react-redux';
import { fetchClinics, fetchClinic, deleteClinic, searchClinics, pushBreadcrumb, popBreadcrumb } from '../../actions/index.js';
import { toast } from 'react-toastify';
import ReactTable from 'react-table'
import store from '../../helpers/store';
import { ic_search } from 'react-icons-kit/md/ic_search';
import SvgIcon from 'react-icons-kit';
require('normalize.css/normalize.css');
// require('styles/App.css');
class ClinicsPage extends Component {
constructor() {
super();
this.handleClickForm = this.handleClickForm.bind(this);
this.handleClickFormSearch = this.handleClickFormSearch.bind(this);
this.closeForm = this.closeForm.bind(this);
this.onPageChange = this.onPageChange.bind(this);
}
componentDidMount(){
this.props.searchClinics({ country: 'Australia' });
}
onPageChange(pageIndex) {
this.props.fetchClinics(pageIndex, null);
}
render() {
let { devs } = this.props;
const columns = [{
Header: 'Id',
accessor: 'id' // String-based value accessors!
}, {
Header: 'Name',
accessor: 'name'
}, {
Header: 'Description', // Required because our accessor is not a string
accessor: 'description',
sortable: true
// accessor: d => d.friend.name // Custom value accessors!
},
{
Header: 'Country', // Required because our accessor is not a string
accessor: 'country',
sortable: true
// accessor: d => d.friend.name // Custom value accessors!
},
{
Header: 'Area', // Required because our accessor is not a string
accessor: 'area',
sortable: true
// accessor: d => d.friend.name // Custom value accessors!
},
{
Header: 'Latitude', // Required because our accessor is not a string
accessor: 'latitude',
sortable: true
// accessor: d => d.friend.name // Custom value accessors!
},
{
Header: 'Longitude', // Required because our accessor is not a string
accessor: 'longitude',
sortable: true
// accessor: d => d.friend.name // Custom value accessors!
},
{
Header: 'Tags', // Required because our accessor is not a string
accessor: 'tags',
sortable: true,
Cell: (row) => {if (row.original.tags.length>1) { return row.original.tags.join(', ') } else { return row.original.tags } }
},
{
Header: () => <span className="text-center">Actions</span>,
accessor: 'id',
id: 'actions',
sortable: true,
Cell: (row) => (<span><button className="text-center btn btn-primary-zoetis margin_right_5" onClick={()=>{this.props.history.push('/editClinic/'+ row.original.id)}}>Edit</button ><button className="text-center btn btn-danger" onClick={()=>{this.props.deleteClinic(row.original.id, row.original)}}>Delete</button ></span>)
}
]
return (
<div className="wrap">
<div className="row margin_top_10 margin_bottom_5">
<div className="col-sm-6">
<a className="btn btn-link color_zoetis btn_zoetis_alt" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapseExample2" onClick={this.handleClickForm}>NEW CLINIC</a>
</div>
<div className="col-sm-6">
<a className="nav-link float_right search-clinic-btn" data-toggle="collapse" onClick={this.handleClickFormSearch} role="button" aria-expanded="false" aria-controls="collapseExample"><span className="search_label">Search data entries...</span> <SvgIcon size={25} icon={ic_search}/></a>
</div>
</div>
<div id="nav-tabContent">
<ReactTable
data={devs.clinics}
pageSizeOptions= {[10]}
defaultPageSize= {10}
columns={columns}
pages={devs.paginationData.totalPages || ''}
sortable={true}
multiSort={true}
//manual
filterable
page={devs.paginationData.pageNumber}
loading={devs.isFetching}
onPageChange={this.onPageChange}
noDataText='No Data Found'
className='-striped -highlight'
/>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
devs: state.reducer.devs,
showMenu: state.reducer.devs.showMenu,
showEditMenu: state.reducer.devs.showEditMenu,
paginationData: state.reducer.devs.paginationData,
location: state.router.location.pathname
}
}
export const mapDispatchToProps = {
fetchClinics,
searchClinics,
fetchClinic,
deleteClinic,
pushBreadcrumb,
popBreadcrumb
}
export default connect(mapStateToProps, mapDispatchToProps)(ClinicsPage);
Notice that i have disabled manual prop. If i enable the manual prop then i can navigate through next and previous pages but i cannot sort or filter the data.
With the manual prop disabled the filtering and the sorting works correct but when i navigate in the next page the table is showing empty. The first page displays correct the first 10 data. Also i have tested the api and returns correct the next 10 data.
Is there any workaround? To keep both server side pagination and alse the default sorting and filtering?

Test decomposing manual property
<ReactTable
filtered={this.state.filtered}
onFilteredChange={this.onFilteredChange.bind(this)}
defaultFilterMethod={(filter, row) =>
String(row[filter.id]) === filter.value
}
columns={columns}
ref={r => (this.selectTable = r)}
className="-striped -highlight"
defaultPageSize={10}
data={this.state.data}
pages={this.state.pages}
loading={this.state.loading}
manual <-------
resizable={true}
filterable
filterAll={true}
onFetchData={(state, instance) => {
this.setState({loading: true})
axios.get(`${API}${controller}`, {
params: {
pages: state.page,
pageSize: state.pageSize,
filtered: state.filtered,
typeOption: `${type}`,
dateinit: `${this.state.dateinit}`,
datefinal: `${this.state.datefinal}`,
data: this.props.data
},
headers: { 'Authorization': `${tokenCopyPaste()}` }
})
.then((res) => {
this.props.exportTable(res.data, type);
this.setState({
data: res.data.data,
fulldata: res.data,
pages: Math.ceil(res.data.pages / state.pageSize),
loading: false
})
})
}
}
/>

Related

Custom handler search filter table antd

I am using antd to create a table with filter feature,
but I got a problem, I want to custom filter search of antd to call api,
antd table
How can I do that with react and antd,
Here is my code
const columns: ColumnsType<Product> = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
render: (name, record) => (
<div className="flex items-center">
<Avatar src={record.avatar}>{name[0].toUpperCase()}</Avatar>
<span style={{ marginLeft: 10 }} className="whitespace-nowrap">
<a title="View & Edit" href={'/product/' + record.id}>
{name}
</a>
</span>
</div>
),
},
{
title: 'About',
dataIndex: 'about',
key: 'about',
render: (about: string) => <p className="text-ellipsis line-clamp-2">{about}</p>,
width: 400,
},
{
title: 'Categories',
dataIndex: 'categories',
key: 'categories',
filterSearch: true,
filters: categories!.map((category: Category) => ({ text: category.name, value: category.id })),
render: (categories: any) => {
console.log(categories);
return '-';
},
// width: 400,
},
{ title: 'Addresses', dataIndex: 'contract_addresses', key: 'address', render: addresses => addresses?.[0] },
];
To filter the table, I usually provide a function that filters the data before it is passed to the table (In my example the function getData. This function can also be used to adjust the filter accordingly. Here is an example, which also consists of a Search-Input to modify the search:
const CustomersTable = (props: any) => {
const [searchText, setSearchText] = useState<string | undefined>(undefined);
const [customers, setCustomers] = useState<ICustomer[]>([]);
const getData = (
sourceData: Array<ICustomer>,
searchText: string | undefined
) => {
if (!searchText) {
return sourceData;
}
return sourceData.filter((item) => {
const comparisonString = `${item.firstname.toLowerCase()}${item.familyname.toLowerCase()}`;
//here you can provide a more sophisticared search
return comparisonString.includes(searchText.toLowerCase());
});
};
const columns = [
{
title: "Vorname",
dataIndex: "firstname",
key: "firstname",
sorter: (a: ICustomer, b: ICustomer) => {
if (a.firstname.toLowerCase() > b.firstname.toLowerCase()) {
return -1;
} else if (a.firstname.toLowerCase() < b.firstname.toLowerCase()) {
return 1;
} else {
return 0;
}
},
},
{
title: "Nachname",
dataIndex: "familyname",
key: "familyname",
},
];
return (
<>
<Search
placeholder="Vorname, Nachname"
value={searchText}
onChange={(e) => {
setSearchText(e.target.value);
}}
/>
<Table
columns={columns}
dataSource={getData(customers, searchText)}
/>
</>
);
};

Ant Design table delete and edit functionalities not reflecting on the PG database

I am trying to implement crud functionalities in Ant design table. I observed that the delete and edit functionalities only works on the instance when I perform the operations on initial render, but after reloading the component, the table returns back to its initial state and the operations don't affect the database in any way.
I see this error on my console
Type '{ title: string; dataIndex: string; key: string; align: string; editable: boolean;
render?: undefined; }' is not assignable to type 'ColumnType<any>'.
Types of property 'align' are incompatible.
Type 'string' is not assignable to type 'AlignType'.
These are the codes below, I hope to break them down in code blocks so they can be understandable
imports
import React, { useState, useEffect } from 'react';
import { Table, Popconfirm, Button, Space, Input, Form } from 'antd';
import { isEmpty } from 'lodash';
api
const apiUrl = 'api/terminals';
useState and useEffect codes
const [gridData, setGridData] = useState([]);
const [loader, setLoader] = useState(false);
const [editingKey, setEditingKey] = useState('');
const [editRow, setEditRow] = useState(false);
const [form] = Form.useForm();
useEffect(() => {
loadData();
}, []);
const loadData = async () => {
setLoader(true);
const response = await axios.get(apiUrl);
setGridData(response.data);
setLoader(false);
};
modifiedData codes
const modifiedData = gridData.map(({ ...item }) => ({
...item,
key: item.id,
}));
const save = async key => {
try {
const row = await form.validateFields();
const newData = [...modifiedData];
const index = newData.findIndex(item => key === item.key);
if (index > -1) {
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
setGridData(newData);
setEditingKey('');
}
} catch (error) {
console.warn('Error', error);
}
};
edit and cancel function code block
const edit = record => {
form.setFieldsValue({
name: '',
stock: '',
stockLevelDate: '',
tankThreatLevel: '',
tankThreatLevelColor: '',
tankTopPosition: '',
tankTopPositionColor: '',
lowPumpable: '',
lowPumpableColor: '',
tankCapacity: '',
...record,
});
setEditingKey(record.key);
};
const cancel = () => {
setEditingKey('');
};
editableCell function block
const EditableCell = ({ editing, dataIndex, title, record, children, ...restProps }) =>
{
const input = <Input />;
return (
<td {...restProps}>
{editing ? (
<Form.Item
name={dataIndex}
style={{ margin: 0 }}
rules={[
{
required: true,
message: `Please input ${title}`,
},
]}
>
{input}
</Form.Item>
) : (
children
)}
</td>
);
};
editing code block
const isEditing = record => {
return record.key === editingKey;
};
columns block
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id',
},
{
title: 'Name' as string,
dataIndex: 'name',
key: 'name',
align: 'center',
editable: true,
},
{
title: 'Stock',
dataIndex: 'stock',
key: 'stock',
align: 'center',
editable: true,
},
{
title: 'Stock Level Date',
dataIndex: 'stockLevelDate',
key: 'stockLevelDate',
align: 'center',
editable: true,
},
{
title: 'Tank Threat Level',
dataIndex: 'tankThreatLevel',
key: 'tankThreatLevel',
align: 'center',
editable: true,
},
{
title: 'Tank Threat Level Color',
dataIndex: 'tankThreatLevelColor',
key: 'tankThreatLevelColor',
align: 'center',
editable: true,
},
{
title: 'Tank Top Position',
dataIndex: 'tankTopPosition',
key: 'tankTopPosition',
align: 'center',
editable: true,
},
{
title: 'Tank Top Position Color',
dataIndex: 'tankTopPositionColor',
key: 'tankTopPositionColor',
align: 'center',
editable: true,
},
{
title: 'Low Pumpable',
dataIndex: 'lowPumpable',
key: 'lowPumpable',
align: 'center',
editable: true,
},
{
title: 'Low Pumpable Color',
dataIndex: 'lowPumpableColor',
key: 'lowPumpableColor',
align: 'center',
editable: true,
},
{
title: 'Tank Capacity',
dataIndex: 'tankCapacity',
key: 'tankCapacity',
align: 'center',
editable: true,
},
{
title: 'Actions',
dataIndex: 'actions',
key: 'actions',
align: 'center',
render: (_, record) => {
const editable = isEditing(record);
return modifiedData.length >= 1 ? (
<Space>
<Popconfirm title="Sure to delete?" onConfirm={() => handleDelete(record)}>
<Button type="primary" disabled={editable} danger>
Delete
</Button>
</Popconfirm>
{editable ? (
<span>
<Space size="middle">
<Button onClick={e => save(record.key)} type="primary" style={{ marginRight: 8
}}>
{' '}
Save
</Button>
<Popconfirm title="Sure to cancel?" onConfirm={cancel}>
<Button>Cancel</Button>
</Popconfirm>
</Space>
</span>
) : (
<Button onClick={() => edit(record)} type="primary">
Edit
</Button>
)}
</Space>
) : null;
},
},
];
mergedCoulumns block
const mergedColumns = columns.map(col => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: record => ({
record,
dataIndex: col.dataIndex,
title: col.title,
editing: isEditing(record),
}),
};
});
handleDelete code block
const handleDelete = value => {
const dataSource = [...modifiedData];
const filteredData = dataSource.filter(item => item.id !== value.id);
setGridData(filteredData);
};
return jsx
<>
<div>
<h2>Terminals</h2>
<Link to={`${match.url}/new`} className="btn btn-primary jh-create-entity" id="jh
-create-
entity" data-cy="entityCreateButton">
<FontAwesomeIcon icon="plus" />
Add Terminal
</Link>
<hr color="red" />
<Form form={form} component={false}>
<Table
components={{
body: {
cell: EditableCell,
},
}}
columns={mergedColumns}
dataSource={modifiedData}
bordered
loading={loader}
/>
</Form>
</div>
</>
Thanks in anticipation

Redux state change does not rerenders datatable

**Here is the cart imports and state
const Cart = ({ cart, setActiveTab, removeFromCart, updateQuantity }) => {
const [selectedRows , setSelectedRows] = useState([]);
const [toggleCleared, setToggleCleared] = useState(false);
const [products, setProducts] = useState(cart.products) }
const columns = [
{
name: 'Product Name',
selector: 'name',
sortable: true,
},
{
name: 'Product Price',
selector: 'price',
sortable: true,
right: true,
},
{
name: 'Product Quantity',
selector: 'quantity',
sortable: true,
right: true,
cell: row => <Fragment><input type="number" className="form-control" value={row.quantity} onChange = {(e)=>updateQuantity( row.id,strong text e.target.value)}/></Fragment>
},
{
name: 'Subtotal',
selector: 'quantity',
sortable: true,
right: true,
cell: row => <Fragment>{row.quantity * row.price}</Fragment>
},
{
name: 'Actions',
selector: 'quantity',
sortable: true,
right: true,
cell: row => <Fragment><i className="fa fa-trash" aria-hidden="true" onClick = {(e)=>removeFromCart(row.id)}></i></Fragment>
},
];
const contextActions = useMemo(() => {
const handleDelete = () => {
selectedRows.forEach(item=>{
console.log(item, 'item')
removeFromCart(products, products.indexOf(item))
});
setProducts(products);
setToggleCleared(!toggleCleared);
console.log('handleDelete', products)
};
return <i className="fa fa-trash" key="delete" onClick={handleDelete} style={{ backgroundColor: 'red' }} ></i>;
});
This code sets the selected rows when we select rows
function rowSelection (rows) =>{
setSelectedRows(rows.selectedRows);
}
return ( <DataTable
title="Cart Products"
columns={columns}
data={products}
selectableRows
onSelectedRowsChange={rowSelection}
clearSelectedRows={toggleCleared}
contextActions={contextActions} />
)
**here is the my cart component which works fine but it does not updates itself when the redux state changes.. i can see the redux state in console that it changes perfectly but datatable does not rerenders
const [products, setProducts] = useState(cart.products) } this will only works on initial rendering ( called initial state).useState will not call once the render is completed. so just pass the cart.products in to the datatable
function rowSelection (rows) =>{
setSelectedRows(rows.selectedRows);
}
return ( <DataTable
title="Cart Products"
columns={columns}
data={cart.products}
selectableRows
onSelectedRowsChange={rowSelection}
clearSelectedRows={toggleCleared}
contextActions={contextActions} /> )

The column with audio file playback from the file system does not change on sorting or paging

I'm new in React and I'm trying to create a simple react table - a list of records with audio file playback. Metadata about records are from database and the audio file is loaded according to the file_address column from the file system.
During sorting and paging, all table columns change, except the playback column, which does not change in general. I attached my code. Thank you in advance for your help :)
import React from 'react';
import ReactTable from 'react-table'
import 'react-table/react-table.css'
import './App.css';
import { Container } from "#material-ui/core";
import { maxHeight } from '#material-ui/system';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoaded: false,
error: null,
items: []
};
}
/**
* call BE endpoint to receive records data
*/
componentDidMount() {
fetch("/records")
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result.Records
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
/**play wav audio */
async play(file_address) {
var audio = new Audio({file_address});
audio.type = 'audio/wav';
try {
await audio.play();
console.log('Playing...');
} catch (err) {
console.log('Failed to play...' + err);
}
}
/**create table structure */
render(){
const items = this.state.items;
const columns = [{
Header: 'ID',
accessor: 'Id',
sortable: true
},
{
Header: 'Name',
accessor: 'Name',
sortable: true
},
{
id: 'Play',
Header: 'Play',
accessor: a => <audio controls>
<source src={a.File_Address} type="audio/wav" />
</audio>
},
{
Header: 'Duration',
accessor: 'Duration',
sortable: true
},
{
Header: 'Date',
accessor: 'Date',
sortable: true
},
{
Header: 'Time',
accessor: 'Time',
sortable: true
},{
Header: 'File address',
accessor: 'File_Address'
}
]
/**return react components with records data */
return (
<Container className="container" maxWidth="xl" style={{ height: maxHeight, background: '#ffffff', color: '#424242'}}>
<h1 className="title">Records</h1>
<ReactTable
style={{
background: '#eeeeee',
color: '#000000'
}}
data={items}
columns={columns}
/>
</Container>
)
}
}
export default App;

React table rendering in the form of a row

Kind of a React noobie here so please don't judge.
The react table is rendering in the form of a row.
My Component:
import React, { Component } from 'react';
import ReactTable from 'react-table';
// import 'react-table/react-table.css';
class Variants extends Component {
constructor(props) {
super(props);
}
render() {
const columns = [
{
Header: 'Gene',
accessor: 'gene'
},
{
Header: 'Nucleotide Change',
accessor: 'nucleotide_change'
},
{
Header: 'Protein Change',
accessor: 'protein_change'
},
{
Header: 'Other Mappings',
accessor: 'other_mappings'
},
{
Header: 'Alias',
accessor: 'alias'
},
{
Header: 'Transcripts',
accessor: 'transcripts'
},
{
Header: 'Region',
accessor: 'region'
},
{
Header: 'Reported Classification',
accessor: 'reported_classification'
},
{
Header: 'Inferred Classification',
accessor: 'inferred_classification'
},
{
Header: 'Source',
accessor: 'source'
},
{
Header: 'Last Evaluated',
accessor: 'last_evaluated'
},
{
Header: 'Last Updated',
accessor: 'last_updated'
},
{
Header: 'More Information',
accessor: 'url',
Cell: e => (
<a target="_blank" href={e.value}>
{' '}
{e.value}{' '}
</a>
)
},
{
Header: 'Submitter Comment',
accessor: 'submitter_comment'
}
];
if (this.props.variants && this.props.variants.length > 0) {
return (
<div>
<h2>
{' '}
There are {this.props.variants.length} variants of this gene!
</h2>
<div>
<ReactTable
data={this.props.variants}
columns={columns}
defaultPageSize={3}
pageSizeOptions={[3, 5, 10, 50, 100]}
/>
</div>
</div>
);
} else {
return [];
}
}
}
export default Variants;
It is rendering the whole table as a row for some weird reason. I have attached the image to show what is happening. Also, the pagination buttons are not nice. Can they be modified?
Has anyone come across a similar problem?
I got it working below. I simplified the data since you didn't provide an example data set but this should help you.
The only thing I can think you have wrong is either you need to uncomment import 'react-table/react-table.css'; or maybe you are passing in your props wrong in <Variants variants={variants}/>
Variants.js
import React, { Component } from 'react';
import ReactTable from 'react-table';
import 'react-table/react-table.css';
class Variants extends Component {
render() {
const columns = [
{
Header: 'Gene',
accessor: 'gene'
},
{
Header: 'Nucleotide Change',
accessor: 'nucleotide_change'
},
{
Header: 'Protein Change',
accessor: 'protein_change'
}
];
if (this.props.variants && this.props.variants.length > 0) {
return (
<div>
<h2>
{' '}
There are {this.props.variants.length} variants of this gene!
</h2>
<div>
<ReactTable
data={this.props.variants}
columns={columns}
defaultPageSize={3}
pageSizeOptions={[3, 5, 10, 50, 100]}
/>
</div>
</div>
);
} else {
return [];
}
}
}
export default Variants;
App.js
import React from 'react';
import './App.css';
import Variants from "./Variants";
const variants = [
{
gene:'a',
nucleotide_change:'a',
protein_change:'a'
},
{
gene:'b',
nucleotide_change:'b',
protein_change:'b'
}
];
function App() {
return (
<div className="App">
<Variants variants={variants}/>
</div>
);
}
export default App;

Resources