Global table search react - javascript

I try to implement global search with new material ui next table component, I have handleSearch method, wich recives event, and than I use regexp to check if event.target.value the same as in table. But when I delete string in search, the columns not update. It starts to search only I start type. How to search by number not only by string in this case
const columns = [
{
dataKey: 'deviceType',
label:'Device Type',
numeric: false,
}, {
dataKey: 'deviceID',
label:'Device ID',
sortable: true,
numeric: true,
// cellRenderer: ({item, key}) =>
// <Button >Default</Button>,
}, {
........
}]
const data = [
{ key: 1, deviceType: 'Tag', deviceID: 1, name:'Tag For sending an ', location: 'Room_104', status: 'assigned'},
{ key: 2, deviceType: 'Tag', deviceID: 2, name:'Tag For sending an ', location: 'Room_104', status: 'assigned'},
{.......},
]
class EnhancedTable extends Component {
state = {
selected: [],
data,
order: {
direction: 'asc',
by: 'deviceID',
},
search: '',
}
handleSearch = event => {
debugger
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({data: filteredDatas, search: event.target.value})
}
render = () => {
const {data, search} = this.state
return (
<Paper>
<Table
data={data}
search={search}
onSearch={this.handleSearch}
/>
</Paper>)
}
}
export default EnhancedTable

fuzzyContains = (text, search) => {
debugger
if (!text)
return false
if (!search)
return true
search = search.toLowerCase()
text = text.toString().toLowerCase()
let previousLetterPosition = -1
return search.split('').every(s => {
debugger
previousLetterPosition = text.indexOf(s, previousLetterPosition + 1)
return previousLetterPosition !== -1
})
}
handleSearch = search => {
const {data} = this.state
// debugger
let filteredData = data.filter(x => Object.keys(x).some(key =>
// debugger
this.fuzzyContains(x[key], search)
))
console.log(filteredData)
this.setState({filteredData, search})
}

Related

onRowDoubleClick shouldn't trigger onSelectionChange in prime-react

I have a project with nextjs and typescript.I use prime react as a UI kit for my project.
On one of my pages I have a table and in this table I have a checkbox per row for select that row
also if user dblClicked on a row it should navigate into another page.my issue is when I dblClick on a row checkbox is triggered(onSelectionChange method trigger). I know that prime table can get selectionMode='checkbox' prop and in that case checkbox triggered only if user clicks on a checkbox itself but I want if user singleClicks on a row onSelectionChange trigger too.
I wrote a wrapper for prime table component (<"Table someProps />)
this is my code
import React, {useEffect, useState} from 'react';
import {DataTableDataSelectableParams} from 'primereact/datatable';
import Table from '../Table';
import {AutoCompleteCompleteMethodParams} from 'primereact/autocomplete';
import {FlightStaticService} from '../../../adapter/FlightStaticService';
import OptionsMenu from '../../OptionsMenu/OptionsMenu';
import {InputSwitch} from 'primereact/inputswitch';
import InputWrapper from '../../InputWrapper/InputWrapper';
import {FlightService} from '../../../adapter/FlightService';
import ConfirmationStatus from '../../ConfirmationStatus/ConfirmationStatus';
import {useRouter} from 'next/router';
const flightStaticInstance = new FlightStaticService();
const flightInstance = new FlightService();
const FlightsListTable = () => {
const [selectedRows, setSelectedRows] = useState<{ [key: string]: string | number | boolean }[]>([]);
const [filteredAirlines, setFilteredAirlines] = useState([]);
const [filteredAirports, setFilteredAirports] = useState([]);
const [shouldUpdateTable, setShouldUpdateTable] = useState(false);
const router = useRouter();
const searchAirlines = (e: AutoCompleteCompleteMethodParams) => {
if (!e.query) {
e.query = 'as';
}
flightStaticInstance
.getAirlines(e.query)
.then((res) => {
setFilteredAirlines(res.data.result);
})
.catch(e => {
setFilteredAirlines([]);
});
};
const searchAirports = (e: AutoCompleteCompleteMethodParams) => {
if (!e.query) {
e.query = 'meh';
}
flightStaticInstance
.getAirports(e.query)
.then((res) => {
setFilteredAirports(res.data.result);
})
.catch(e => {
setFilteredAirports([]);
});
};
const isRowSelectable = (event: DataTableDataSelectableParams) => {
const data = event.data;
if (selectedRows.find((sel) => sel.id === data.id)) {
return true;
}
return selectedRows.length < 2 && data.isActive;
};
useEffect(() => {
if (shouldUpdateTable) {
setShouldUpdateTable(false);
}
}, [shouldUpdateTable]);
useEffect(() => {
if (selectedRows.length > 0) {
sessionStorage.setItem('flights', JSON.stringify(selectedRows));
}
}, [selectedRows]);
const confirmStatusBodyTemplate = (rowData: any) => {
return <ConfirmationStatus status={rowData.status}/>
};
const statusBodyTemplate = (rowData: any) => {
return rowData.isActive ? 'فعال' : 'غیرفعال';
};
const optionsBodyTemplate = (rowData: any) => {
return <OptionsMenu options={[{
type: 'link',
url: `/flight/${rowData.id}`,
label: 'جزییات پرواز',
iconName: 'icon-note-text2'
}, {
type: 'link',
url: `/flight/${rowData.id}/edit`,
label: 'ویرایش پرواز',
iconName: 'icon-edit-2'
},
{
type: 'link',
url: `/flight/${rowData.id}/pricing?flightGroupTitle=${rowData.flightGroupTitle}`,
label: 'تقویم قیمتی',
iconName: 'icon-calendar-2'
},
{
type: 'element',
element: <div className='w-full' onClick={e => e.stopPropagation()}>
<InputWrapper labelClassName='text-grey-4' className='w-full' labelBeforeInput={true}
labelBesideInput label='وضعیت'>
<InputSwitch
onChange={e => {
flightInstance.toggleFlightStatus(rowData.id).then(res => {
setShouldUpdateTable(true);
}).catch(e => {
});
}
}
checked={rowData.isActive}
className='mr-auto'/>
</InputWrapper>
</div>
}
]}/>
}
return (
<Table
url="/Flight/GetFlights"
shouldUpdateTable={shouldUpdateTable}
filters={[
{
name: 'airlineId',
label: 'ایرلاین',
type: 'autocomplete',
value: '',
suggestions: filteredAirlines,
completeMethod: searchAirlines,
optionValue: 'iata',
optionType: 'string',
fieldName: 'nameFa'
},
{
name: 'flightGroupTitle',
label: 'عنوان پرواز',
type: 'text',
value: ''
},
{
name: 'originAirPortId',
label: 'فرودگاه مبدا',
type: 'autocomplete',
value: '',
optionValue: 'iata',
optionType: 'string',
suggestions: filteredAirports,
completeMethod: searchAirports,
fieldName: 'nameFa'
},
{
name: 'destinationAirPortId',
label: 'فرودگاه مقصد',
type: 'autocomplete',
value: '',
optionValue: 'iata',
optionType: 'string',
suggestions: filteredAirports,
completeMethod: searchAirports,
fieldName: 'nameFa'
}
]}
columns={[
{
field: 'airlineNameFa',
header: 'ایرلاین',
},
{
field: 'flightGroupTitle',
header: 'عنوان پرواز',
sortable: true,
},
{field: 'originCityNameFa', header: 'مبدا'},
{field: 'destinationCityNameFa', header: 'مقصد'},
{field: 'baggageAllowance', header: 'بار مجاز', sortable: true},
{
field: 'confirmStatus',
header: 'وضعیت تایید',
body: confirmStatusBodyTemplate,
},
{
field: 'isActive',
header: 'وضعیت',
body: statusBodyTemplate,
},
{
field: 'options',
body: optionsBodyTemplate
},
]}
tableProps={{
selection: selectedRows,
onSelectionChange: (e) => setSelectedRows(e.value),
isDataSelectable: isRowSelectable,
showSelectAll: false,
rowClassName: (data) => data.isActive ? '' : 'text-disabled',
onRowDoubleClick: (e) => router.push(`/flight/${e.data.id}`)
}}
/>
);
};
export default FlightsListTable;
OK here is a working Code Sandbox showing exactly what you want to do:
https://codesandbox.io/s/primereact-datatable-single-and-double-click-selection-0in9em?file=/src/demo/DataTableSelectionDemo.js
The trick is to handle onRowClick yourself.
const onRowClick = (event) => {
if (event.originalEvent.detail === 1) {
timer.current = setTimeout(() => {
const selected = [...selectedProducts8];
selected.push(event.data);
setSelectedProducts8(selected);
}, 300);
}
};
const onRowDoubleClick = (e) => {
clearTimeout(timer.current);
console.log("dblclick");
};
If you agree with this don't forget to select this as the right answer.

Why am I not able to post my data with react?

For now, only apply:0 data are displayed by default in my table.I'm trying to send to my API when you click on Apply button, a list of all ids applied and not applied for instance : data:{apply: [3], notApply:[1,2]}.
Hereapply field in my data means the value is equal to 1 --> not displayed in the table; and notApply - i.e equal to 0 --> displaying data.
So when I click on the toggle button under the show column, it should turns to 1 the statusapply (not displaying the row data in my table which is not the case). The Cancel button sends nothing to my API.
Here what I've tried (but not working):
export default function MenuDisplayApi() {
const { menuId } = useParams();
const { match } = JsonData;
const [selected, setSelected] = useState({});
const [hidden, setHidden] = useState({});
const [menus, setMenus] = useState([]);
const [applyStatus, setApplyStatus]=useState(false)
useEffect(() => {
axios.post(url,{menuId:parseInt(menuId)})
.then(res => {
console.log(res)
setMenus(res.data.menus)
})
.catch(err => {
console.log(err)
})
}, [menuId]);
// If any row is selected, the button should be in the Apply state
// else it should be in the Cancel state
const [data, setData]= useState({
notApply:data.notApply,
apply: data.apply
})
function submit(e){
e.preventDefault()
axios.post(url,{
notApply:data.notApply,
apply: data.apply
})
.then(res => {
console.log(res)
})
}
// useEffect(() => {
// const data = {
// notApply:notApply,
// apply: apply
// }
// console.log('check', data)
// }, [])
// function handle(e){
// const newdata={...data}
// newdata[e.target.id]=e.target.value
// setData(newdata)
// console.log(newdata)
// }
const buttonMode = Object.values(selected).some((isSelected) => isSelected)
? "apply"
: "cancel";
const rowSelectHandler = (id) => (checked) => {
setSelected((selected) => ({
...selected,
[id]: checked
}));
};
const handleClick = () => {
if (buttonMode === "apply") {
// Hide currently selected items
const currentlySelected = {};
Object.entries(selected).forEach(([id, isSelected]) => {
if (isSelected) {
currentlySelected[id] = isSelected;
}
});
setHidden({ ...hidden, ...currentlySelected });
// Clear all selection
const newSelected = {};
Object.keys(selected).forEach((id) => {
newSelected[id] = false;
});
setSelected(newSelected);
} else {
// Select all currently hidden items
const currentlyHidden = {};
Object.entries(hidden).forEach(([id, isHidden]) => {
if (isHidden) {
currentlyHidden[id] = isHidden;
}
});
setSelected({ ...selected, ...currentlyHidden });
// Clear all hidden items
const newHidden = {};
Object.keys(hidden).forEach((id) => {
newHidden[id] = false;
});
setHidden(newHidden);
}
};
const matchData = (
menus.filter(({ _id }) => {
return !hidden[_id];
});
const getRowProps = (row) => {
return {
style: {
backgroundColor: selected[row.values.id] ? "lightgrey" : "white"
}
};
};
const data = [
{
Header: "id",
accessor: (row) => row._id
},
{
Header: "Name",
accessor: (row) => (
<Link to={{ pathname: `/menu/${menuId}/${row._id}` }}>{row.name}</Link>
)
},
{
Header: "Description",
//check current row is in hidden rows or not
accessor: (row) => row.description
},
{
Header: "Dishes",
//check current row is in hidden rows or not
accessor: (row) => row.dishes,
id: "dishes",
Cell: ({ value }) => value && Object.values(value[0]).join(", ")
},
{
Header: "Show",
accessor: (row) => (
<Toggle
value={selected[row._id]}
onChange={rowSelectHandler(row._id)}
/>
)
}
];
const initialState = {
sortBy: [
{ desc: false, id: "id" },
{ desc: false, id: "description" }
],
hiddenColumns: ["dishes", "id"]
};
if (menus.apply === 0) {
setApplyStatus(true)
}
if (menus.apply === 1) {
setApplyStatus(false)
}
return (
<div>
<button type="submit" onClick={handleClick}>
{buttonMode === "cancel" ? "Cancel" : "Apply"}
</button>
<Table
data={matchData && (applyStatus ? true : i.apply !== 1)}
columns={data}
initialState={initialState}
withCellBorder
withRowBorder
withSorting
withPagination
rowProps={getRowProps}
/>
</div>
);
}
Here my json from my api for menuId:1:
[
// ...other menus
{
"_id": 3,
"name": "Cucumber Soup ",
"description": "Cucumber Soup",
"dishes": [
{
"meat": "N/A",
"vegetables": "cucumber"
}
],
"taste": "Medium",
"comments": "2/4",
"price": "Medium",
"availability": 1,
"trust": 1,
"status": "Not started",
"apply": 0
}
]
Please check my codeSandbox. It works fine on local json files, so you can have a better understanding regarding what I'm trying.
Please see this picture for better understanding :

Context state being updated unexpectedly - React Typescript

First time poster so let me know if more information is need.
Trying to figure out why my global state using context API is being updated even when my setSate method is commented out. I thought i might have been mutating the state directly accidently but I dont believe I am
"specialModes" in actionOnClick() is the state in question
const SpecialFunctions: FC = (props: Props) => {
const { currentModeContext, specialModesContext: specialActionsContext, performCalc, inputValueContext } = useContext(AppContext)
const { specialModes, setSpecialModes } = specialActionsContext
const { currentMode, setCurrentMode } = currentModeContext
const { inputValue, setInputValue } = inputValueContext
const categoryOnClick = (index: number) => {
setCurrentMode(specialModes[index])
console.log(specialModes[index].title);
}
const actionOnClick = (action: IAction) => {
let newAction = action
newAction.value = performCalc()
let newSpecialModes = specialModes.map((mode) => {
if (mode === currentMode) {
let newMode = mode
newMode.actions = mode.actions.map((element) => {
if (element === action) {
return newAction
}
else return element
})
return newMode
}
else return mode
})
//setSpecialModes(newSpecialModes)
}
let headings = specialModes.map((categorgy, index) => {
return <Heading isActive={categorgy === currentMode ? true : false} onClick={() => categoryOnClick(index)} key={index}>{categorgy.title}</Heading>
})
let actions = currentMode.actions.map((action, index) => {
return (
<Action key={index} onClick={() => actionOnClick(action)}>
<ActionTitle>{action.title}</ActionTitle>
<ActionValue>{action.value}</ActionValue>
</Action>
)
})
return (
<Wrapper>
<Category>
{headings}
</Category>
<ActionsWrapper toggleRadiusCorner={currentMode === specialModes[0] ? false : true}>
{actions}
</ActionsWrapper>
</Wrapper>
)
}
Context.tsx
interface ContextType {
specialModesContext: {
specialModes: Array<ISpecialModes>,
setSpecialModes: React.Dispatch<React.SetStateAction<ISpecialModes[]>>
},
currentModeContext: {
currentMode: ISpecialModes,
setCurrentMode: React.Dispatch<React.SetStateAction<ISpecialModes>>
},
inputValueContext: {
inputValue: string,
setInputValue: React.Dispatch<React.SetStateAction<string>>
},
inputSuperscriptValueContext: {
inputSuperscriptValue: string,
setInputSuperscriptValue: React.Dispatch<React.SetStateAction<string>>
},
performCalc: () => string
}
export const AppContext = createContext({} as ContextType);
export const ContextProvider: FC = ({ children }) => {
const [SpecialModes, setSpecialModes] = useState([
{
title: 'Rafter',
actions: [
{
title: 'Span',
active: false
},
{
title: 'Ridge Thickness',
active: false
},
{
title: 'Pitch',
active: false
}
],
},
{
title: 'General',
actions: [
{
title: 'General1',
active: false
},
{
title: 'General2',
active: false
},
{
title: 'General3',
active: false
}
],
},
{
title: 'Stairs',
actions: [
{
title: 'Stairs1',
active: false
},
{
title: 'Stairs2',
active: false
},
{
title: 'Stairs3',
active: false
}
],
}
] as Array<ISpecialModes>)
const [currentMode, setCurrentMode] = useState(SpecialModes[0])
const [inputValue, setInputValue] = useState('0')
const [inputSuperscriptValue, setInputSuperscriptValue] = useState('')
const replaceCharsWithOperators = (string: string): string => {
let newString = string.replaceAll(/\s/g, '') // delete white space
newString = newString.replace('×', '*')
newString = newString.replace('÷', '/')
console.log(string)
console.log(newString)
return newString
}
const performCalc = (): string => {
let originalEquation = `${inputSuperscriptValue} ${inputValue} =`
let equation = inputSuperscriptValue + inputValue
let result = ''
equation = replaceCharsWithOperators(equation)
result = eval(equation).toString()
setInputSuperscriptValue(`${originalEquation} ${result}`)
setInputValue(result)
console.log(result)
return result
}
return (
<AppContext.Provider value={
{
specialModesContext: {
specialModes: SpecialModes,
setSpecialModes: setSpecialModes
},
currentModeContext: {
currentMode,
setCurrentMode
},
inputValueContext: {
inputValue,
setInputValue
},
inputSuperscriptValueContext: {
inputSuperscriptValue,
setInputSuperscriptValue
},
performCalc
}}>
{children}
</AppContext.Provider>
)
}
In your mode.actions.map() function you are indirectly changing actions field of your original specialModes array.
To fix this problem you need to create shallow copy of specialModes array Using the ... ES6 spread operator.
const clonedSpecialModes = [...specialModes];
let newSpecialModes = clonedSpecialModes.map((mode) => {
// rest of your logic here
})

Material Table not updating table data after mutation

When a user adds additional information, a mutation is made to the database adding the new info, then the local state is updated, adding the new information to the lead.
My mutation and state seem to get updated fine, the issue seems to be that the state of the Material Table component does not match its 'data' prop. I can see in the React Dev tools that the state was updated in the parent component and is being passes down, the table just seems to be using stale data until I manually refresh the page.
I will attach images of the React Devtools as well as some code snippets. Any help would be much appreciated.
Devtools Material Table data prop:
Devtools Material Table State
Material Table Parent Component:
const Leads = () => {
const [leadState, setLeadState] = useState({});
const [userLeadsLoaded, setUserLeadsLoaded] = React.useState(false);
const [userLeads, setUserLeads] = React.useState([]);
const { isAuthenticated, user, loading } = useAuth()
const [
createLead,
{ data,
// loading: mutationLoading,
error: mutationError },
] = useMutation(GQL_MUTATION_CREATE_LEAD);
const params = { id: isAuthenticated ? user.id : null };
const {
loading: apolloLoading,
error: apolloError,
data: apolloData,
} = useQuery(GQL_QUERY_ALL_LEADS, {
variables: params,
});
useEffect(() => {
if (apolloData) {
if (!userLeadsLoaded) {
const { leads } = apolloData;
const editable = leads.map(o => ({ ...o }));
setUserLeads(editable);
setUserLeadsLoaded(true);
};
}
}, [apolloData])
if (apolloLoading) {
return (
<>
<CircularProgress variant="indeterminate" />
</>
);
};
if (apolloError) {
console.log(apolloError)
//TODO: Do something with the error, ie default user?
return (
<div>
<div>Oh no, there was a problem. Try refreshing the app.</div>
<pre>{apolloError.message}</pre>
</div>
);
};
return (
<>
<Layout leadState={leadState} setLeads={setUserLeads} leads={userLeads} setLeadState={setLeadState} createLead={createLead}>
{apolloLoading ? (<CircularProgress variant="indeterminate" />) : (<LeadsTable leads={userLeads} setLeads={setUserLeads} />)}
</Layout>
</>
)
}
export default Leads
Handle Submit function for adding additional information:
const handleSubmit = async (event) => {
event.preventDefault();
const updatedLead = {
id: leadState.id,
first_name: leadState.firstName,
last_name: leadState.lastName,
email_one: leadState.email,
address_one: leadState.addressOne,
address_two: leadState.addressTwo,
city: leadState.city,
state_abbr: leadState.state,
zip: leadState.zipCode,
phone_cell: leadState.phone,
suffix: suffix,
address_verified: true
}
const { data } = await updateLead({
variables: updatedLead,
refetchQueries: [{ query: GQL_QUERY_GET_USERS_LEADS, variables: { id: user.id } }]
})
const newLeads = updateIndexById(leads, data.updateLead)
console.log('New leads before setLeads: ', newLeads)
setLeads(newLeads)
// setSelectedRow(data.updateLead)
handleClose()
};
Material Table Component:
const columnDetails = [
{ title: 'First Name', field: 'first_name' },
{ title: 'Last Name', field: 'last_name' },
{ title: 'Phone Cell', field: 'phone_cell' },
{ title: 'Email', field: 'email_one' },
{ title: 'Stage', field: 'stage', lookup: { New: 'New', Working: 'Working', Converted: 'Converted' } },
{ title: 'Active', field: 'active', lookup: { Active: 'Active' } },
];
const LeadsTable = ({ leads, setLeads }) => {
const classes = useStyles();
const { user } = useAuth();
const [isLeadDrawerOpen, setIsLeadDrawerOpen] = React.useState(false);
const [selectedRow, setSelectedRow] = React.useState({});
const columns = React.useMemo(() => columnDetails);
const handleClose = () => {
setIsLeadDrawerOpen(!isLeadDrawerOpen);
}
console.log('All leads from leads table render: ', leads)
return (
<>
<MaterialTable
title='Leads'
columns={columns}
data={leads}
icons={tableIcons}
options={{
exportButton: false,
hover: true,
pageSize: 10,
pageSizeOptions: [10, 20, 30, 50, 100],
}}
onRowClick={(event, row) => {
console.log('Selected Row:', row)
setSelectedRow(row);
setIsLeadDrawerOpen(true);
}}
style={{
padding: 20,
}}
/>
<Drawer
variant="temporary"
open={isLeadDrawerOpen}
anchor="right"
onClose={handleClose}
className={classes.drawer}
>
<LeadDrawer onCancel={handleClose} lead={selectedRow} setLeads={setLeads} setSelectedRow={setSelectedRow} leads={leads} />
</Drawer>
</>
);
};
export default LeadsTable;
Try creating an object that contains refetchQueries and awaitRefetchQueries: true. Pass that object to useMutation hook as a 2nd parameter. See example below:
const [
createLead,
{ data,
loading: mutationLoading,
error: mutationError },
] = useMutation(GQL_MUTATION_CREATE_LEAD, {
refetchQueries: [{ query: GQL_QUERY_GET_USERS_LEADS, variables: { id: user.id } }],
awaitRefetchQueries: true,
});
Manually updating cache. Example blow is adding a new todo. In your case you can find and update the record before writing the query.
const updateCache = (cache, {data}) => {
// Fetch the todos from the cache
const existingTodos = cache.readQuery({
query: GET_MY_TODOS
});
// Add the new todo to the cache (or find and update an existing record here)
const newTodo = data.insert_todos.returning[0];
cache.writeQuery({
query: GET_MY_TODOS,
data: {todos: [newTodo, ...existingTodos.todos]}
});
};
const [addTodo] = useMutation(ADD_TODO, {update: updateCache});

React-data-grid - Changing cell value using global variable upon

I'm trying to create a certain functionality in my react-data-grid.
I have a column called subStart, and I have a dropdown that I want to use so that the user can set the value of a cell to the value of a state variable (this.state.timeTotalSec).
So if the user clicks on "Use Global Time" option in a 'Start Time' cell, it will replace the value of that cell with the value of this.state.timeTotalSec. How on earth do I do this?
I have the dropdown functionality working. But how do I get it to change the cell value?
const rows = [
{ id: 1, subStart: "00:00.000", subEnd: "00:00.000" , subText: 'Text1'},
{ id: 2, subStart: "00:00.000", subEnd: "00:00.000" , subText: 'Text2'},
{ id: 3, subStart: "00:00.000", subEnd: "00:00.000" , subText: 'Text3'}
];
const columns = [
{
key: "id",
name: "ID"
},
{
key: "subStart",
name: "Start Time",
editable: true
},
{
key: "subEnd",
name: "End Time",
editable: true
},
{
key: "subText",
name: "Text",
editable: true
}
].map(c => ({ ...c, ...defaultColumnProperties }));
const subStartActions = [
{
icon: <span className="glyphicon glyphicon-remove" />,
callback: () => {
alert("Deleting");
}
},
{
icon: "glyphicon glyphicon-link",
actions: [
{
text: "Use Global Time",
callback: () => {
// TODO
// **** TRYING TO MAKE THIS WORK ****
}
}
]
}
];
function getCellActions(column, row) {
const cellActions = {
subStart: subStartActions
};
return row.id % 2 === 0 ? cellActions[column.key] : null;
}
const ROW_COUNT = 50;
class App extends React.Component {
constructor (props) {
super(props)
this.state = {
playing: false,
duration: 0,
timeMilli: 0,
timeSec: 0,
timeMin: 0,
timeTotalSec: 0,
rows
}
}
onDuration = (duration) => {
this.setState({ duration })
}
onProgress = (progress) => {
if (this.state.duration == 0) {
return
}
const timeTotalSec = progress.played * this.state.duration
if (timeTotalSec !== this.state.timeTotalSec) {
const timeMin = Math.floor(timeTotalSec / 60)
const timeSec = Math.floor(timeTotalSec - (timeMin)*60)
const timeMilli = (timeTotalSec - timeSec - timeMin*60).toFixed(3)
this.setState({ timeTotalSec })
this.setState({ timeMin })
this.setState({ timeSec })
this.setState({ timeMilli })
}
}
onGridRowsUpdated = ({ fromRow, toRow, updated }) => {
this.setState(state => {
const rows = state.rows.slice();
for (let i = fromRow; i <= toRow; i++) {
rows[i] = { ...rows[i], ...updated };
}
return { rows };
});
};
render () {
const { data } = this;
return (
<div className='player-wrapper'>
<ReactPlayer
url='https://www.youtube.com/watch?v=lhlZkqEag7E'
className='react-player'
playing={this.state.playing}
onPlay={() => this.setState({ playing: true })}
onPause={() => this.setState({ playing: false })}
controls='True'
onDuration={this.onDuration}
onProgress={this.onProgress}
/>
Video is currently: {this.state.playing ? 'playing' : 'paused'}
<br />
Duration: {Math.round(this.state.duration).toString() + ' seconds'}
<br />
Elapsed: {this.state.timeMin + 'min ' + this.state.timeSec + 'sec ' +
this.state.timeMilli + 'ms'}
<br />
<button onClick={() => this.setState({ playing: true })}>Play</button>
<button onClick={() => this.setState({ playing: false })}>Pause</button>
<ButtonToolbar>
<Button variant="primary" onClick={() => this.setState(this.state.playing ? false : true)}>Play/Pause</Button>
</ButtonToolbar>
<ReactDataGrid
columns={columns}
rowGetter={i => this.state.rows[i]}
rowsCount={ROW_COUNT}
// minHeight={500}
getCellActions={getCellActions}
onGridRowsUpdated={this.onGridRowsUpdated}
enableCellSelect={true}
/>
</div>
)
}
}
ReactDataGrid will just render what data you pass to it, If you want to change the value of a cell, you should update the rows from data source or state you are using.in your case rows
this.state = {
playing: false,
duration: 0,
timeMilli: 0,
timeSec: 0,
timeMin: 0,
timeTotalSec: 10,
rows // your datasourse
};
I've supposed,id is your data Key.Add updateRowDate to actions to handle your state changes.
actions: [
{
text: "Use Global Time",
callback: () => {
// TODO
// **** TRYING TO MAKE THIS WORK ****
updateRowDate(row.id);
}
}
]
and here is updateRowDate in App component
updateRowDate = rowId => {
this.setState(prv => ({
rows: prv.rows.map(q => {
if (q.id === rowId) return { ...q, subStart: this.state.timeTotalSec };
return q;
})
}));
finally, you need to pass updateRowDate to getCellActions
<ReactDataGrid
columns={columns}
rowGetter={i => this.state.rows[i]}
rowsCount={ROW_COUNT}
// minHeight={500}
getCellActions={(column, row) =>
getCellActions(column, row, this.updateRowDate)
}
onGridRowsUpdated={this.onGridRowsUpdated}
enableCellSelect={true}
/>
Here is the temporary sandbox containing the fixed version

Categories