Reputation: 2693
I'm using ajax to submit a multipart form with array, text fields and files.
I append each VAR to the main data as so
var attachments = document.getElementById('files');
var data= new FormData();
for (i=0; i< attachments.files.length; i++){
data.append('file', attachments.files[i]);
console.log(attachments.files[i]);
data.append ('headline', headline);
data.append ('article', article);
data.append ('arr', arr);
data.append ('tag', tag);
then I use the ajax function to send it to a PHP file to store inside sql DB.
$.ajax({
type: "post",
url: 'php/submittionform.php',
cache: false,
processData: false,
contentType: false,
data: data,
success: function(request) {$('#box').html(request); }
})
But on the PHP side, the arr
variable, which is an array appears as a string.
When I don't send it with ajax as Form data but use the simple $.POST
option I do get it as an array on the PHP side, but then I can't send the files as well.
any solutions?
Upvotes: 213
Views: 443978
Reputation: 31
Javascript with typescript. Create a function for FormData() data handling
function createFormData(formData: FormData, key: string,
data: any): void {
if (typeof data === 'object' && !Array.isArray(data)) {
for (const prop in data) {
if (data.hasOwnProperty(prop)) {
createFormData(formData, `${key}[${prop}]`, data[prop]);
}
}
} else if (Array.isArray(data)) {
data.forEach((item, index) => {
createFormData(formData, `${key}[${index}]`, item);
});
} else {
formData.append(key, data);
}
}
const data = {name:["Shariar","Sheikh"],age:24}
const formData = new FormData()
createFormData(formData,"name",data.name)
createFormData(formData,"age",data.age)
Upvotes: 0
Reputation: 327
In a case where you have an array of elements or maybe an object. You can simply use the set method together with JSON.stringify to convert the array to a string and set the value to that string. An tstringified json data back to a proper array JSON, set the form value, and on the backend convert back to a valid array with very little problems.
const bookItems = [
{
name: "John Doe",
age: 21
}
...
];
formData.set("books", JSON.stringify(bookItems));
Upvotes: 0
Reputation: 846
If you are using django ArrayField
so you need send data as example below
const form = new FormData();
const value = ["Hello", "World"];
const key = "arr";
let i;
for (i = 0; i < value.length; i++) {
form.append(key, value[i]);
}
axios.post(url, form).then(res=> console.log(res));
Upvotes: 1
Reputation: 15
simple way :
data.map(dt=>formdata.append("name",dt))
i've tried it, it works perfectly
Upvotes: -3
Reputation: 23277
You can also send an array via FormData
this way:
var formData = new FormData;
var arr = ['this', 'is', 'an', 'array'];
for (var i = 0; i < arr.length; i++) {
formData.append('arr[]', arr[i]);
}
console.log(...formData);
So you can write arr[]
the same way as you do it with a simple HTML form. In case of PHP it should work.
You may find this article useful: How to pass an array within a query string?
Upvotes: 420
Reputation: 11
JavaScript code:
var formData = new FormData();
let arr = [1,2,3,4];
formData.append('arr', arr);
Output on php:
$arr = $_POST['arr']; ===> '1,2,3,4'
Solution php code:
$arr = explode(",", $_POST['arr']); ===> [1,2,3,4]
Upvotes: 0
Reputation: 754
I've fixed the typescript version. For javascript, just remove type definitions.
_getFormDataKey(key0: any, key1: any): string {
return !key0 ? key1 : `${key0}[${key1}]`;
}
_convertModelToFormData(model: any, key: string, frmData?: FormData): FormData {
let formData = frmData || new FormData();
if (!model) return formData;
if (model instanceof Date) {
formData.append(key, model.toISOString());
} else if (model instanceof Array) {
model.forEach((element: any, i: number) => {
this._convertModelToFormData(element, this._getFormDataKey(key, i), formData);
});
} else if (typeof model === 'object' && !(model instanceof File)) {
for (let propertyName in model) {
if (!model.hasOwnProperty(propertyName) || !model[propertyName]) continue;
this._convertModelToFormData(model[propertyName], this._getFormDataKey(key, propertyName), formData);
}
} else {
formData.append(key, model);
}
return formData;
}
Upvotes: 1
Reputation: 4495
TransForm three formats of Data to FormData :
1. Single value like string, Number or Boolean
let sampleData = {
activityName: "Hunting3",
activityTypeID: 2,
seasonAssociated: true,
};
2. Array to be Array of Objects
let sampleData = {
activitySeason: [
{ clientId: 2000, seasonId: 57 },
{ clientId: 2000, seasonId: 57 },
],
};
3. Object holding key value pair
let sampleData = {
preview: { title: "Amazing World", description: "Here is description" },
};
The that make our life easy:
function transformInToFormObject(data) {
let formData = new FormData();
for (let key in data) {
if (Array.isArray(data[key])) {
data[key].forEach((obj, index) => {
let keyList = Object.keys(obj);
keyList.forEach((keyItem) => {
let keyName = [key, "[", index, "]", ".", keyItem].join("");
formData.append(keyName, obj[keyItem]);
});
});
} else if (typeof data[key] === "object") {
for (let innerKey in data[key]) {
formData.append(`${key}.${innerKey}`, data[key][innerKey]);
}
} else {
formData.append(key, data[key]);
}
}
return formData;
}
Example : Input Data
let sampleData = {
activityName: "Hunting3",
activityTypeID: 2,
seasonAssociated: true,
activitySeason: [
{ clientId: 2000, seasonId: 57 },
{ clientId: 2000, seasonId: 57 },
],
preview: { title: "Amazing World", description: "Here is description" },
};
Output FormData :
activityName: Hunting3
activityTypeID: 2
seasonAssociated: true
activitySeason[0].clientId: 2000
activitySeason[0].seasonId: 57
activitySeason[1].clientId: 2000
activitySeason[1].seasonId: 57
preview.title: Amazing World
preview.description: Here is description
Upvotes: 3
Reputation: 953
here's another version of the convertModelToFormData
since I needed it to also be able to send Files.
utility.js
const Utility = {
convertModelToFormData(val, formData = new FormData, namespace = '') {
if ((typeof val !== 'undefined') && val !== null) {
if (val instanceof Date) {
formData.append(namespace, val.toISOString());
} else if (val instanceof Array) {
for (let i = 0; i < val.length; i++) {
this.convertModelToFormData(val[i], formData, namespace + '[' + i + ']');
}
} else if (typeof val === 'object' && !(val instanceof File)) {
for (let propertyName in val) {
if (val.hasOwnProperty(propertyName)) {
this.convertModelToFormData(val[propertyName], formData, namespace ? `${namespace}[${propertyName}]` : propertyName);
}
}
} else if (val instanceof File) {
formData.append(namespace, val);
} else {
formData.append(namespace, val.toString());
}
}
return formData;
}
}
export default Utility;
my-client-code.js
import Utility from './utility'
...
someFunction(form_object) {
...
let formData = Utility.convertModelToFormData(form_object);
...
}
Upvotes: 5
Reputation: 1903
Based on @YackY answer shorter recursion version:
function createFormData(formData, key, data) {
if (data === Object(data) || Array.isArray(data)) {
for (var i in data) {
createFormData(formData, key + '[' + i + ']', data[i]);
}
} else {
formData.append(key, data);
}
}
Usage example:
var data = {a: '1', b: 2, c: {d: '3'}};
var formData = new FormData();
createFormData(formData, 'data', data);
Sent data:
data[a]=1&
data[b]=2&
data[c][d]=3
Upvotes: 6
Reputation: 73
If you have nested objects and arrays, best way to populate FormData object is using recursion.
function createFormData(formData, data, key) {
if ( ( typeof data === 'object' && data !== null ) || Array.isArray(data) ) {
for ( let i in data ) {
if ( ( typeof data[i] === 'object' && data[i] !== null ) || Array.isArray(data[i]) ) {
createFormData(formData, data[i], key + '[' + i + ']');
} else {
formData.append(key + '[' + i + ']', data[i]);
}
}
} else {
formData.append(key, data);
}
}
Upvotes: 2
Reputation: 119
add all type inputs to FormData
const formData = new FormData();
for (let key in form) {
Array.isArray(form[key])
? form[key].forEach(value => formData.append(key + '[]', value))
: formData.append(key, form[key]) ;
}
Upvotes: 5
Reputation: 66
Next version valid for model containing arays of simple values:
function convertModelToFormData(val, formData = new FormData(), namespace = '') {
if((typeof val !== 'undefined') && (val !== null)) {
if(val instanceof Date) {
formData.append(namespace, val.toISOString());
} else if(val instanceof Array) {
for(let element of val) {
convertModelToFormData(element, formData, namespace + '[]');
}
} else if(typeof val === 'object' && !(val instanceof File)) {
for (let propertyName in val) {
if(val.hasOwnProperty(propertyName)) {
convertModelToFormData(val[propertyName], formData, namespace ? namespace + '[' + propertyName + ']' : propertyName);
}
}
} else {
formData.append(namespace, val.toString());
}
}
return formData;
}
Upvotes: 2
Reputation: 22408
Typescript version:
export class Utility {
public static convertModelToFormData(model: any, form: FormData = null, namespace = ''): FormData {
let formData = form || new FormData();
let formKey;
for (let propertyName in model) {
if (!model.hasOwnProperty(propertyName) || !model[propertyName]) continue;
let formKey = namespace ? `${namespace}[${propertyName}]` : propertyName;
if (model[propertyName] instanceof Date)
formData.append(formKey, model[propertyName].toISOString());
else if (model[propertyName] instanceof Array) {
model[propertyName].forEach((element, index) => {
const tempFormKey = `${formKey}[${index}]`;
this.convertModelToFormData(element, formData, tempFormKey);
});
}
else if (typeof model[propertyName] === 'object' && !(model[propertyName] instanceof File))
this.convertModelToFormData(model[propertyName], formData, formKey);
else
formData.append(formKey, model[propertyName].toString());
}
return formData;
}
}
Using:
let formData = Utility.convertModelToFormData(model);
Upvotes: 16
Reputation: 7452
You have several options:
JS
var json_arr = JSON.stringify(arr);
PHP
$arr = json_decode($_POST['arr']);
Sending an array via FormData
.
JS
// Use <#> or any other delimiter you want
var serial_arr = arr.join("<#>");
PHP
$arr = explode("<#>", $_POST['arr']);
Upvotes: 156
Reputation: 17203
This is an old question but I ran into this problem with posting objects along with files recently. I needed to be able to post an object, with child properties that were objects and arrays as well.
The function below will walk through an object and create the correct formData object.
// formData - instance of FormData object
// data - object to post
function getFormData(formData, data, previousKey) {
if (data instanceof Object) {
Object.keys(data).forEach(key => {
const value = data[key];
if (value instanceof Object && !Array.isArray(value)) {
return this.getFormData(formData, value, key);
}
if (previousKey) {
key = `${previousKey}[${key}]`;
}
if (Array.isArray(value)) {
value.forEach(val => {
formData.append(`${key}[]`, val);
});
} else {
formData.append(key, value);
}
});
}
}
This will convert the following json -
{
name: 'starwars',
year: 1977,
characters: {
good: ['luke', 'leia'],
bad: ['vader'],
},
}
into the following FormData
name, starwars
year, 1977
characters[good][], luke
characters[good][], leia
characters[bad][], vader
Upvotes: 7