Skip to content

Instantly share code, notes, and snippets.

@ghinda
Last active March 30, 2024 18:51
Show Gist options
  • Save ghinda/8442a57f22099bdb2e34 to your computer and use it in GitHub Desktop.
Save ghinda/8442a57f22099bdb2e34 to your computer and use it in GitHub Desktop.
JavaScript Object to FormData, with support for nested objects, arrays and File objects. Includes Angular.js usage.
// takes a {} object and returns a FormData object
var objectToFormData = function(obj, form, namespace) {
var fd = form || new FormData();
var formKey;
for(var property in obj) {
if(obj.hasOwnProperty(property)) {
if(namespace) {
formKey = namespace + '[' + property + ']';
} else {
formKey = property;
}
// if the property is an object, but not a File,
// use recursivity.
if(typeof obj[property] === 'object' && !(obj[property] instanceof File)) {
objectToFormData(obj[property], fd, property);
} else {
// if it's a string or a File object
fd.append(formKey, obj[property]);
}
}
}
return fd;
};
// usage example
var z = objectToFormData({
obj: {
prop: 'property value'
},
arr: [
'one',
'two',
'three',
new File([''], '')
],
file: new File([''], '')
});
var xhr = new XMLHttpRequest;
xhr.open('POST', '/', true);
xhr.send(z);
// usage for Angular.js
// wrap object to formdata method,
// to use it as a transform with angular's http.
var formDataTransform = function(data, headersGetter) {
// we need to set Content-Type to undefined,
// to make the browser set it to multipart/form-data
// and fill in the correct *boundary*.
// setting Content-Type to multipart/form-data manually
// will fail to fill in the boundary parameter of the request.
headersGetter()['Content-Type'] = undefined;
return objectToFormData(data);
};
$http({
method: 'POST',
url: '/',
transformRequest: formDataTransform,
data: { your_object: {} }
})
.success(function(res) {});
@develforever
Copy link

Namespace is lost. This could fix it:
objectToFormData(obj[property], fd, namespace+"["+ property+"]");

@IvsonEmidio
Copy link

IvsonEmidio commented Aug 16, 2022

Update for Typescript 2022.
Edit: Date support removed.

function parseGenericObject<T>(
   object: T,
   form?: FormData,
   namespace?: string
 ): FormData {
   const formData = form || new FormData()
   for (const property in object) {
     const isPropertyExist = property in object

     if (!isPropertyExist) {
       continue
     }

     const contextProperty = object[property]
     const formKey = namespace ? `${namespace}[${property}]` : property

     if (
       typeof contextProperty === 'object' &&
       !(contextProperty instanceof File)
     ) {
       parseGenericObject<any>(contextProperty, formData, formKey)
     } else {
       formData.append(formKey, String(contextProperty))
     }
   }
   return formData
 }

@Ou7law007
Copy link

This does not work. It obviously is not nesting anything.

The server receives: {'p1[p1]' (all one key): val} instead of {'p1': {'p2': val}}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment