Question
Since you need to have no errors on the array does this make the most sense for validating Arrays or am I making this too difficult? If you don't return undefined for the array, the submit will not work.
products is an array with each object having a name, cases, and bottles.
export const validate = values => {
const errors = {};
if (!values.customer) errors.customer = 'Required';
if (!values.date) errors.date = 'Required';
const productErrors = [];
values.products.forEach(product => {
let errors = {};
if (!product.name) errors.name = 'Required';
if (!product.cases && !product.bottles) {
errors.cases = 'Required';
errors.bottles = 'Required';
}
productErrors.push(errors);
});
if (productErrors.some(errorObject => !isEmpty(errorObject))) {
errors.product = productErrors;
} else {
errors.product = undefined;
}
return errors;
};
You could maybs make it less imperative with like map and reduce but this seems fine to me. Tbh, I’m still exlloring “best practices” with arrays too
Check out the latest version.
I noticed that remove(i) touches the array, while push({}) doesn't. Are you getting this as well? Is this intended behavior?
FieldArray name="names"...
() => push({ name: 'David' }) // touched = {};
() => remove(index) // touched = { names: [] }
So this is what I found for showing errors with FieldArrays based on touched and errors! I don't know the perf impact on this function, but I see a lot of people having this issue in the future.
function getError(touched, errors, name) {
return (touched[name] && errors[name]) || (getNested(touched, name) && getNested(errors, name));
}
function getNested(theObject, path, separator) {
try {
separator = separator || '.';
return path
.replace('[', separator)
.replace(']', '')
.split(separator)
.reduce(function(obj, property) {
return obj[property];
}, theObject);
} catch (err) {
return undefined;
}
}
const error = getError(touched, errors, name);
<Input
fieldHasError={!!error}
errorText={error}
/>
This has finally solved everything for me with Formik!!
Thanks so much for all your hard work @jaredpalmer
Should I just export dlv as get from the internals?
Spoke too soon. This is a new one. With this object, handleSubmit will not work. No errors, no trying to submit. The errors object is empty, so why wouldn't handleSubmit work?
{
"values": {
"customer": {
"id": "1545",
"description": "FRUGAL MACDOOGAL"
},
"date": "2018-02-09",
"notes": "",
"followup": "",
"products": [
{
"name": {
"id": "11810",
"description": "FIREBALL (100M)"
}
}
]
},
"errors": {},
"touched": {
"customer": {
"id": true,
"description": true
},
"date": true,
"notes": true,
"followup": true,
"products": [
{
"name": {
"id": true,
"description": true
}
}
]
}
}
My validate
export const validate = values => {
const errors = {};
if (!values.customer) errors.customer = 'Required';
if (!values.date) errors.date = 'Required';
const productErrors = [];
values.products.forEach(product => {
let errors = {};
if (!product.name) errors.name = 'Required';
productErrors.push(errors);
});
if (productErrors.some(obj => !isEmpty(obj))) {
errors.products = productErrors;
} else {
errors.products = undefined;
}
return errors;
};
@jaredpalmer Under Formik's _this.submitForm, isValid = Object.keys(maybePromisedErrors).length === 0 is showing isValid as false, and maybePromisedErrors = {products: undefined}
Shouldn't undefined make isValid = true?
EDIT: Fixed by getting rid of the else statement.
@jaredpalmer also wanted to add I just used nested fieldarrays and they work fine.
<Field name={`products[${i}].formats[${j}].qpc`} label="QPC" component={Form.Input} />
I have the same problem, I can not set the fieldarray as touched, setFieldTouched creates as object and not as array. And when I push he also does not arrow as touched.
Most helpful comment
Check out the latest version.