setFieldValue gives always sets value boolean true from multiple selection Dropdown - reactjs

if I console.log(data.value) it indeed shows array of chosen options. But when I console.log in validation function in form or submit the form, then the value of that field is always boolean true
initial value is [], but regardless of which multiple options I choose, the output is always boolean true. Diagnoses are strings. StateOptions is array of objects with key, value and text
with the rest of code always all fields(I do not write them here) give value, which was written to them
Looks like setFieldValue function(one of default Formik props) works wrong
this is the code of the field, which always has value true:
import { Dropdown, DropdownProps, Form } from "semantic-ui-react";
<DiagnosisSelection
diagnoses={diagnoses}
name="diagnosisCodes"
setFieldValue={setFieldTouched}
setFieldTouched={setFieldValue}
disabled={!(entrytype)}
/>
export const DiagnosisSelection = ({
diagnoses,
setFieldValue,
setFieldTouched,
disabled,
name
}: {
diagnoses: DiagnosisEntry[];
setFieldValue: FormikProps<{ diagnosisCodes: string[] }>["setFieldValue"];
setFieldTouched: FormikProps<{ diagnosisCodes: string[] }>["setFieldTouched"];
disabled:boolean;
name:string;
}) => {
const field = "diagnosisCodes";
const onChange = (
_event: React.SyntheticEvent<HTMLElement, Event>,
data: DropdownProps
) => {
setFieldTouched(field, true);
setFieldValue(field, data.value);
};
const stateOptions = diagnoses.map(diagnosis => ({
key: diagnosis.code,
text: `${diagnosis.name} (${diagnosis.code})`,
value: diagnosis.code
}));
if (disabled)
return null
return (
<Form.Field name={name}>
<label>Diagnoses</label>
<Dropdown
name={name}
fluid
multiple
search
selection
options={stateOptions}
onChange={onChange}
/>
<ErrorMessage name={field} />
</Form.Field>
);
};

It appeared that I wrote wrong: setFieldValue was setFieldTouched and viceversa:
<DiagnosisSelection
diagnoses={diagnoses}
name="diagnosisCodes"
setFieldValue={setFieldValue}
setFieldTouched={setFieldTouched}
disabled={!(entrytype)}
/>

Related

React using Formik does not clear the data value in Material UI form

I'm using formik.resetForm() to remove values from text fields in a form after submitting the data.
...
const handleSubmitProduct = async (values: Object, resetForm: any) => {
... code to handle my form data ...
resetForm()
if (response.ok) {
console.debug(response.status)
} else {
console.error(response)
}
}
const validate = (values: Object) => {
const errors: any = {}
if (!values.product_name) {
errors.product_name = "Include name"
}
return errors
}
... initialValues defined ...
const formik = useFormik({
initialValues: initialValues,
validate,
onSubmit: (values: Object, { resetForm }) => {
console.debug(JSON.stringify(values, null, 2))
handleSubmitProduct(values, resetForm)
},
})
return (
<FormLabel>Display name</FormLabel>
<TextField
onChange={formik.handleChange}
id="product_name"
onBlur={formik.handleBlur}
error={formik.touched.product_name && Boolean(formik.errors.product_name)}
helperText={formik.touched.product_name && formik.errors.product_name}
/>
<Button onClick={() => formik.handleSubmit()} variant="contained">
Submit
</Button>
)
I know there are many other questions like this but mine is different where I know the underlying Formik resources for values, errors, touched have been cleared but the values are still present in the text boxes.
The issue is I know the underlying Formik objects are cleared because after I submit, the validation triggers and prompts me like there is no value in the text field.
I've tried
resetForm({values: {initialValues}}) has the same result
resetForm(initialValues) has the same result
Use action.resetForm({values: {initialValues}}) in the onSubmit() which same result
https://codesandbox.io/s/mui-formik-fr93hm?file=/src/MyComponent.js but this approach uses the <Formik /> as opposed to useFormik which would change up my entire page but I'm in process to try anyway
I think the problem is that value of TextField is not value of formik. so the TextField is not controlled and by chaning value of formik it won't change.
assigning value of formik to it will do what you want
value={formik.values.firstName}
like this :
<TextField
onChange={formik.handleChange}
id="product_name"
value={formik.values.firstName}
onBlur={formik.handleBlur}
error={formik.touched.product_name && Boolean(formik.errors.product_name)}
helperText={formik.touched.product_name && formik.errors.product_name}
/>

Validating a child input type file with react-hook-form and Yup

I'm creating a form with a file upload with help of react-hook-form and Yup. I am trying to use the register method in my child component. When passing register as a prop (destructured in curly braces) the validation and submiting doesn't work. You can always submit the form and the submitted file object is empty.
Here's a sandbox link.
There are several of problems with your code.
1- register method returns an object with these properties:
{
onChange: function(){},
onBlur:function{},
ref: function(){}
}
when you define your input like this:
<input
{...register('photo')}
...
onChange={(event) => /*something*/}
/>
actually you are overrding the onChange method which has returned from register method and react-hook-form couldn't recognize the field change event. The solution to have your own onChange alongside with react-hook-form's onChange could be something like this:
const MyComp = ()=> {
const {onChange, ...registerParams} = register('photo');
...
return (
...
<input
{...params}
...
onChange={(event) => {
// do whatever you want
onChange(event)
}}
/>
);
}
2- When you delete the photo, you are just updating your local state, and you don't update photo field, so react-hook-form doesn't realize any change in your local state.
the problems in your ImageOne component could be solved by change it like this:
function ImageOne({ register, errors }) {
const [selectedImage, setSelectedImage] = useState(null);
const { onChange, ...params } = register("photo");
return (
...
<Button
className="delete"
onClick={() => {
setSelectedImage(null);
//Make react-hook-form aware of changing photo state
onChange({ target: { name: "photo", value: [] } });
}}
>
...
<input
//name="photo"
{...params}
type="file"
accept="image/*"
id="single"
onChange={(event) => {
setSelectedImage(event.target.files[0]);
onChange(event); // calling onChange returned from register
}}
/>
...
);
}
3- Since your input type is file so, the value of your photo field has length property that you can use it to handle your validation like this:
const schema = yup.object().shape({
photo: yup
.mixed()
.test("required", "photo is required", value => value.length > 0)
.test("fileSize", "File Size is too large", (value) => {
return value.length && value[0].size <= 5242880;
})
.test("fileType", "Unsupported File Format", (value) =>{
return value.length && ["image/jpeg", "image/png", "image/jpg"].includes(value[0].type)
}
)
});
Here is the full edited version of your file.

Formik, React-Select & Multiple Variables

i'm entirely lost when it comes to figuring this out. I have a existing select that works with formik & react-select, but I can't get it to work as a multi. Here's what i have so far:
import Select from 'react-select';
import { useField } from 'formik';
export default function SelectField(props) {
const [field, state, { setValue, setTouched }] = useField(props.field.name);
const onChange = ({ value }) => {
setValue(value);
};
return <Select {...props} onChange={onChange} onBlur={setTouched} />;
}
and
<Field
component={SelectField}
name="campfeatures"
options={selectObjects}
/>
How would I turn this into being capable of taking multi select? If I add isMulti to the Field, it "works" but it doesn't actually retain the multiple values.
Thanks for your help!
The argument type for onChange changes when the react-select receives isMulti from a single object to a list of objects. When using isMulti you don't need to destruct; the first parameter is the value.
You also want to make the react-select a controlled component by managing its value.
export default function SelectField(props) {
const [field, state, { setValue, setTouched }] = useField(props.field.name);
// value is an array now
const onChange = (value) => {
setValue(value);
};
// use value to make this a controlled component
// now when the form receives a value for 'campfeatures' it will populate as expected
return <Select {...props} value={state?.value} isMulti onChange={onChange} onBlur={setTouched} />;
}
The new value is an array of the selected options with label and value fields. If you want to store just the value you'll need to map it to a value and modify the react-select to handle that

How to reset the value of antd autocomplete, if the value is not in the data source

I'm using ant design AutoComplete for a location selection. And the data source is an array. Here is my code.
<Form.Item
label={t("City")}
name="location"
rules={[
{
required: true,
message: t("Please enter your city"),
},
]}
>
<AutoComplete
options={this.props.cityList}
allowClear={true}
placeholder={t("Enter your city")}
className="ant-select-custom"
filterOption={(inputValue, option) =>
option.value.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1
}
/>
</Form.Item>
The problem is, I can type anything that not in the data source. What I want it to restrict that. If I type something that not in the data source, The value should be erased. I tried with onBlur() and onChange() but no luck. Can anyone help me with this?
Thanks in advance
set value props in AutoComplete tag, and set an state for it, check if value on search is not found change the state to the initial.
const [value, setValue] = useState('');
const handleSearch = async val => {
if (val) {
const response = await dispatch(yourAction(val));
if (!response?.length) {
...
setValue(''); // this will clear the input
} else {
...
}
} else {
...
}
};
<AutoComplete
...,
value={value}
/>
This works for me.

How can i define a default value for react-select v1

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.

Resources