将数组附加到 FormData 并通过 AJAX 发送

我使用 ajax 提交一个包含数组、文本字段和文件的多部分表单。

我像这样将每个 VAR 附加到主数据

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);

然后使用 ajax 函数将其发送到一个 PHP 文件,以便存储在 sqlDB 中。

$.ajax({
type: "post",
url: 'php/submittionform.php',
cache: false,
processData: false,
contentType: false,
data: data,
success: function(request) {$('#box').html(request); }
})

但是在 PHP 方面,arr变量是一个数组,它显示为一个字符串。

当我不使用 ajax 作为表单数据发送它,而是使用简单的 $.POST选项时,我会在 PHP 端将它作为一个数组来获得,但这样我就不能同时发送文件了。

有什么办法吗?

354477 次浏览

你有几个选择:

将其转换为 JSON 字符串,然后用 PHP 解析(推荐使用)

JS

var json_arr = JSON.stringify(arr);

PHP

$arr = json_decode($_POST['arr']);

或者使用 @ Curios 的方法

通过 FormData发送数组。


不推荐使用: 使用序列化数据,然后在 PHP 中反序列化

JS

// Use <#> or any other delimiter you want
var serial_arr = arr.join("<#>");

PHP

$arr = explode("<#>", $_POST['arr']);

你也可以这样通过 FormData发送一个数组:

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);

因此,您可以像使用简单的 HTML 表单那样编写 arr[]。在 PHP 的情况下,它应该工作。

您可能会发现这篇文章很有用: 如何在查询字符串中传递数组?

这是一个老问题,但我最近在发布对象和文件时遇到了这个问题。我需要能够发布一个对象,其子属性也是对象和数组。

下面的函数将遍历一个对象并创建正确的 formData 对象。

// 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);
}
});
}
}

这将转换以下 json-

{
name: 'starwars',
year: 1977,
characters: {
good: ['luke', 'leia'],
bad: ['vader'],
},
}

转换为下面的 FormData

 name, starwars
year, 1977
characters[good][], luke
characters[good][], leia
characters[bad][], vader

打字稿版本:

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;
}
}

使用:

let formData = Utility.convertModelToFormData(model);

下一个版本对包含简单值的数组的模型有效:

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;
}

将所有类型输入添加到 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]) ;
}

如果有嵌套对象和数组,填充 FormData 对象的最佳方法是使用递归。

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);
}
}

基于@YackY 回答简短的递归版本:

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);
}
}

用法例子:

var data = {a: '1', b: 2, c: {d: '3'}};
var formData = new FormData();
createFormData(formData, 'data', data);

发送数据:

data[a]=1&
data[b]=2&
data[c][d]=3

这是另一个版本的 convertModelToFormData,因为我需要它也能够发送文件。

Ulityy.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);
...
}

将三种数据格式转换为 FormData :

1. 单值,如字符串、数字或布尔值

 let sampleData = {
activityName: "Hunting3",
activityTypeID: 2,
seasonAssociated: true,
};

2. 数组是对象的数组

let sampleData = {
activitySeason: [
{ clientId: 2000, seasonId: 57 },
{ clientId: 2000, seasonId: 57 },
],
};

3. 对象持有键值对

let sampleData = {
preview: { title: "Amazing World", description: "Here is description" },
};

让我们的生活变得轻松:

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;
}

例子 : 输入资料

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" },
};

输出表格数据:

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

我已经修复了类型脚本的版本。对于 javascript,只需删除类型定义。

  _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;
}

JavaScript 代码:

var formData = new FormData();
let arr = [1,2,3,4];
formData.append('arr', arr);

Php 的输出:

$arr = $_POST['arr']; ===>  '1,2,3,4'

解决方案 php 代码:

$arr = explode(",", $_POST['arr']); ===> [1,2,3,4]

简单的方法:

data.map(dt=>formdata.append("name",dt))

我试过了,效果很好

如果您正在使用 姜戈 ArrayField,所以您需要发送数据作为例子如下

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));

在有元素数组或对象的情况下。您可以简单地使用 set 方法和 JSON.stringify 一起将数组转换为字符串并将值设置为该字符串。将 tstringfied JSON 数据返回到正确的数组 JSON,设置表单值,并在后端将其转换回一个有效的数组,这样问题就很少了。

const bookItems = [
{
name: "John Doe",
age: 21
}
...
];
formData.set("books", JSON.stringify(bookItems));