Reputation: 6176
There is a component, GenericTable
that receives as attributes the data.
in the component which has the data:
const headers = ['ID', 'Name', 'City'];
const rows = [{cells: ['1', 'John', 'Paris']},
{cells: ['3', 'Ben', 'Berlin']},
{cells: ['2', 'Helen', 'Barcelona']}
];
const idList = ['1', '3', '2'];
<GenericTable
headers={headers}
rows={rows}
idList={idList}
/>
in GenericTable:
import { Table } from 'semantic-ui-react';
export default class GenericTable extends React.PureComponent {
constructor(props) {
super(props);
}
render() {
const { headers, rows, idList } = this.props;
return (
<Table>
<Table.Header>
<Table.Row>
{headers.map(header => (
<Table.HeaderCell key={headers.indexOf(header)}>
{header}
</Table.HeaderCell>
)}
</Table.Row>
</Table.Header>
<Table.Body>
{rows.map((row, rowIndex) => (
<Table.Row key={idList && idList[rowIndex]}>
<Table.Cell>
...
</Table.Cell>
</Table.Row>
)}
</Table.Body>
</Table>
);
}
}
Is there a way to make the table sortable? For example, add a button near name header and when it is clicked to sort the table alphabetically based on that column?
I've tried to solve it but it doesn't work. I added the default value in the state, a button for each column header which can be clicked, and when it's clicked it should sort the data based on that column:
import { Table } from 'semantic-ui-react';
export default class GenericTable extends React.PureComponent {
constructor(props) {
super(props);
this.state = { // added state
currentSort: 'default',
};
}
onSortChange = () => { // added method
const { currentSort } = this.state;
let nextSort;
if (currentSort === 'down') nextSort = 'up';
else if (currentSort === 'up') nextSort = 'default';
else if (currentSort === 'default') nextSort = 'down';
this.setState({
currentSort: nextSort,
});
};
render() {
const { currentSort } = this.state; // added state
const sortTypes = { // added constant
up: {
class: 'sort-up',
fn: (a, b) => a.name - b.name,
},
down: {
class: 'sort-down',
fn: (a, b) => b.name - a.name,
},
default: {
class: 'sort',
fn: (a, b) => a,
},
};
const { headers, rows, idList } = this.props;
return (
<Table>
<Table.Header>
<Table.Row>
{headers.map(header => (
<Table.HeaderCell key={headers.indexOf(header)}>
{header}
// added button
<button onClick={this.onSortChange} type="button">
<i className={`fas fa-${sortTypes[currentSort].class}`} />
</button>
</Table.HeaderCell>
)}
</Table.Row>
</Table.Header>
<Table.Body>
// added below
{[...rows].sort(sortTypes[currentSort].fn).map((row, rowIndex) => (
<Table.Row key={idList && idList[rowIndex]}>
<Table.Cell>
...
</Table.Cell>
</Table.Row>
)}
</Table.Body>
</Table>
);
}
}
Upvotes: 1
Views: 3809
Reputation: 1963
You can safe the rows prop in the component state. If the table header is clicked you can update the state with the onSortChange function
<Table.Row>
{headers.map((header,index) => (
<Table.HeaderCell key={headers.indexOf(header)}>
{header}
// added below
<button onClick={() => this.onSortChange(index)} type="button">
<i className={`fas fa-${sortTypes[currentSort].class}`} />
</button>
</Table.HeaderCell>
)}
</Table.Row>
onSortChange = (i) => { // added method
var newRows = rows.sort(function(a, b){
if(a.cells[i] < b.cells[i]) { return -1; }
if(a.cells[i] > b.cells[i]) { return 1; }
return 0;
})
this.setState({rows: newRows})
};
/Edit I did an example here
https://codesandbox.io/s/nervous-elbakyan-g9tw5?fontsize=14&hidenavigation=1&theme=dark
Upvotes: 1
Reputation: 499
Here is an example of how you can implement sorting using lodash. Note am using Hooks although I see you are still using classes but you should still be able to use the code either way. Just need to use component state instead of the useReducer hook. You can also use vanilla JS instead of lodash.
import _ from 'lodash'
import React from 'react'
import { Table } from 'semantic-ui-react'
const headers = ['ID', 'Name', 'City'];
const rows = [{cells: ['1', 'John', 'Paris']},
{cells: ['3', 'Ben', 'Berlin']},
{cells: ['2', 'Helen', 'Barcelona']}
];
const columnsData = rows.map(row => {
return {ID: row.cells[0], Name: row.cells[1], City: row.cells[2] }
})
function tableReducer(state, action) {
switch (action.type) {
case 'CHANGE_SORT':
if (state.column === action.column) {
return {
...state,
data: state.data.reverse(),
direction:
state.direction === 'ascending' ? 'descending' : 'ascending',
}
}
return {
column: action.column,
data: _.sortBy(state.data, [action.column]),
direction: 'ascending',
}
default:
throw new Error()
}
}
function TableExampleSortable() {
const [state, dispatch] = React.useReducer(tableReducer, {
column: null,
data: columnsData,
direction: null,
})
const { column, data, direction } = state
return (
<Table>
<Table.Header>
<Table.Row>
{headers.map(header => (
<Table.HeaderCell key={headers.indexOf(header)}
sorted={column === header ? direction : null}
onClick={() => dispatch({ type: 'CHANGE_SORT', column: header })}>
{header}
</Table.HeaderCell>
))}
</Table.Row>
</Table.Header>
<Table.Body>
{data.map(({ ID, Name, City }) => (
<Table.Row key={ID}>
<Table.Cell>{ID}</Table.Cell>
<Table.Cell>{Name}</Table.Cell>
<Table.Cell>{City}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
)
}
export default TableExampleSortable
Upvotes: 0