I am using the autocomplete component with filterOptions to suggest the creation of a new value as shown below:
<Autocomplete
multiple
name="participant-tags"
options={people}
getOptionLabel={(option) => option.name}
renderInput={(params) => {
return (
<TextField
{...params}
variant="outlined"
label="Participants"
/>
)
}}
filterOptions={(options, params) => {
const filtered = filter(options, params);
logger.debug('filterOptions(params) %j', params)
// Suggest the creation of a new value
if (params.inputValue !== '') {
filtered.push({
inputValue: params.inputValue,
name: `Add "${params.inputValue}"`,
});
}
return filtered;
}}
onKeyDown={(e) => {
if(e.keyCode === 13) {
// TODO: select currently highlighted option
e.preventDefault()
}
}}
onChange={(e, value, reason) => {
logger.debug(e.type)
logger.debug(value)
logger.debug(reason)
e.preventDefault()
}}
/>
However, I can't figure out where to handle the selection of the "Add this option" to actually add the option?
This was solved leveraging the 'reason' parameter in the onChange handler, and the onKeyDown handler isn't needed:
filterOptions={(options, params) => {
const filtered = filter(options, params);
if (params.inputValue !== '') {
filtered.push({
inputValue: params.inputValue,
[displayOptionsField]: `Add New ${newOptionLabel} "${params.inputValue}"`,
});
}
return filtered;
}}
onChange={(e, value, reason) => {
let newOptions
if (reason==='select-option') {
const last = value.pop();
if (last.inputValue) {
newOptions = value.concat([{[displayOptionsField]: last.inputValue}])
}
else {
newOptions = value.concat([last])
}
}
if (reason==='create-option') {
const last = value.pop();
newOptions = value.concat([{[displayOptionsField]: last}])
}
if (reason==='remove-option') {
newOptions = value
}
if (newOptions) {
onChange(newOptions)
}
}}
The onChange inside the onChange handler is there as a prop from a wrapping component.
Related
I am trying to trigger onCellEditApproved when the value of the editable column changes (or onBlur) inside MaterialTable
cellEditable={{
cellStyle: {},
onCellEditApproved: (newValue, oldValue, rowData, columnDef) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
let updatedRow = rowData
updatedRow.anQty = parseInt(newValue)
const updatedRowData = {
...rowData,
[columnDef.anQty]: newValue,
};
setGetCompanyData(prevData => {
const index = prevData.indexOf(rowData);
return [...prevData.slice(0, index), updatedRowData, ...prevData.slice(index + 1)];
});
}, 1000);
});
}
}}
onCellEditApproved is triggered when the user press "Enter" and I want to override that behavior with onChange and onBlur, that's why I made a custom EditField:
components={{
EditField: props => {
const handleChange = (event) => {
//const { onCellEditApproved } = props;
props.onChange(event.target.value);
//onCellEditApproved(props.value, props.oldValue, props.rowData, props.columnDef);
}
return <input {...props} type="text" className="test" onChange={handleChange} />
},
}}
I have tried to get onCellEditApproved event via props inside of EditField but unsuccessfully.
i am trying to create a search form using React typescript props event.I have acheived half of it but now stuck on an checkbox multiSelector where i have no idea how we can implement it.i have googled a lot but got nothing in return.
here is my code.
I am using common typescript props event onChange for setting all the values inside my search Api Object.
can anyone help me out with code or docs how we can acheive multiSelector checkbox for React Typescript props event.
1.here is my search for structure=>
enter code here
let columns = useMemo(
() => [
{
Header: "Name", accessor: "username",
Cell: (props: any) => {
if (authoritiesList.includes("USR-U")) {
let path = "/users/" + props.value;
return createClickableLink(path, props.value);
} else {
return <>
<span>{props.row.original.username}</span>
</>
}
},
FilterOptions: {
FilterInput:
<input type="text" placeholder="Username..." />,
overrideFilterLabel: "Username",
overrideFilterAccessor: "username"
}
},
{
Header: "Role(s)", accessor: "roles", disableSortBy: true,
Cell: (props: any) => {
return <>
{props.row.original.roles.map((role: any) => {
return (
<div>
<span>{role}</span><br/>
</div>)
})}
</>
},
FilterOptions: {
FilterSelect:
roleData.items.map((curRole:any)=>{
return (
<input type="checkbox value=
{curRole.name} />
)
})} ,
overrideFilterLabel: "Roles",
overrideFilterAccessor: "roles"
}
},
},
], [customerData,roleData]
)
enter code here
const selector = (state: any) => state.users;
return (
<div className="m-0 p-0 ">
<section id="content-wrapper">
<div className="row">
<div className="col-lg-12 ml-auto">
<Breadcrumb crumbs={crumbs}/>
<div className="table_data mt-2">
{createSearchButton()}
{authoritiesList.includes("USR-C") && createAddButton("/users/create", "Add User")}
<DataTable columns={columns}
fetchAction={userActions.getAllData as Dispatch<Action>}
exportAction={userActions.exportData as Dispatch<Action>}
selector={selector}/>
</div>
</div>
</div>
</section>
</div>
);
}
I want to handle multi selected checkbox event for this form in
Typescript. all forms input tags are working currently but multiselected checkbox is not working for brining output to the query object.
here is my typescript code.
for (let column of tableColumns) {
if (!column.FilterOptions) {
column.FilterOptions = {};
}
if (column.FilterOptions?.FilterSelect) {
column.FilterOptions.FilterSelect.props.onKeyPress = (event: KeyboardEvent) => {
event.key === 'Enter' && setApplyFilter(true);
}
column.FilterOptions.FilterSelect.props.onChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
updateFilterQuerySelect(column, filterQuery, setFilterQuery, event);
}
}
if (column.FilterOptions?.FilterInput) {
column.FilterOptions.FilterInput.props.onKeyPress = (event: KeyboardEvent) => {
event.key === 'Enter' && setApplyFilter(true);
}
column.FilterOptions.FilterInput.props.onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
updateFilterQuery(column, filterQuery, setFilterQuery, event);
}
}
}
here is function updateFilterQuery
const updateFilterQuery = (column: DataTableColumn, filterQuery: any, setFilterQuery: Function, event: React.ChangeEvent) => {
let tempQuery: any = {...filterQuery};
let key: string = column.FilterOptions?.overrideFilterAccessor || column.accessor;
let value: any = event.target.value;
if (event.target.value == "on" && event.target.checked != undefined) {
value = event.target.checked;
}
if (event.target.value == undefined) {
delete tempQuery[key];
} else {
key === 'phone' ? tempQuery[key] = getUnformattedPhoneNumber(value)
:
tempQuery[key] = value;
}
setFilterQuery(tempQuery);
}
It is a search form and similary it is working same as for other forms as well th eonly part missing in this form is now multiselector which is not working.
You have to separate selection state into a custom hook. A state is an array of selected items.
CodeSandbox
hooks.ts
import React, { useState } from "react";
export const useMultiselect = (initialValue: string[]) => {
const [selected, setSelected] = useState<string[]>(initialValue);
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
const index = selected.indexOf(value);
if (index > -1) {
setSelected([...selected.slice(0, index), ...selected.slice(index + 1)]);
} else {
setSelected([...selected, ...[value]]);
}
};
const isSelected = (value: string) => {
return selected.includes(value);
};
return { selected, isSelected, onChange };
};
App.tsx
import { useMultiselect } from "./hooks";
const data = ["Apple", "Orange", "Banana", "Pear", "Peach"];
export default function App() {
const { selected, isSelected, onChange } = useMultiselect([]);
return (
<div>
<div>Select your favorite fruites!</div>
<ul style={{ listStyleType: "none" }}>
{data.map((value) => (
<li key={value}>
<input
id={value}
type="checkbox"
value={value}
checked={isSelected(value)}
onChange={onChange}
/>
<label htmlFor={value}>{value}</label>
</li>
))}
</ul>
<div>Selected: {selected.join()}</div>
</div>
);
}
I'm building a dynamic table using React-Table and i want to add a new row of editable cells.
At the moment i can add new row but only when i press the global edit button i can edit it, instead i want to add a row which would be editable at first.
This is my code -
Main component
function StyledTable() {
useEffect(() => {
dispatch(getData(mokeJsonData));
}, []);
const [datatoColumns] = useState(columnDataaa.slice(1));
const [skipPageReset, setSkipPageReset] = useState(false);
const data = useSelector((state) => state.dataReducer.data);
const dispatch = useDispatch();
const columns = useMemo(
() => [
{
Header: "",
id: "expander",
Cell2: ({ row }) => {
return (
<span {...row.getToggleRowExpandedProps()}>
{row.isExpanded ? "-" : "+"}
</span>
);
},
Cell: () => {
return <div></div>;
},
},
{
Header: columnDataaa[0].Header,
accessor: columnDataaa[0].accessor,
Cell: ({ value, row }) => {
return (
<FlexDiv>
<HighlightOffIcon
style={{ marginRight: "5px", color: "grey", width: "20px" }}
onClick={() => dispatch(deleteRow(row.index))}
/>
{value}
</FlexDiv>
);
},
},
...datatoColumns,
],
[]
);
useEffect(() => {
setSkipPageReset(false);
}, [data]);
const renderRowSubComponent = useCallback(
({ row }) => ({
values: row.original.addInfo && row.original.addInfo,
}),
[]
);
return (
<Styles>
<h1>הגדרת מנהל</h1>
<Table
columns={columns}
skipPageReset={skipPageReset}
renderRowSubComponent={renderRowSubComponent}
/>
</Styles>
);
}
export default StyledTable;
Editable Cell
const EditableCell = ({
value: initialValue,
row: { index },
column: { id, editable, type, width, valueOptions },
}) => {
const [value, setValue] = useState(initialValue);
const onChange = (e) => {
setValue(e.target.value);
};
const dispatch = useDispatch();
const onBlur = () => {
if (value === "") return alert("requiredddd");
return dispatch(updateMyData({ index, id, value }));
};
useEffect(() => {
setValue(initialValue);
}, [initialValue]);
if (type === "singleSelect")
return (
<InputSelect
value={value}
onChange={onChange}
onBlur={onBlur}
style={{ width: width }}
>
{valueOptions.map((item, i) => {
return (
<option value={item.label} key={i}>
{item.label}
</option>
);
})}
</InputSelect>
);
if (type === "date")
return (
<DatePicker
style={{ width: width }}
type="date"
disabled={editable === false}
value={value}
onChange={onChange}
onBlur={onBlur}
/>
);
return (
<input
style={{ width: width }}
disabled={editable === false}
value={value}
onChange={onChange}
onBlur={onBlur}
/>
);
};
export default EditableCell;
Add Row function
addRow: (state, action) => {
const obj = {};
action.payload.slice(1).forEach((item) => {
obj[item.accessor] = '';
});
if (
obj &&
Object.keys(obj).length === 0 &&
Object.getPrototypeOf(obj) === Object.prototype
)
return;
else {
state.data.splice(0, 0, obj);
state.originalData = state.data;
}
},
Thanks
Pass the state variable and method to the useTable() root hook. custom plugin hooks and other variables/methods maintaining the component state are returned from the table instance. These you can later retrieve from anywhere you want.
const {
// all your hooks...
} = useTable(
{
columns,
data,
// all your other hooks...
updateMyData,
// pass state variables so that we can access them in edit hook later
editableRowIndex, // index of the single row we want to edit
setEditableRowIndex // setState hook for toggling edit on/off switch
},
// other hooks...
(hooks) => {
hooks.allColumns.push((columns) => [
// other hooks such as selection hook
...columns,
// edit hook
{
accessor: "edit",
id: "edit",
Header: "edit",
Cell: ({ row, setEditableRowIndex, editableRowIndex }) => (
<button
className="action-button"
onClick={() => {
const currentIndex = row.index;
if (editableRowIndex !== currentIndex) {
// row requested for edit access
setEditableRowIndex(currentIndex);
} else {
// request for saving the updated row
setEditableRowIndex(null); // keep the row closed for edit after we finish updating it
const updatedRow = row.values;
console.log("updated row values:");
console.log(updatedRow);
// call your updateRow API
}
}}
>
{/* single action button supporting 2 modes */}
{editableRowIndex !== row.index ? "Edit" : "Save"}
</button>
)
}
]);
}
);
you can found example from bellow link
github repo link: https://github.com/smmziaul/only-one-row-editable
code sandbox link: https://codesandbox.io/s/github/smmziaul/only-one-row-editable
I need to be able to send two values when handling an onChange event in my select box however I am not sure a way of doing this as they are currently sent as a string. I am using react with react-bootstrap.
const DropDown = () => {
const handleOnchange = (event) => {
console.log(event.target.value)
const filter = event.target.value[0];
const initialState = [...initialValues]
let result = [];
console.log(event)
setDefaultSelect(event.target.name)
if(event.target.value === 'Show All') {
setValues(initialState);
}
else {
initialState.forEach(item => {
let found = item.store_category.filter(item => item == filter);
if (found.length) {
result.push(item);
}
});
setValues(result);
}
}
return (
<Form>
<Form.Group controlId="exampleForm.SelectCustom">
<Form.Control onChange={(e) => handleOnchange(e)} as="select" custom>
<option className="pl-2" hidden>{defaultSelect}</option>
<option>Show All</option>
{storeCategorys.map((item, index) => (
<option value={{itemId: item.id, itemName: item.name}} key={index}>{item.name}</option>
))}
</Form.Control>
</Form.Group>
</Form>
);
}
How about to use useEffect instead of handleOnchange?
const DropDown = () => {
const [selectedItem, setSelectedItem] = useState({});
useEffect(() => {
console.log(selectedItem);
}, [selectedItem]); // will be fired when `selectedItem` is changes
...
{storeCategorys.map((item, index) => (
<option
value={{itemId: item.id, itemName: item.name}}
key={index}
onClick={() => {setSelectedItem(item)}} // will fire `useEffect`
// on `selectedItem`
>{item.name}</option>
))}
...
}
I have created this function inside onChange to handle my inputs using react-select. it works perfectly fine in terms of submitting the input and using it later. The thing is, the clear property is not working. Before I created my function inside onChange, it used to work whenever I click on "x". Yet now it is not. Any help?
{["role1", "role2", "role3"].map(role => (
<Select
cacheOptions
defaultOptions
loadOptions={this.loadOptions}
key={role}
getOptionLabel={i => i.full_name}
getOptionValue={i => i.id}
closeMenuOnSelect={false}
isMulti
className="selectStyle"
placeholder={t(role)}
value={form.users.filter(item => item.role === role)}
onChange={values => {
let newValues = form.users;
values.forEach(item => {
if (
newValues.filter(v => v.id === item.id && v.role === role)
.length
) {
return;
}
item.role = role;
newValues.push(item);
});
setFormValue({ name: "users", value: newValues });
}}
clearValue={() => {
setFormValue({
name: "users",
value: form.users.filter(item => item.role !== role)
});
}}
/>