I try to make function that get an array of object and according to object in the array generate a table with dynamic rowspan.
I tried many solutions but none of them helped.
I tried this code,but I did not continue it because the beginning did not work well
const returnTabel = state => {
return state.map((item, index) => {
return (
<tr key={index}>
{Object.keys(item).map((key, index) => {
if (Array.isArray(item[key])) {
return item[key].map((object, index) => {
return Object.keys(object).map((i, index) => {
if (Array.isArray(object[i])) {
} else {
return (
<tr>
<td>{object[i]}</td>
</tr>
);
}
});
});
} else {
return (
<td rowSpan={2} key={index}>
{item[key]}
</td>
);
}
})}
</tr>
);
});};
Here is my data:
const state = [
{
name: 'Bill',
info: [
{
hobby: 'Practice',
field: [
{ type: 'Swim', hours: '6' },
{ type: 'Run', hours: '7' }
]
},
{
hobby: 'Listen to music',
field: [
{ type: 'Jazz', hours: '3' },
{ type: 'Electronic music', hours: '3' },
{ type: 'Hip hop', hours: '3' }
]
}
],
student: 'No'
},
{
name: 'John',
info: [
{
hobby: 'Practice',
field: [
{ type: 'Swim', hours: '1' },
{ type: 'Run', hours: '2' }
]
}
],
student: 'Yes'
}]
I want to make this table with my data
You can simplify the render mapping if you map the data to rows that look like:
[{"txt":"Bill","rowSpan":5},{"txt":"Practice","rowSpan":2},{"txt":"Swim"},{"txt":"6"},{"txt":"No","rowSpan":5}]
//OR
[null,{"txt":"Listen to music","rowSpan":3},{"txt":"Jazz"},{"txt":"3"},null]
//OR
[null,null,{"txt":"Run"},{"txt":"7"},null]
Then the render simplifies down to:
return (
<table border="1">
{rows.map(cells => (
<tr>
{cells.map(cell => cell && <td rowSpan={cell.rowSpan}>{cell.txt}</td>)}
</tr>
)
)}
</table>
);
Working example
const data=[{name:"Bill",info:[{hobby:"Practice",field:[{type:"Swim",hours:"6"},{type:"Run",hours:"7"}]},{hobby:"Listen to music",field:[{type:"Jazz",hours:"3"},{type:"Electronic music",hours:"3"},{type:"Hip hop",hours:"3"}]}],student:"No"},{name:"John",info:[{hobby:"Practice",field:[{type:"Swim",hours:"1"},{type:"Run",hours:"2"}]}],student:"Yes"}];
const rowData = data.reduce((a, { name, info, student }) => {
const rowSpan = info.reduce((a, { field }) => a + field.length, 0);
let [firstCell, lastCell] = [name, student].map(txt => ({ txt, rowSpan }));
info.forEach(({ hobby, field }, i) => {
const rowSpan = field.length;
let hobCell = { txt: hobby, rowSpan };
field.forEach((f, j) => {
const fieldCells = Object.values(f).map(txt => ({ txt }));
if (j > 0) {
hobCell = firstCell = lastCell = null;
}
const row = [firstCell, hobCell, ...fieldCells, lastCell];
a.push(row);
});
});
return a;
}, []);
console.log( rowData)
const Table = () => {
const [rows] = React.useState(rowData);
return (
<table border="1">
{rows.map((cells,i) => (
<tr key={i}>
{cells.map((cell,j) => cell && <td key={`${i}-${j}`} rowSpan={cell.rowSpan}>{cell.txt}</td>)}
</tr>
)
)}
</table>
);
};
// Render it
ReactDOM.render(
<Table />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Related
I am working on the table content which has 5 rows . few rows content description is same so I need to show only one row in this case and give expan button. when expand button is clicked it should show all the rows which has the same associated description. I am pasting the screenshot which I got as output .
In the above screenshot I've got the "-" button for all the rows which has same description. but I need only one "-"(collapse) button for "paytm" and one "-"button for "Paypal". and when they are clicked only one paytm, PayPal should be displayed.
let rows = [
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/04/2021' }
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/03/2020' }
},
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2021' }
},
{
id: { value: '' },
description: { value: 'Gpay' },
DueDate: { value: '04/03/2020' }
},
];
I am showing the table based on the lasted date and check if there exists any multiple same descriptions and putting them all in one object.
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = [
...(acc[current.description.value] || []),
current,
];
return acc;
}, {});
console.log(descriptionSortedArray);
and transforming the object based on latest date
const transformedRows = Object.keys(descriptionSortedArray).reduce(
(acc, current) => {
acc[current] = sortRowsByDate(descriptionSortedArray[current]);
return acc;
},
{}
);
// console.log(Object.keys(descriptionSortedArray));
console.log({ transformedRows });
and getting the key values for them by using object.keys and mapping over them.
x.[paytm:[], Gpay:[], PayPal :[]];
based on the inner array key length I am showing button (expand and collapse)if
x[paytm]>1 ?show button: without button
code is below
import React, { Component } from 'react';
import './style.css';
export default class App extends React.Component {
render() {
let rows = [
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/04/2021' }
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/03/2020' }
},
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2021' }
},
{
id: { value: '' },
description: { value: 'Gpay' },
DueDate: { value: '04/03/2020' }
},
];
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = [
...(acc[current.description.value] || []),
current,
];
return acc;
}, {});
console.log(descriptionSortedArray);
const sortRowsByDate = (rows) =>
rows.sort(
(a, b) => new Date(b.DueDate.value) - new Date(a.DueDate.value)
);
const transformedRows = Object.keys(descriptionSortedArray).reduce(
(acc, current) => {
acc[current] = sortRowsByDate(descriptionSortedArray[current]);
return acc;
},
{}
);
// console.log(Object.keys(descriptionSortedArray));
console.log({ transformedRows });
return (
<div>
<table>
<tr>
<th>id</th>
<th>description</th>
<th>duedate</th>
<th></th>
</tr>
{Object.keys(transformedRows).map((rowKey) => {
// console.log("rowKey===", rowKey)
// console.log(transformedRows[rowKey])
return (
<tbody>
{transformedRows[rowKey].length > 1
? transformedRows[rowKey].map((obj) => (
<tr>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td>{<button>-</button>}</td>
</tr>
))
: transformedRows[rowKey].map((obj) => (
<tr>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td></td>
</tr>
))}
</tbody>
);
})}
</table>
</div>
);
}
}
Please help in this. I need to show only one collapse button for the rows having same description(paytm is repeated show them only in one row give "expand" and "collapse" button). when even button is clicked it should be toggled. Please help
You can keep another field called visible along with your data array and toggle its value when clicked on the button.
Define a state to store the transformedRows
state = {
transformedRows: {}
};
Do the transformation like below in componentDidMount.
componentDidMount = () => {
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = {
...acc[current.description.value],
data: [...(acc[current.description.value]?.["data"] ?? []), current],
visible: false
};
return acc;
}, {});
const sortRowsByDate = (rows) =>
rows.sort(
(a, b) => new Date(b.DueDate.value) - new Date(a.DueDate.value.data)
);
const transformedRows = Object.keys(descriptionSortedArray).reduce(
(acc, current) => {
acc[current] = {
...descriptionSortedArray[current],
data: sortRowsByDate(descriptionSortedArray[current]["data"])
};
return acc;
},
{}
);
this.setState({ transformedRows });
};
Toggle the visible state when clicking on the button.
handleToggle = (entry, visibility) => {
this.setState((prevState) => {
return {
...prevState,
transformedRows: Object.fromEntries(
Object.entries(prevState.transformedRows).map(([key, value]) => {
if (key === entry) {
return [key, { ...value, visible: visibility }];
} else {
return [key, value];
}
})
)
};
});
};
Render rows as below.
<tbody>
{Object.entries(transformedRows).map(([key, { data, visible }]) => {
if (data.length > 1) {
return data.map((item, index) => (
<tr>
{(index === 0 || (index >= 1 && visible)) && (
<>
<td>{item.id.value}</td>
<td>{item.description.value}</td>
<td>{item.DueDate.value}</td>
</>
)}
{index === 0 && (
<td>
{
<button
onClick={() => {
this.handleToggle(key, !visible);
}}
>
toggle
</button>
}
</td>
)}
</tr>
));
} else {
return data.map(item => (
<tr>
<td>{item.id.value}</td>
<td>{item.description.value}</td>
<td>{item.DueDate.value}</td>
</tr>
));
}
})}
</tbody>
Create an accordion component as follow:
React accordion
Then use it as follow:
return (
<div>
<table>
<thead>
<tr>
<th>id</th>
<th>description</th>
<th>duedate</th>
<th></th>
</tr>
</thead>
{Object.keys(transformedRows).map((rowKey) => {
// console.log("rowKey===", rowKey)
// console.log(transformedRows[rowKey])
console.log(rowKey);
return (
<tbody key={rowKey}>
{transformedRows[rowKey].length > 1 ? (
<tr>
<td colSpan="4">
<Accordion label={rowKey}>
{transformedRows[rowKey].map((obj) => (
<div key={obj.id.value}>
<span>{obj.id.value}</span>
<span>{obj.description.value}</span>
<span>{obj.DueDate.value}</span>
<span>{<button>-</button>}</span>
</div>
))}
</Accordion>
</td>
</tr>
) : (
transformedRows[rowKey].map((obj) => (
<tr key={obj.id.value}>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td></td>
</tr>
))
)}
</tbody>
);
})}
</table>
</div>
);
Full code:
let rows = [
{
id: { value: '1' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '2' },
description: { value: 'paypal' },
DueDate: { value: '04/04/2021' },
},
{
id: { value: '3' },
description: { value: 'paypal' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '4' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2021' },
},
{
id: { value: '5' },
description: { value: 'Gpay' },
DueDate: { value: '04/03/2020' },
},
];
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = [...(acc[current.description.value] || []), current];
return acc;
}, {});
console.log(descriptionSortedArray);
const sortRowsByDate = (rows) =>
rows.sort((a, b) => new Date(b.DueDate.value) - new Date(a.DueDate.value));
const transformedRows = Object.keys(descriptionSortedArray).reduce((acc, current) => {
acc[current] = sortRowsByDate(descriptionSortedArray[current]);
return acc;
}, {});
return (
<div>
<table>
<thead>
<tr>
<th>id</th>
<th>description</th>
<th>duedate</th>
<th></th>
</tr>
</thead>
{Object.keys(transformedRows).map((rowKey) => {
// console.log("rowKey===", rowKey)
// console.log(transformedRows[rowKey])
console.log(rowKey);
return (
<tbody key={rowKey}>
{transformedRows[rowKey].length > 1 ? (
<tr>
<td colSpan="4">
<Accordion label={rowKey}>
{transformedRows[rowKey].map((obj) => (
<div key={obj.id.value}>
<span>{obj.id.value}</span>
<span>{obj.description.value}</span>
<span>{obj.DueDate.value}</span>
<span>{<button>-</button>}</span>
</div>
))}
</Accordion>
</td>
</tr>
) : (
transformedRows[rowKey].map((obj) => (
<tr key={obj.id.value}>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td></td>
</tr>
))
)}
</tbody>
);
})}
</table>
</div>
);
Im quite new to reactJS and ive been trying to create a table sorting based on this https://www.florin-pop.com/blog/2019/07/sort-table-data-with-react/. All works fine, did some changes and all, except my setState doesnt seem to update the my sorting. Here are some of my codes:
class TableView extends Component {
constructor(props) {
super(props)
this.state = {
students: [
{ name: 'Brian', age: 20, email: 'brian#hotmail.com' },
{ name: 'Kathy', age: 42, email: 'kathy#gmail.com' },
{ name: 'Donney', age: 50, email: 'donneylee#sjks.com' },
{ name: 'Cindy', age: 36, email: 'cindy#jflasjfl.com'}
]
}
this.headers = ['name', 'age', 'email'];
this.sortTypes = {
up: {
fn: (a, b) => { if (a.name < b.name) { return - 1 }}
},
down: {
fn: (a, b) => { if (a.name > b.name) { return 1 }}
},
default: {
fn: (a, b) => a
}
};
this.stateSort = {
currentSort: 'default'
};
}
onSortAsc = () => {
const { currentSort } = this.stateSort;
this.setState({ currentSort: 'up' }, () => {
console.log(currentSort);
});
}
renderTableData() {
const { currentSort } = this.stateSort;
const data = this.state.students;
return (
( data.length > 0 && (
[...data].sort(this.sortTypes[currentSort].fn).map(p => (
<tr key={p.name}>
<td>{p.name}</td>
<td>{p.age}</td>
<td>{p.email}</td>
</tr>
))
)
))
}
renderTableHeader() {
return<th key={index}>{key}<DropdownButton menuAlign="right" className="table-dropdown" title="">
<Dropdown.Item onClick={this.onSortAsc}>Sort A-Z</Dropdown.Item>
<Dropdown.Item href="#/action-2">Sort Z-A</Dropdown.Item>
</DropdownButton></th>
}
//The table
render() { //Whenever our class runs, render method will be called automatically, it may have already defined in the constructor behind the scene.
return (
<div>
<div id="table-view">
<button>Hide Fields</button>
<span class="more-btn"><FaEllipsisH /></span>
<div id="table-content">
<table id='funding-stage'>
<thead>
<tbody>
<tr>{this.renderTableHeader()}</tr>
{this.renderTableData()}
</tbody>
</thead>
</table>
</div>
</div>
</div>
)
}
};
export default Tableview;
Im not sure what went wrong. Ive tried different solutions but nothing seems to work.
The currentSort state should be in the state object (e.g you should access it as this.state.currentSort ) if you put it in another object ( stateSort ) and that object is the one in the state object, changing it will not cause update or rerender.
1 - remove
this.stateSort = {
currentSort: 'default'
};
2 - add currentSort to state object
this.state = {
students: [
{ name: 'Brian', age: 20, email: 'brian#hotmail.com' },
{ name: 'Kathy', age: 42, email: 'kathy#gmail.com' },
{ name: 'Donney', age: 50, email: 'donneylee#sjks.com' },
{ name: 'Cindy', age: 36, email: 'cindy#jflasjfl.com'}
],
currentSort: 'default'
}
3 - in onSortAsc function
onSortAsc = () => {
this.setState({ currentSort: 'up' }, () => {
console.log(currentSort);
});
}
and If that didn't help, update your code snippet and show the whole component to help you better.
I want to display movies row-by-row without changing the data model.
Here's my code:
import * as React from "react";
import { useTable } from "react-table";
const borderStyle = {
border: "1px dashed navy"
};
export default function App() {
const data = React.useMemo(
() => [
{
actor: "Johnny Depp",
movies: [
{
name: "Pirates of the Carribean 1"
},
{
name: "Pirates of the Carribean 2"
},
{
name: "Pirates of the Carribean 3"
},
{
name: "Pirates of the Carribean 4"
}
]
}
],
[]
);
const columns = React.useMemo(
() => [
{
Header: "Actor",
accessor: "actor",
},
{
Header: "Movies",
accessor: (row, index) => {
console.log({ row });
// i want to display this row-by-row instead of in 1-row without changing data model
return row.movies.map(movie => movie.name);
}
}
],
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({ columns, data });
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()} style={borderStyle}>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row);
if (i == 0) {
console.log({ row });
}
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell, j) => {
if (i == 0 && j < 2) {
console.log({ cell, i, j });
}
return (
<td
{...cell.getCellProps()}
style={borderStyle}
>
{cell.render("Cell")}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
}
It currently looks like:
Here's the direct link to it: https://codesandbox.io/s/modest-sanderson-z0keq?file=/src/App.tsx
My movie list is an array of objects so how will I display it beside actor name? So it looks like:
There is no other way to do it rather than by flattening the data as the author of the library mentioned, so here's how I did it:
import * as React from "react";
import { useTable } from "react-table";
type Data = {
actor: string;
movie: string;
}
const borderStyle = {
border: "1px dashed navy"
};
export default function App() {
const origData = [
{
actor: "Johnny Depp",
movies: [
{
name: "Pirates of the Carribean 1"
},
{
name: "Pirates of the Carribean 2"
},
{
name: "Pirates of the Carribean 3"
},
{
name: "Pirates of the Carribean 4"
}
]
}
];
const newData: Array<Data> = [];
origData.forEach(actorObj => {
actorObj.movies.forEach(movie => {
newData.push({
actor: actorObj.actor,
movie: movie.name
});
});
});
const data = React.useMemo(() => newData, []);
const columns = React.useMemo(
() => [
{
Header: "Actor",
accessor: "actor"
},
{
Header: "Movies",
accessor: "movie"
}
],
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({ columns, data });
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()} style={borderStyle}>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row);
if (i == 0) {
console.log({ row });
}
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell, j) => {
if (i == 0 && j < 2) {
console.log({ cell, i, j });
}
return (
<td
rowSpan={cell.rowSpan}
{...cell.getCellProps()}
style={borderStyle}
>
{cell.render("Cell")}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
}
I'm using the react-sortablejs library.
When trying to move cards within the list. I get the error:
Cannot read property 'map' of undefined
I have a dense structure and it gets lost here. How to handle onChange so that I can see in the console that the order of the notes within the list has changed.
Demo here
import Sortable from 'react-sortablejs';
// Functional Component
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
onChange={(order, sortable, evt) => {
console.log(order)
onChange(order);
}}
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
class App extends React.Component {
state = {
item: {
id: "abc123",
name: "AAA",
lists: [
{
id: "def456",
list_id: "654wer",
title: 'List1',
desc: "description",
listItems: [
{
id: "ghj678",
title: "ListItems1",
listItemsId: "88abf1"
},
{
id: "poi098",
title: "ListItems2",
listItemsId: "2a49f25"
},
{
id: "1oiwewedf098",
title: "ListItems3",
listItemsId: "1a49f25dsd8"
}
]
},
{
id: "1ef456",
list_id: "654wer",
title: 'List 2',
desc: "description",
listItems: [
{
id: "1hj678",
title: "ListItems4",
listItemsId: "18abf1"
},
{
id: "1oi098",
title: "ListItems5",
listItemsId: "1a49f25"
},
{
id: "1oiwewe098",
title: "ListItems6",
listItemsId: "1a49f25dsd"
}
]
},
{
id: "2ef456",
title: 'List 3',
list_id: "254wer",
desc: "description",
listItems: [
{
id: "2hj678",
title: "ListItems7",
listItemsId: "28abf1"
},
{
id: "2oi098",
title: "ListItems8",
listItemsId: "234a49f25"
},
{
id: "df098",
title: "ListItems9",
listItemsId: "1asd8"
}
]
}
]
}
};
render() {
const c = this.state.item['lists'].map(item => { return item.listItems});
return (
this.state.item['lists'].map(item => {
return (<div>
{item.title}
<SortableList
key={uniqueId()}
items={item}
onChange={(item) => {
console.log(item)
this.setState({item});
}}
>
</SortableList>
</div>)
})
)
}
};
Thanks in advance.
You have to update few changes in your code.
Update the SortableList function as below.
First pass data-id={val.id} in li and after that in onChange method you will receive the order with id. So based on that we are sorting the records.
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
onChange={(order, sortable, evt) => {
items.listItems.sort(function(a, b){
return order.indexOf(a.id) - order.indexOf(b.id);
});
onChange(items);
}}
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val.id}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
Update the onChange event of App component.
onChange={(item) => {
let itemObj = {...this.state.item};
itemObj.lists.map(x=>{
if(x.id === item.id) x = item;
});
this.setState({itemObj});
}}
That's it!
Here is the working demo for you
https://stackblitz.com/edit/react-sortablejs-blzxwd
When remove the onChange event in the Sortable list, Its works.
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
I try to convert react class component to stateless component, I'm not a goood with complex stateless component. What is the best practice to do that. Now I've got to component, Table and EnchanceTable, I want to convert Table to stateless, with all functgion I have inside and without any state. I've started already with thsi but not quite sure is it true way.
Table component(should be stateless)
class Table extends React.Component {
static propTypes = {
columns: PropTypes.arrayOf(columnsShape),
}
constructor(props) {
super(props)
this.state = {
order: 'asc',
orderBy: this.props.orderBy,
selected: [],
searchValue: '',
data: this.props.data,
filterData: this.props.data,
}
}
defaultCellRenderer = ({item, dataKey}) =>
item[dataKey]
handleRequestSort = (event, property) => {
const orderBy = property
let order = 'desc'
if (this.state.orderBy === property && this.state.order === 'desc') {
order = 'asc'
}
const filterData = this.state.filterData.sort(
(a, b) => order === 'desc' ? b[orderBy] > a[orderBy] : a[orderBy] > b[orderBy],
)
this.setState({ filterData, order, orderBy })
}
handleSelectAllClick = (event, checked) => {
const {data,selected, onSelectAll} = this.props
if (checked) {
this.setState({ selected: this.state.data.map(item => item.id) })
}
else
this.setState({ selected: [] })
}
unselectSelected = () => {
this.setState({selected: []})
}
deleteSelected = () => {
const {data, selected, onDelete} = this.props
onDelete(selected)
}
handleKeyDown = (event, id) => {
if (keycode(event) === 'space') {
this.handleClick(event, id)
}
}
handleClick = (event, id) => {
const { selected } = this.state
const selectedIndex = selected.indexOf(id)
let newSelected = []
if (selectedIndex === -1) {
newSelected = newSelected.concat(selected, id)
} else if (selectedIndex === 0) {
newSelected = newSelected.concat(selected.slice(1))
} else if (selectedIndex === selected.length - 1) {
newSelected = newSelected.concat(selected.slice(0, -1))
} else if (selectedIndex > 0) {
newSelected = newSelected.concat(
selected.slice(0, selectedIndex),
selected.slice(selectedIndex + 1),
)
}
this.setState({ selected: newSelected })
}
handleSearch = event => {
const {data} = this.state
let filteredDatas = []
filteredDatas = data.filter(e => {
let mathedItems = Object.values(e)
let returnedItems
mathedItems.forEach(e => {
const regex = new RegExp(event.target.value, 'gi')
if (typeof e == 'string')
returnedItems = e.match(regex)
})
return returnedItems
})
this.setState({filterData: filteredDatas, searchValue: event.target.value})
}
isSelected = id => this.state.selected.indexOf(id) !== -1;
render() {
const { data, order, orderBy, selected } = this.state
const {selectable, columns, children, filtering, numSelected, ...others} = this.props
return (
<div>
{selectable &&
<EnhancedTableToolbar
numSelected={selected.length}
handleSearch={this.handleSearch}
value={this.searchValue}
unselectSelected={this.unselectSelected}
deleteSelected={this.deleteSelected}
/> }
<MuiTable >
{selectable
? <EnhancedTableHead
columns={columns}
numSelected={selected.length}
order={order}
orderBy={orderBy}
onSelectAllClick={this.handleSelectAllClick}
onRequestSort={this.handleRequestSort}
/>
: <TableHead>
<TableRow >
{columns.map(({dataKey, label}) =>
<TableCell>
{label}
</TableCell>)}
</TableRow>
</TableHead>
}
<TableBody>
{data.map((item, index) => {
const isSelected = this.isSelected(item.id)
return selectable
? <TableRow
hover
onClick={event => this.handleClick(event, item.id)}
onKeyDown={event => this.handleKeyDown(event, item.id)}
role="checkbox"
aria-checked={isSelected}
tabIndex="-1"
key={item.id}
selected={isSelected}
>
<TableCell checkbox>
<Checkbox checked={isSelected}/>
</TableCell>
{columns.map(({dataKey, cellRenderer, numeric}) =>
<TableCell numeric={numeric}>
{(cellRenderer || this.defaultCellRenderer)({item, dataKey})}
</TableCell>)}
</TableRow>
: <TableRow hover>
{columns.map(({dataKey, cellRenderer, numeric}) =>
<TableCell numeric={numeric}>
{(cellRenderer || this.defaultCellRenderer)({item, dataKey})}
</TableCell>)}
</TableRow>
})}
</TableBody>
</MuiTable>
</div>
)}
}
EnchancedTable class component(interactivity component)
const columns = [
{
dataKey: 'deviceType',
label:'Device Type',
numeric: false,
}, {
dataKey: 'deviceID',
label:'Device ID',
sortable: true,
numeric: true,
// cellRenderer: ({item, dataKey}) =>
// <Button >Default</Button>,
}, {
dataKey: 'name',
label: 'Name',
sortable: true,
numeric: false,
},{
dataKey: 'currentVersion',
label: 'Current Version',
sortable: true,
numeric: false,
},{
dataKey: 'location',
label: 'Location',
sortable: true,
numeric: false,
},{
dataKey: 'status',
label: 'Status',
sortable: true,
numeric: false,
},{
dataKey: 'lastAliveMessage',
label: 'Last alive message',
sortable: true,
numeric: false,
}, {
dataKey: 'action',
label: 'Actions',
cellRenderer: () => <SimpleMenu />,
}]
const data = [
{ id: 1, deviceType: 'Tag', deviceID: 1, name:'Tag For sending an ', location: 'Room_104', status: 'assigned'},
{ id: 2, deviceType: 'Tag', deviceID: 2, name:'Tag For sending an ', location: 'Room_104', status: 'assigned'},
{ id: 3, deviceType: 'Tag', deviceID: 3, name:'Tag For sending an ', location: 'Room_104', status: 'assigned'},
{ id: 4, deviceType: 'Tag', deviceID: 4, name:'Tag For sending an ', location: 'Room_104', status: 'assigned'},
{ id: 5, deviceType: 'Tag', deviceID: 5, name:'Tag For sending an ', location: 'Room_104', status: 'assigned'},
]
class EnhancedTable extends {Component} {
state = {
selected: [],
data,
}
render = () => {
const {selected, data} = this.state
return (
<Paper>
<Table
data={data}
selectable
columns={columns}
orderBy='deviceId'
selected={selected}
onSelect={selected => this.setState({selected})}
onDelete={items => this.setState({data: data.filter((item, index) => !items.includes(index))})}
onSelectAll={}
/>
</Paper>)
}
}
The best way to implement a stateless component in react is to use recompose. You can see my this answer.