Related
I have react google chart timeline with chartEvents.
I want when clicked on define chart, display modal window.
On first page load it doesnt work (and when I reload page).
But if I going to another tab in my app,then return to my timeline and click on chart its work without problems.
Please give me advice, whats a problem?
P.S.
I have some thoughts about this:
Problems with load of timeline(in first load page doesnt load all data in google-chart)
Problems with useState(Many counts of useState in my component)
My code example:
Modal.setAppElement('#modal')
interface IItem {
name: string,
duration: string,
id: string,
startDate: Date,
endDate: Date
}
export const options = {
timeline: {
groupByRowLabel: true,
colorByRowLabel: true,
showBarLabels: false,
barLabelStyle: { fontSize: 18 },
},
tooltip: {
isHtml: true
}
}
export function NewGantt() {
const [modalIsOpen, setIsOpen] = useState(false)
const [selectedVacation, setselectedVacation] = useState({ fullname: '', duration: '', startDate: new Date(), endDate: new Date(), vacationId: '' })
const [rows, setrows] = useState([['', '', '', new Date(), new Date(), null, 0, null]])
const [projects, setprojects] = useState<IProject[]>([])
const [selected, setSelected] = useState(selectedOptions[0])
const [dataArray, setDataArray] = useState([
[
{ type: 'string', id: 'Name' },
{ type: 'string', id: 'Duration' },
{ type: 'string', role: 'tooltip', div: { html: true } },
{ type: 'string', id: 'style', role: 'style' },
{ type: 'date', id: 'Start' },
{ type: 'date', id: 'End' },
],
[
'User', '01.01.2022-02.01.2022', `
<div style='padding: 10px'>
<b>User:</b> user <br><hr>
<div style='margin-top: 10px'><b>Vacation dates:</b> 01.01.2022-02.01.2022</div>
</div>
`, 'black', new Date('Sun Mar 12 2023 00:00:00 GMT+0700'), new Date('Sun Mar 13 2023 00:00:00 GMT+0700')
]
]) as any
const { isLoading: isLoadingProjects, refetch: refetch } = useQuery(
['projects'],
async () => {
const res = await axios.get(`${SERVER_URI}/rest/workspace/pm/projects`, {
headers: {
Authorization: `${localStorage.getItem('JWT_Token')}`,
},
})
if (res.data) {
setprojects(res.data.map((el: IProject) => ({ ...el, isActive: false })))
}
},
{
refetchOnWindowFocus: false,
},
)
function projectsButton(project: IProject) {
const projectIndex = projects.findIndex(
(pr) => pr.projectId === project.projectId,
)
const arr = [...projects]
arr[projectIndex].isActive = !arr[projectIndex].isActive
setprojects(arr)
}
useEffect(() => {
const activeProjectIds = [...projects]
.filter((pr) => pr.isActive)
.map((pr) => pr.projectId)
.join(',')
if (activeProjectIds.length > 0) {
requestOfStatus(selected.statusType, activeProjectIds)
} else {
requestOfStatus(selected.statusType, '')
}
}, [projects])
const arr: any[][] = []
useEffect(() => {
const arrayObjects: any[] = [
{ type: 'string', id: 'Name' },
{ type: 'string', id: 'Duration' },
{ type: 'string', role: 'tooltip', div: { html: true } },
{ type: 'string', id: 'style', role: 'style' },
{ type: 'date', id: 'Start' },
{ type: 'date', id: 'End' },
]
rows.forEach((vacation: any) => {
const name = vacation[1]
const startDate = new Date(vacation[2])
const endDate = new Date(vacation[3])
const duration = `${startDate.toLocaleDateString()} - ${endDate.toLocaleDateString()} + ${vacation[0].toString()}`
const tooltip = `
<div style='padding: 10px'>
<b>Пользователь:</b> ${name}<br><hr>
<div style='margin-top: 10px'><b>Dates of vacations:</b> ${startDate.toLocaleDateString()} - ${endDate.toLocaleDateString()}</div>
</div>
`
let color: string
if (vacation[7] === 'decisionRejected') {
color = 'red'
} else if (vacation[7] === 'noDecision') {
color = 'blue'
} else if (vacation[7] === 'decisionApproved') {
color = 'green'
} else {
color = 'black'
}
const object = [name, duration, tooltip, color, startDate, endDate]
arr.push(object)
})
const merged = [arrayObjects, ...arr]
setDataArray(merged)
}, [rows])
const requestOfStatus = async (statusType: string, activeProjectIds: string) => {
const requests = []
const output: any[][] = []
if (statusType === 'all') {
requests.push(await axios.get(`${SERVER_URI}/rest/workspace/pm/vacations?stringProjectIds=${activeProjectIds}&approveType=noDecision`, {
headers: {
Authorization: `${localStorage.getItem('JWT_Token')}`,
},
}))
requests.push(await axios.get(`${SERVER_URI}/rest/workspace/pm/vacations?stringProjectIds=${activeProjectIds}&approveType=decisionApproved`, {
headers: {
Authorization: `${localStorage.getItem('JWT_Token')}`,
},
}))
requests.push(await axios.get(`${SERVER_URI}/rest/workspace/pm/vacations?stringProjectIds=${activeProjectIds}&approveType=decisionRejected`, {
headers: {
Authorization: `${localStorage.getItem('JWT_Token')}`,
},
}))
} else {
requests.push(await axios.get(`${SERVER_URI}/rest/workspace/pm/vacations?stringProjectIds=${activeProjectIds}&approveType=${statusType}`, {
headers: {
Authorization: `${localStorage.getItem('JWT_Token')}`,
},
}))
}
axios.all(requests).then(axios.spread((...res) => {
const rows: any[][] = []
for (let i = 0; i < res.length; i++) {
const merged = [...res[i].data]
const urls = res[i].config.url
merged.forEach((vacation: any) => {
const startDate = new Date(vacation.vacationStartDate)
startDate.setDate(startDate.getDate() - 1)
rows.push([
vacation.vacationId, // index
vacation.user.userDetails.fullName, // user fullname
startDate, // start date
new Date(vacation.vacationEndDate), // end date
++vacation.duration, // duration
100, // progress
null, // dependencies
urls?.split('approveType=')[1].trim()
])
})
}
const flags: never[] = [], l = rows?.length
let i
// eslint-disable-next-line #typescript-eslint/no-explicit-any, #typescript-eslint/ban-ts-comment
// #ts-ignore
for (i = 0; i < l; i++) {
// eslint-disable-next-line #typescript-eslint/no-explicit-any, #typescript-eslint/ban-ts-comment
// #ts-ignore
if (flags[rows[i][3]]) continue;
// eslint-disable-next-line #typescript-eslint/no-explicit-any, #typescript-eslint/ban-ts-comment
// #ts-ignore
flags[rows[i][3]] = true;
// eslint-disable-next-line #typescript-eslint/no-explicit-any, #typescript-eslint/ban-ts-comment
// #ts-ignore
output.push(rows[i]);
}
setrows(output)
}))
}
const openModal = () => {
setIsOpen(()=>{
return true
})
}
return (
<>
<Header />
<div className='flex flex-col justify-center w-10/12 p-6 m-auto'>
<div className='flex flex-row items-center'>
<div className='flex flex-row'>
{!isLoadingProjects &&
projects &&
(projects as [])?.map((project: IProject) => (
<button
key={project.projectId}
onClick={() => {
projectsButton(project)
}}
className={`px-4 py-2 pt-0 mt-5 mr-5 font-bold text-white rounded hover:bg-gray-700 ${!project.isActive
? 'bg-white border-2 text-gray-500 border-gray-500/50'
: 'text-white bg-gray-500'
}`}
>
{project.projectName}
</button>
))}
</div>
<ApproveTypeMenu onSelected={(item: { id: number, name: string, statusType: string }) => { setSelected(item) }} selected={selected} />
<button className='px-4 py-2 pt-0 mt-5 mr-5 font-bold text-white rounded hover:bg-gray-700 bg-white border-2 text-gray-500 border-gray-500/50'>Применить фильтры</button>
</div>
<Chart
chartType="Timeline"
data={dataArray}
width='100%'
height="600px"
options={options}
chartLanguage='ru'
chartEvents={[
{
eventName: 'ready',
callback: (params) => {
const { chartWrapper, google } = params
const chart: any = chartWrapper.getChart()
google.visualization.events.addListener(chart, 'select', () => {
const [fullname, duration, , , startDate, endDate] = dataArray[chart.getSelection()[0].row + 1]
const vacationId = duration.split('+')[1].trim()
setselectedVacation({ fullname: `${fullname}`, duration: `${duration}`, startDate: startDate, endDate: endDate, vacationId: `${vacationId}` })
openModal()
})
},
},
]}
controls={[
{
controlType: 'CategoryFilter',
options: {
filterColumnIndex: 0,
ui: {
allowTyping: true,
allowMultiple: true,
orientation: 'horizontal',
caption: 'Choose colleague',
showRangeValues: false,
label: 'Filter by colleagues',
labelSeparator: ' ',
},
filterColumnLabel: 'Column Label'
},
controlPosition: 'top',
}
]}
/>
</div>
{selectedVacation.vacationId?.length > 0 && (
<PMModal
vacation={selectedVacation}
isModalOpen={modalIsOpen}
setIsModalOpen={setIsOpen}
refetch={refetch}
/>
)}
</>
);
}
My chartEvents code example without 'ready' event
chartEvents={[
{
eventName: 'select',
callback: (params) => {
const { chartWrapper, google } = params
const chart: any = chartWrapper.getChart()
const [fullname, duration, , , startDate, endDate] = dataArray[chart.getSelection()[0].row + 1]
const vacationId = duration.split('+')[1].trim()
setselectedVacation({ fullname: `${fullname}`, duration: `${duration}`, startDate: startDate, endDate: endDate, vacationId: `${vacationId}` })
openModal()
},
},
]}
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>
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 am creating a React app and have the following list:
const list = [
{
id: '1',
task: 'task 1',
activities: [{
'Google': [
{url: 'https://www.google.com'},
{visited: false}
],
'Yahoo': [
{url: 'https://www.yahoo.com'},
{visited: false}
],
'Bing': [
{url: 'https://www.bing.com'},
{visited: false}
]
}],
visitedAll: false
},
{
id: '2',
task: 'task 2',
activities: [{
'Facebook': [
{url: 'https://www.facebook.com'},
{visited: false}
],
'Instagram': [
{url: 'https://www.instagram.com'},
{visited: false}
],
'Twitter': [
{url: 'https://www.twitter.com'},
{visited: false}
]
}],
visitedAll: false
}
];
I am iterating through the list like so:
<ul>
{list.map(item => (
<li key={item.id}>
{item.task}
<ul>
{Object.keys(item.activities[0]).map((act, i) => <li key={i}>{act}</li>)}
</ul>
</li>
))}
</ul>
Which will produce the following output:
task 1
Google
Yahoo
Bing
task 2
Facebook
Instagram
Twitter
How can I wrap the submenu list items with their corresponding anchors?
How do I add an onClick event which will set the visited key to true for each item?
You could first modify activities property to be one object using reduce method and then you can create separate component for sub-items where each holds state with visited property.
const {useState} = React;
const list = [{"id":"1","task":"task 1","activities":[{"Google":[{"url":"https://www.google.com"},{"visited":false}],"Yahoo":[{"url":"https://www.yahoo.com"},{"visited":false}],"Bing":[{"url":"https://www.bing.com"},{"visited":false}]}],"visitedAll":false},{"id":"2","task":"task 2","activities":[{"Facebook":[{"url":"https://www.facebook.com"},{"visited":false}],"Instagram":[{"url":"https://www.instagram.com"},{"visited":false}],"Twitter":[{"url":"https://www.twitter.com"},{"visited":false}]}],"visitedAll":false}]
.map(({activities, ...rest}) => ({
...rest, activities: activities.reduce((r, e) => Object.assign(r, e), {})
}))
const SubListItem = props => {
const {data, name} = props;
const [visited, setVisited] = useState(data[1].visited);
const toggle = event => {
event.preventDefault();
setVisited(!visited);
}
return <li>
<a style={{color: visited ? "green" : ''}}
onClick={toggle}
href={data[0].url}>{name}</a>
</li>
}
const List = ({data}) => <ul>
{data.map(item => <li key={item.id}>
{item.task}
<ul>{Object.keys(item.activities).map(act => (
<SubListItem key={act} name={act} data={item.activities[act]} />
))}</ul>
</li>)}
</ul>
ReactDOM.render(<List data={list} />, document.querySelector("#app"))
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="app"></div>
I would implement an Anchor component which will save the state of visited.
Also, the parent component App would have a state of "all visited anchors".
Example:
const list = [
{
id: '1',
task: 'task 1',
activities: {
Google: {
url: 'https://www.google.com'
},
Yahoo: {
url: 'https://www.yahoo.com'
},
Bing: {
url: 'https://www.bing.com'
}
}
},
{
id: '2',
task: 'task 2',
activities: {
Facebook: {
url: 'https://www.facebook.com'
},
Instagram: {
url: 'https://www.instagram.com'
},
Twitter: {
url: 'https://www.twitter.com'
}
}
}
];
const Anchor = ({ name, href, onClick }) => {
const [isVisited, setIsVisited] = useState(false);
const onAnchorClick = () => {
setIsVisited(visited => !visited);
onClick();
};
return (
// v add href={href}
<a onClick={onAnchorClick}>{`${name} is ${
isVisited ? '' : 'not'
} visited`}</a>
);
};
// You can get such object from reducing the list
const visitedInitial = {
Google: false,
Yahoo: false,
Bing: false,
Facebook: false,
Instagram: false,
Twitter: false
};
const App = () => {
const [visited, setVisited] = useState(visitedInitial);
return (
<>
<h1>
{Object.values(visited).every(value => value === true)
? 'All Visited'
: 'Please visit all'}
</h1>
<ul>
{list.map(({ id, task, activities }) => (
<li key={id}>
{task}
<ul>
{Object.entries(activities).map(([name, { url }], i) => (
<li key={i}>
<Anchor
name={name}
href={url}
target="_blank"
onClick={() =>
setVisited(prev => ({ ...prev, [name]: true }))
}
/>
</li>
))}
</ul>
</li>
))}
</ul>
</>
);
};
Here is the answer based on the items you've provided. I've extracted drawing sub-items into a separate function that accepts an item argument. Every sub-item has an onClick handler which sets visited to true.
import React, { useState, useCallback } from "react";
import ReactDOM from "react-dom";
const initialItems = [
{
id: "1",
task: "task 1",
activities: [
{
Google: [{ url: "https://www.google.com" }, { visited: false }],
Yahoo: [{ url: "https://www.yahoo.com" }, { visited: false }],
Bing: [{ url: "https://www.bing.com" }, { visited: false }]
}
]
},
{
id: "2",
task: "task 2",
activities: [
{
Facebook: [{ url: "https://www.facebook.com" }, { visited: false }],
Instagram: [{ url: "https://www.instagram.com" }, { visited: false }],
Twitter: [{ url: "https://www.twitter.com" }, { visited: false }]
}
]
}
];
function App() {
const [items, setItems] = useState(initialItems);
const setVisited = React.useCallback(
(id, activityName) => {
const item = items.find(item => item.id === id);
if (item) {
item.activities[0][activityName][1].visited = true;
setItems([...items]);
}
},
[items, setItems]
);
const getSubItems = useCallback(
item => {
const activities = item.activities[0];
return Object.keys(activities).map(activityName => {
const url = activities[activityName][0].url;
const onClick = () => {
setVisited(item.id, activityName);
};
return (
<li key={activityName}>
<a
href={url}
onClick={onClick}
target="_blank"
rel="noopener noreferrer"
>
{activityName}
</a>
</li>
);
});
},
[setVisited]
);
return (
<div>
<ul>
{items.map(item => (
<li key={item.id}>
{item.task}
<ul>{getSubItems(item)}</ul>
</li>
))}
</ul>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
EXAMPLE
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.