I am working on an app that relies heavily on data input and so I have to construct different kinds of objects with required and non-required data, and the non-required data piece is my issue here, as this leads to a lot of additional code and I am wondering if there is a way to avoid this.
Here I have a form that has 6 fields (its just one example, but I have the same case in many other places in the app), 2 of them are required, the rest are not, and I wrote this function to handle the object creation:
const handleAddSupplier = (e) => {
e.preventDefault();
const formData = e.target.elements;
const supplierData = {
name: formData.name.value,
companyId: formData.companyId.value,
...((formData.country.value || formData.city.value || formData.postalCode.value || formData.street.value) && {
address: {
...(formData.country.value && { country: formData.country.value }),
...(formData.city.value && { city: formData.city.value }),
...(formData.postalCode.value && { postalCode: formData.postalCode.value }),
...(formData.street.value && { street: formData.street.value }),
},
}),
};
console.log(supplierData);
};
And it works, but its too much code in my opinion, I suspect that there is an easier way to do this.
The "signature" of the object that must be created is:
{
name: "",
companyId: "",
address: {
country: "",
city: "",
postalCode: "",
street: ""
}
}
The address object and its fields are entirely optional, so if none of the fields of address is available (i.e. the user inputs only the required fields and nothing else), the address object should not be created at all, not even as an empty object.
My code works, I am just interested to see if there are other simpler ways.
Edit: I destructured the object a bit and saved myself some writing, but still, what if I have 10 non-required fields, do I conditionally "OR" them all 10?
const { name, companyId, country, city, postalCode, street } = e.target.elements;
const supplierData = {
name: name.value,
companyId: companyId.value,
...((country.value || city.value || postalCode.value || street.value) && {
address: {
...(country.value && { country: country.value }),
...(city.value && { city: city.value }),
...(postalCode.value && { postalCode: postalCode.value }),
...(street.value && { street: street.value }),
},
}),
};
Or another way of writing the same thing:
const {
name: { value: name },
companyId: { value: companyId },
country: { value: country },
city: { value: city },
postalCode: { value: postalCode },
street: { value: street },
} = e.target.elements;
const supplierData = {
name: name,
companyId: companyId,
...((country || city || postalCode || street) && {
address: {
...(country && { country }),
...(city && { city }),
...(postalCode && { postalCode }),
...(street && { street }),
},
}),
};
So this begs the question, is this just a "pick your poison" scenario? Last scenario for example, you write the code to destructure and name the properties prior to creating the object, and then within the object, the code is simpler and easier to read?
And this leads me to another question, the optimization that I am looking for, is it something worth investigating at all, or sticking to either of these scenarios is fine?