Can't change value of react-select field - reactjs

I am using the React-Select library for my React app select fields. I have the same form for adding and editing data. If I don't provide any value, it works just fine, but if I want to have default values when the app renders, I can't change them. They appear as selected, but if I try to select another option it just doesn't update and the value I provided in value prop remains selected.
I tried using defaultValue instead of value, but then it doesn't select anything when the app renders.
<Select
placeholder="Deposit"
options={deposits}
getOptionValue={ option =>
option["id"]
}
getOptionLabel={ option => {
return option["name"];
}}
onChange={ value => {
this.setState({ deposit_id: value.id }}
value={{
value: deposit_id || "",
name: deposit_name || ""
}}
/>
deposits is an array of objects, and it renders the list of names, but when I click on one of them, the one that I provided in value remains selected, but it should select the one that I click on... How do I change it? Is there something wrong with my onChange function? Or what is it that I'm doing wrong?

Try the following code. The value props should be a string, i.e the value from the state.
<Select
placeholder="Deposit"
options={deposits}
getOptionValue={ option =>
option["id"]
}
getOptionLabel={ option => {
return option["name"];
}}
onChange={ value => {
this.setState({ deposit_id: value.id }}
value={deposit_id}
/>

Related

Unchecking a checkbox in react from several checkbox groups (I'm using React hooks)

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.

Changing Autocomplete value using react-hook-form (Material-UI)

I have two Autocomplete fields, my goal is to change the value of the second field by the value of the first field.
The problem I face is when my trying to send the new value to the "setValue" function nothing happens the state form changing, but the autocomplete field shows the old value.
In this sand box:
https://codesandbox.io/s/dazzling-carson-84dxp?file=/src/Form/Components/UserCountry.js
you can see my implementation.
If you look at console when you change user_name field, you can see materialUI warning in the console which says:
Material-UI: A component is changing the uncontrolled value state of Autocomplete to be controlled.
it's reason is that your user_country's value by default is undefined and material consider this field as uncontrolled field, it means material will take the control of user_country value. To solve the problem you have two solutions:
1- Defining your form by defaultValues options like this:
const methods = useForm({
defaultValues: {
user_name: null,
user_country: null
}
});
2- Sending null as value to AutoComplete when it doesn't have any value, like this:
<Controller
control={control}
name={`user_country`}
render={({ field: { onChange, value } }) => (
<Autocomplete
id="country-select-demo"
options={countries}
onChange={(event, item) => {
onChange(item);
}}
value={value || null}
...
/>
)}
/>
Here You can see your form which updates user_country whenever you change user_name field.

Value is not updating .. its updating but after refreshing the page but not everytime | Reactjs

const availableFunc = (id) => {
if (Active.length > 0) {
let available = Active.filter((obj) => obj.type === id).map((obj) =>
obj.available !== undefined ? obj.available : ""
);
return available[0];
}
};
All data is stored in Active and the desired value is present in available when I console available[0] then I am getting the correct value but don't know why it's not updating the value in defaultValue={}. Sometime after 5-6 refresh its updated [but I] don't know how!! Again I refresh the page the value goes hidden.
Please team and seniors help me to solve this problem..
<Select
defaultValue={availableFunc(res.eId)}
onChange={(event) =>
handleChangeSelect(
event.target.value,
res.eId,
res.dropDown[0]
)
}
>
{res.vals &&
res.vals.map((res) => {
return (
<MenuItem value={res}>{res}</MenuItem>
);
})}
</Select>
Issue
The defaultValue prop/attribute is just the initial value of the input when the component mounts. It's generally used for uncontrolled inputs, i.e. you aren't storing the input's value in state (updated via the onChange handler). Changes to this prop don't actually change the value being used by the input, you should be seeing a react warning, something to the effect of "Changing an input from uncontrolled to controlled...".
Solution
Since you've attached an onChange handler I'll assume you meant for this to be a controlled input. Use the value prop.
<Select
value={availableFunc(res.eId)}
onChange={(event) =>
handleChangeSelect(
event.target.value,
res.eId,
res.dropDown[0]
)
}
>
...

react-final-form input.onChange(null) does not update state immediately

We currently have a component <RenderDropdown /> which renders a material-ui <Select /> element. This takes options as props and is wrapped in a react-final-form <Field />.
Our issue is when we load the initialValues props of the <Form />, there are a few cases where the selected dropdown value no longer exists in the dropdown, so we want to set the dropdown value to null. We do that within the <RenderDropdown />:
componentDidMount() {
this.clearInputIfValueDoesntExistInOptions();
}
componentDidUpdate() {
this.clearInputIfValueDoesntExistInOptions();
}
clearInputIfValueDoesntExistInOptions() {
const {
input: { value, onChange },
options
} = this.props;
// Clear input value if it doen't exist in options
if (
value &&
!options.some((option) => option.key === value || option.value === value)
) {
console.log(
"clearInputIfValueDoesntExistInOptions",
"Setting value to null as the selected value does not exist in the current dropdown's options"
);
// If I use input.onChange, it does not update the final form state to null immediately.
onChange(null);
}
}
This does set the value to null, but the form state does not update immediately, so the UI does not update either. It only updates once we change another field value or if we submit the form.
I've made a quick demo that simulates our issue:
https://codesandbox.io/s/react-final-form-inputonchange-null-k7poj
Thanks.

Antd RadioGroup onChange fires before radio value is set

I'm using ant design and I'm having trouble with a radio group. It seems to me like the onChange handler on the RadioGroup fires when a radio button is clicked, but before the value of that radio button is set.
Here is some sample code
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log('field value', getFieldValue(name)); // previous value, not changed value.
};
const component =
getFieldDecorator &&
getFieldDecorator(name, {
initialValue: value,
rules: formatValidations(validations)
})(
<RadioGroup name={name} onChange={handleChange}>
<Radio value={1} key={1}>1</Radio>
<Radio value={2} key={2}>2</Radio>
<Radio value={3} key={3}>3</Radio>
</RadioGroup>
);
When this handleChange function runs, the field value is wrong. The first time I click radio 1, the value is undefined. Then I click 2, the value is 1. In other words, the onChange event is triggered, but the the value of the radio button is not yet set, I am only able to get the previously set value. Can anyone see anything wrong with my implementation?
Also, e.target.value is the expected changed value (it does not match the getFieldValue value).
Thanks
The antd support recommends using onValuesChange in Form.create() https://github.com/ant-design/ant-design/issues/20418
I found this workaround that works for me:
<Radio.Group
onChange={(e: RadioChangeEvent) => {
form.setFieldsValue({ yourRadioFieldNameFromGetFieldDecorator: e.target.value }, () => {
handleChange();
});
}}
>
The callback ensures that field value is set.
You should really use e.target.value if you want the value immediately. since the value is not set yet (to the antd form yet) at the moment you click the radio.(the field needs to pass setStatus, setfeedback etc)
if you really want to use getFieldValue, you can do the setTime strick
setTimeout(() => console.log(this.props.form.getFieldValue('radio-group')), 0)

Resources