Open mantydze opened 7 years ago
Column sorting in example isn't meant to work - it isn't implemented. It is up to the user to sort the data and re-render following the change of props.
In that case the name of the library is misleading... Datatables usually provide sorting out of the box.
@advance512 Thanks for your comment! @mantydze Yes, you are right! most of Datatables component provide features like sorting are done within the library. but on the other hand, in react and flux(redux) world, it means you will lose some of your controls of components. so far, I don't know which is the right way. So, you can choose! :) there are a lot of cool react datatables already!
@hyojin
Could you please provide the demo source code, so it might help us to see how you implement sorting, pagination and search functionality.
Right now the examples are not working as demo. :)
Here is how I use the this component. I have placed it in another component so I can easily change to another library, if I run into a wall.
Haven't done sorting yet, but as you can see it should be quite easy. Look at the filtering example, but instead of filter - use Array.prototype.sort()
.
/* eslint-disable class-methods-use-this */
import React, { PropTypes } from 'react';
import DataTables from 'material-ui-datatables';
import { RefreshIndicator } from 'material-ui';
import get from 'lodash/get';
export class DataTable extends React.Component {
constructor(props) {
super(props);
this.state = {
page: 1,
rowSize: 10,
filterValue: null,
};
this.handleCellClick = ::this.handleCellClick;
this.handleCellDoubleClick = ::this.handleCellDoubleClick;
this.handleFilterValueChange = ::this.handleFilterValueChange;
this.handleSortOrderChange = ::this.handleSortOrderChange;
this.handleRowSizeChange = ::this.handleRowSizeChange;
this.handlePreviousPageClick = ::this.handlePreviousPageClick;
this.handleNextPageClick = ::this.handleNextPageClick;
}
handlePreviousPageClick() {
const newState = Object.assign({}, this.state, { page: this.state.page - 1 });
this.setState(newState);
}
handleNextPageClick() {
const newState = Object.assign({}, this.state, { page: this.state.page + 1 });
this.setState(newState);
}
handleRowSizeChange(rowSizeIndex, rowSize) {
const newState = Object.assign({}, this.state, { page: 1, rowSize });
this.setState(newState);
}
handleCellClick(tableRow, tableColumn, dataItem, dataItemField) {
const { handleClick } = this.props;
// eslint-disable-next-line no-console
// console.log('handleCellClick', dataItem, dataItemField);
handleClick(dataItem, dataItemField);
}
// eslint-disable-next-line no-unused-vars,no-unused-vars-rest/no-unused-vars
handleCellDoubleClick(tableRow, tableColumn, dataItem, dataItemField) {
}
handleFilterValueChange(...args) {
// eslint-disable-next-line no-console
let filterValue = get(args, '[0]', null);
if (filterValue) {
filterValue = filterValue.toLowerCase();
}
const newState = Object.assign({}, this.state, { filterValue });
this.setState(newState);
}
handleSortOrderChange(...args) {
// eslint-disable-next-line no-console
console.log('SortOrderChange', args);
}
render() {
const { loading, tableColumns, dataItems, dataItemFormatter } = this.props;
if (loading) {
return (
<div>
<RefreshIndicator
size={64}
left={10}
top={10}
status="loading"
style={{
position: 'relative',
}}
/>
</div>
);
} else {
// Only filter if required
let filteredItems = dataItems;
// Filter to select only the items that pass our seach, but only in the selected columns
if (this.state.filterValue) {
filteredItems = filteredItems.filter((item) => {
for (const currentColumn of tableColumns) {
if (get(item, currentColumn.key, '').toString().toLowerCase().includes(this.state.filterValue)) {
return true;
}
}
return false;
});
}
// TODO: Prime reselect location right here
const formattedDataItems =
filteredItems
.slice(this.state.rowSize * (this.state.page - 1), this.state.rowSize * (this.state.page))
.map(dataItemFormatter);
return (
<DataTables
height={'auto'}
selectable={false}
showRowHover
columns={tableColumns}
data={formattedDataItems}
showCheckboxes={false}
showHeaderToolbar
onPreviousPageClick={this.handlePreviousPageClick}
onNextPageClick={this.handleNextPageClick}
onRowSizeChange={this.handleRowSizeChange}
onCellClick={this.handleCellClick}
onCellDoubleClick={this.handleCellDoubleClick}
onFilterValueChange={this.handleFilterValueChange}
onSortOrderChange={this.handleSortOrderChange}
count={dataItems.length}
page={this.state.page}
rowSize={this.state.rowSize}
/>
);
}
}
}
DataTable.propTypes = {
loading: PropTypes.bool,
tableColumns: PropTypes.arrayOf(PropTypes.shape({
key: PropTypes.string,
label: PropTypes.string,
})),
dataItems: PropTypes.arrayOf(PropTypes.object),
dataItemFormatter: PropTypes.func,
handleClick: PropTypes.func,
};
DataTable.defaultProps = {
loading: true,
tableColumns: [
{
key: 'name',
label: 'Name',
},
],
dataItems: [],
dataItemFormatter: item => item,
handleClick: () => {
},
};
@advance512 Thank you for giving us your code! :) @bharadwajag It depends on your data and how you want to implement, but if you are thinking sorting on client side, I think using lodash is a good option. https://lodash.com/docs/4.17.4#sortBy
And also you can find my demo code on gh-pages branch, https://github.com/hyojin/material-ui-datatables/tree/gh-pages/demo/src
@hyojin @advance512 Thanks for the quick reply.
Hi,
I went through your example code but did not understand how to implement it (React novice here). I fetch my data from an external API, store it in props
(eg. this.props.foo.posts
), then map it into table rows.
Could you please help point out how to modify the FakeApi
function in the code below?
FakeAPI(this.state.currentPage, this.state.rowSize, key, order, this.state.filter, (result) => {
this.setState({
total: result.count,
data: result.data,
sort: key,
order: order,
});
});
Any help would be appreciated. Thanks!
@ekaoddlass Hi, FakeAPI just slices data array based on currentPage
and rowSize
parameters and returns it. So if your api already has pagination, call your api, instead of FakeAPI, and just pass page and row size parameter and set the result as data prop. if it doesn't, you can fetch all data then manipulate as same as what FakeAPI does.
I'm not sure what is your problem exactly, if you have troubles with managing data on front-end side, I recommend you to look through the documents of Flux/Redux.
Sorting in example does not work