Handling different data types
Converting nested objects and arrays
In the wild world of internet, your JavaScript object may contain nested objects or arrays. In that case, it's time to flex your recursion skills:
function serialize(data, parentKey, formData = new FormData()) {
Object.entries(data).forEach(([key, value]) => {
if (value instanceof File) {
formData.append(parentKey ? `${parentKey}[${key}]` : key, value); // special pass for File VIPs
} else if (typeof value === 'object' && !(value instanceof Date)) {
serialize(value, parentKey ? `${parentKey}[${key}]` : key, formData); // Oh look, another level, here we go again!
} else {
formData.append(parentKey ? `${parentKey}[${key}]` : key, value); // normal objects, nothing fancy.
}
});
return formData;
}
const obj = { user: { name: 'Alice', avatar: FileObject } };
const formData = serialize(obj); // Don't worry `serialize()`, we're not judging you... much.
Ignoring the unworthy
Every king has his favorites and so can your FormData. If any object property should not join the FormData party, use an ignore list:
const ignoreList = ['secret', 'deprecated'];
Object.entries(obj).forEach(([key, value]) => {
if (!ignoreList.includes(key)) {
formData.append(key, value); // Welcome to the exclusive club!
}
});
VIP treatment for files
Beware when your object plays hosts to File instances! Bestow them directly to your FormData, showing the respect they deserve:
if (value instanceof File) {
formData.append(key, value, value.name); // Rolling out the red carpet for File data
}
Advanced tactics
Harness the power of ES6
Unleash your inner Jedi by leveraging ES6 for a cleaner conversion:
const obj = { key1: 'value1', key2: 'value2' };
const formData = Object.keys(obj).reduce((fd, key) => (fd.append(key, obj[key]), fd), new FormData());
Diving deep with recursive conversion
If your JavaScript object is as nested as a set of Russian dolls, use a recursive function for deep conversion:
const convertToFormData = (obj, fd = new FormData(), prevKey = null) => {
Object.entries(obj).forEach(([key, value]) => {
const fieldName = prevKey ? `${prevKey}[${key}]` : key;
if (value instanceof Object && !(value instanceof File || value instanceof Date)) {
return convertToFormData(value, fd, fieldName); // Let's dive deeper...
}
fd.append(fieldName, value); // The end is near...whoops, not that morbid.
});
return fd;
};
While submitting data through jQuery's $.ajax()
, set processData
and contentType
to false:
$.ajax({
url: '/target-url',
type: 'POST',
data: formData,
processData: false, // jQuery, stop meddling with our data!
contentType: false, // jQuery, do you even MIME?
success: function(data) {
console.log('Upload successful!');
}
});
Error handling and server response
Validation on the server-side
In the realm of security, never trust the client. Always validate FormData on the server-side:
if ($_FILES['avatar']['error'] === UPLOAD_ERR_OK) {
// All smooth sailing for file upload
} else {
// Time to manage those pesky file upload errors
}
Handling client-side responses
Bask in the sun of jQuery's .done()
, absorbing server responses and fending off any errors:
$.ajax(/*...*/).done(function(data) {
console.log('Response received:', data);
}).fail(function(jqXHR, textStatus) {
console.error('Request failed:', textStatus); // Error: the winters of discontent
});
Ensuring wide compatibility
Create harmony across IE11 and other modern browsers through vigorous testing.