'Only send values that have changed in formik onSubmit
I have a small table of data that is pre-filled by an api call on page load. Each row in the table has a facility name and an Enabled
value which comes from the api call. If Enabled
== true the checkbox is shown as checked.
I have a couple checkboxes that are grayed out because of a condition in which it cannot be changed at all so there's a readOnly attribute on the field.
Onto my question, for brevity I condensed the list of facilities shown in the table, but in reality there could be X
amount of facilities. In my onSubmit
function I only want to send the facility name and enabled
value if they have been selected/deselected instead of sending the entire list every time submit is pressed.
Ideally I want the shape of the data sent to look like so:
{
facilityName: "Backup Restore",
enabled: true
}
Now, I have been able to isolate JUST the facilityName
and enabled
value but I cannot figure out to only include the values that have been changed in the form. Like I said above, not every single facility name and enabled key/value should be sent every time submit is pressed just the ones that have been changed.
This is what I currently have(and can be seen in the sandbox below) in my onSubmit function
<Formik
enableReinitialize
initialValues={{
facilities: loggingFacilities
}}
onSubmit={async (values, { setSubmitting }) => {
alert(JSON.stringify(values, null, 2));
try {
setLoggingFacilities(values.facilities);
const valuesToSend = values.facilities.map(facility => {
return {
key: facility.facilityName,
value: facility.enabled
};
});
.....
I have a codesandbox here
Solution 1:[1]
From the second param of your onSubmit
callback, you can access props
, so you could diff values
against props.initialValues
or however you have called the prop you use to initialize the form.
Actually, that's the suggestion from Jared Palmer:
You can compare
initialValues
and values withinhandleSubmit
/onSubmit
.
Using Array.prototype.filter()
it would look something like this:
onSubmit={async (values, { props, setSubmitting }) => {
// Let's assume this has the same format as `values.facilities`:
const { initialValues } = props;
try {
setLoggingFacilities(values.facilities);
const valuesToSend = values.facilities.filter((facility, i) => {
// Let's send only those that have just been disabled or enabled:
return facility.enabled !== initialValues[i].enabled;
}).map((facility) => ({
key: facility.facilityName,
value: facility.enabled
}));
// ...
} catch(err) { ... }
}
Solution 2:[2]
Try this:
const getChangedValues = (values, initialValues) => {
return Object
.entries(values)
.reduce((acc, [key, value]) => {
const hasChanged = initialValues[key] !== value
if (hasChanged) {
acc[key] = value
}
return acc
}, {})
}
Solution 3:[3]
I'm arriving later to this issue but I think you can use dirty flag. It appears to do the deep comparing with initial values for you. And will complement nicely with @Dazinger approach.
dirty: boolean Returns true if values are not deeply equal from initial values, false otherwise. dirty is a readonly computed property and should not be mutated directly.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | randomKek |
Solution 3 | Guillermo F. Lopez |