I want to change the state whenever I delete an element from the react-select multi varient select option.
There is a second param in the onChange function for react-select, where it captures the context, meaning it has information about what action is performed or what element got removed.
const onChange = (value, context) => {
// console.log(value);
if (context.action === "remove-value") {
console.log(context.removedValue.id);
const newState = newitems.filter(
(item) => item.id !== context.removedValue.id
);
setnewitems(newState);
}};
<Select
isMulti
options={options}
onChange={onChange}
/>
Related
I have several checkboxes running in several checkbox groups. I can't figure out how to uncheck (thus changing the state) on a particular checkbox. FOr some reason I can't reach e.target.checked.
<Checkbox
size="small"
name={item}
value={item}
checked={checkboxvalues.includes(item)}
onChange={(e) => handleOnChange(e)}
/>
and my function
const handleOnChange = (e) => {
const check = e.target.checked;
setChecked(!check);
};
I made a working sample of the component in this sandbox.
You need to create handleOnChange function specific to each group. I have created one for Genre checkbox group in similar way you can create for other groups.
Here is handler function.
const handleOnChangeGenre = (e) => {
let newValArr = [];
if (e.target.checked) {
newValArr = [...state.pillarGenre.split(","), e.target.value];
} else {
newValArr = state.pillarGenre
.split(",")
.filter((theGenre) => theGenre.trim() !== e.target.value);
}
setState({ ...state, pillarGenre: newValArr.join(",") });
};
pass this function as handleOnChange prop to CustomCheckboxGroup as below.
<CustomCheckboxGroup
checkboxdata={genres}
checkboxvalues={state.pillarGenre}
value={state.pillarGenre}
sectionlabel="Genre"
onToggleChange={handleGenreSwitch}
togglechecked={genreswitch}
handleOnChange={handleOnChangeGenre}
/>
comment your handleOnChange function for testing.
check complete working solution here in sandbox -
complete code
Here's how I'd do it: https://codesandbox.io/s/elastic-pateu-flwqvp?file=/components/Selectors.js
I've abstracted the selection logic into a useSelection() custom hook, which means current selection is to be found in store[key].selected, where key can be any of selectors's keys.
items, selected, setSelected and sectionLabel from each useSelection() call are stored into store[key] and spread onto a <CustomCheckboxGroup /> component.
The relevant bit is the handleCheck function inside that component, which sets the new selection based on the previous selection's value: if the current item is contained in the previous selected value, it gets removed. Otherwise, it gets added.
A more verbose explanation (the why)
Looking closer at your code, it appears you're confused about how the checkbox components function in React.
The checked property of the input is controlled by a state boolean. Generic example:
const Checkbox = ({ label }) => {
const [checked, setChecked] = useState(false)
return (
<label>
<input
type="checkbox"
checked={checked}
onChange={() => setChecked(!checked)}
/>
<span>{label}</span>
</label>
)
}
On every render, the checked value of the <input /> is set according to current value of checked state. When the input's checked changes (on user interaction) the state doesn't update automatically. But the onChange event is triggered and we use it to update the state to the negative value of the state's previous value.
When dealing with a <CheckboxList /> component, we can't serve a single boolean to control all checkboxes, we need one boolean for each of the checkboxes being rendered. So we create a selected array and set the checked value of each <input /> to the value of selected.includes(item) (which returns a boolean).
For this to work, we need to update the value of selected array in every onChange event. We check if the item is contained in the previous version of selected. If it's there, we filter it out. If not, we add it:
const CheckboxList = ({ items }) => {
const [selected, setSelected] = useState([])
const onChecked = (item) =>
setSelected((prev) =>
prev.includes(item)
? prev.filter((val) => val !== item)
: [...prev, item]
)
return items.map((item) => (
<label key={item}>
<input
type="checkbox"
checked={selected.includes(item)}
onChange={() => onChecked(item)}
/>
<span>{item}</span>
</label>
))
}
Hope that clears things up a bit.
The best way to do it, it's to save selected checkboxes into a state array, so to check or uncheck it you just filter this state array based on checkbox value property that need to be unique.
Try to use array.some() on checkbox property checked. To remove it it's just filter the checkboxes setted up in the state array that are different from that single checkbox value.
I am passing through the react-select Select component as an InputComponent within the Material-UI InputBase component. I have successfully been able to populate the value from the options, however, I'm unable to use isClearable.
When isClearable is triggered, null is passed to the handleChange(event) function and I'm hoping there is a way to force an object through to prevent null creating an error.
The handleChange function within InputBase has var element = event.target || inputRef.current. As event is null, it's not even getting to inputRef which will contain the required object.
Would be good to get this working as an uncontrolled component.
I have created a codebox to illustrate the problem: https://codesandbox.io/s/morning-feather-l7xqf
You could supply your custom onChange() to catch the null and pass through your own value:
// Deconstruct from otherProps
const SelectWrapper = ({ inputRef, onChange, ...otherProps }) => {
function handleChange(event) {
// Overwrite the event with your own object if it doesn't exist
if (!event) {
event = {
target: inputRef,
value: '',
};
}
onChange(event);
}
return (
// Pass in the custom handleChange
<Select styles={customStyle} isClearable ref={inputRef} onChange={handleChange} {...otherProps} />
);
};
I am trying to close the Select dropdown when the limit of selected items is reached.
The following is not working:
handleSearch = selectedOption => {
const closeMenuOnSelect = selectedOption.length >= 3;
this.setState({ closeMenuOnSelect }, () => this.updateSelect());
}
updateSelect = () => {
console.log(this.state.closeMenuOnSelect); // the state is getting updated but it does not have the effect on the `closeMenuOnSelect` property
}
And the component:
<Select className='react-select-container'
isMulti
closeMenuOnSelect={this.state.closeMenuOnSelect}
options={this.state.locations}
onChange={(e) => this.handleSearch(e)} />
It doesn't need to on event. I just want the menu to remain open and when the limit of selected options is reached I want to close it.
There is a prop "menuIsOpen" in React Select and by using it you can control the open or close of dropDown
const [showMenu, setShowMenu] = useState(false);
<Select className='react-select-container'
isMulti
options={this.state.locations}
onChange={(e) => this.handleSearch(e)}
menuIsOpen={showMenu}
onBlur={() => setShowMenu(false)}
blurInputOnSelect
/>
So now you can call setShowMenu(true) / setShowMenu(false) to show or hide the select menu as per your need.
I had a react-select rendering a list of emails, and i need to keep the selected emails as a default option when the email is selected and saved, but the defaultValues are not working. How can i do that?
Here is my select component:
const [selectedOption, setSelectedOption] = useState("")
const makeEmailOption = item => ({
value: item.id,
label: item.ccEmail,
id: item.id,
chipLabel: item.ccEmail,
rest: item,
selected: item.selected
})
const makeEmailOptions = items => items.map(makeEmailOption)
const handleChange = (value) => {
setSelectedOption(value)
props.emails(value)
}
return (
<div>
<Select
multi={true}
name={props.name}
options={makeEmailOptions(props.ccemailfilter)}
onChange={handleChange}
value={selectedOption}
/>
</div>
)
I receive everything as props and work with that to make the options. How can i do that to make the default value if a field selected is true?
You almost have it, but in this case, you are setting the value to the selectedOption instead of setting the defaultValue. Also, you are changing the default value each time there is a change, which shouldn't be needed.
const defaultVal = {value: selectedOption, label: selectedOption};
return (
<div>
<Select
multi={true}
name={props.name}
options={makeEmailOptions(props.ccemailfilter)}
defaultValue={defaultVal}
/>
</div>
)
I came with the following solution, since my component use a function to set some variables to the select, i use a useEffect to call that with a filter right after the page render.
useEffect(() => {
handleChange(makeEmailOption(props.ccemailfilter.filter(x => x.selected)))
}, [])
const handleChange = (value) => {
setSelectedOption(value)
props.emails(value)
}
So, the handleChange are called on the onChange of the select and once after the page loads, to create a value to the select to use.
I am using react semantic ui dropdown and want to handle onclick event on my dropdown. consider i have this method to handle
handleClick = (e, {value }) => this.setState({id: value })
then i can call with this
<Dropdown
selection
options={myOptions}
placeholder='I change value on keyboard navigation'
onClick={this.handleClick} />
but in some circumstances i want to call handleClick with additional parameter, i've tried this
<Dropdown
selection
options={myOptions}
placeholder='I change value on keyboard navigation'
onClick={this.handleClick.bind(this,idx)} />
and change my handler to handleClick = (e, {value },idx) => this.setState({id: value }) but it seems not working. What am i doing wrong or any suggestion?
I think this part is not executing like this
onClick={this.handleClick.bind(this,idx)}
It should be change to this
onClick={(idx) => this.handleClick.bind(this,idx)}
In React when we have to pass the arguments with function on click , then we have to add arrow notation like above.
If this help doesn't work for you then I think you have to change your binding
Then Following code will help you
Change onClick={this.handleClick.bind(this,idx)} to this
onClick={(e, e.target.value, idx) => this.handleClick(e, e.target.value, idx)}
And also change
handleClick = (e, {value },idx) => this.setState({id: value })
to this
handleClick = (e, value, idx) => this.setState({id: value })