将数组附加到 FormData 并通过 AJAX 发送
Posted
技术标签:
【中文标题】将数组附加到 FormData 并通过 AJAX 发送【英文标题】:appending array to FormData and send via AJAX 【发布时间】:2013-04-12 19:33:26 【问题描述】:我正在使用 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 文件以存储在 sql DB 中。
$.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 端的一个数组,但我也无法发送文件。
有什么解决办法吗?
【问题讨论】:
【参考方案1】:您也可以通过这种方式通过FormData
发送数组:
var formData = new FormData;
var arr = ['this', 'is', 'an', 'array'];
for (var i = 0; i < arr.length; i++)
formData.append('arr[]', arr[i]);
因此,您可以像使用简单的 HTML 表单一样编写 arr[]
。如果是 PHP,它应该可以工作。
您可能会发现这篇文章很有用:How to pass an array within a query string?
【讨论】:
@Oleg 在formData.append('arr[]', arr[i]);
中写arr[]
有什么必要?为什么arr
不正确?我都试过了,但只有 arr[]
有效。
@Totoro 因为在arr
的情况下,您只需在每次循环迭代时重新定义此值,最后,最终值将等于最后一个数组元素,而不是整个数组
@Oleg 如果重新定义是这种情况,那么 arr[]
有什么不同,为什么 arr[]
没有重新定义? arr[]
也是一个字符串。在我的情况下,在测试 arr
和 arr[]
时都没有重新定义。我在 FormData 中得到了多个数组,它们具有相同的键但不同的值。所以我得到了arr
,其值为1
,另一个arr
,其值为2
。
@Totoro 是的,你是对的,我的错误。我相信这是更多特定于服务器端的问题。不同的语言可能会以不同的方式解析查询字符串。例如,PHP 的行为与您描述的一样,但我看到了示例(如果内存服务,在 Java 中),其中arr
也适用于数组。在this topic 有这个问题的更详细的答案
如果有人想发布一组对象,您可以将此答案扩展为如下for (var i = 0; i < myArr; i++) var myItemInArr = myArr[i]; for (var prop in myItemInArr) fileData.append(`myArr[$i][$prop]`, myItemInArr[prop]);
【参考方案2】:
您有多种选择:
将其转换为 JSON 字符串,然后在 PHP 中解析(推荐)
JS
var json_arr = JSON.stringify(arr);
PHP
$arr = json_decode($_POST['arr']);
或者使用@Curios's method
通过FormData
发送数组。
不推荐:用序列化数据,然后用 PHP 反序列化
JS
// Use <#> or any other delimiter you want
var serial_arr = arr.join("<#>");
PHP
$arr = explode("<#>", $_POST['arr']);
【讨论】:
问题是数组包含真实文本行,带有空格和标点符号。我不想搞砸了。 当您使用 JSON 对其进行编码和解析时,数据不会丢失。试一试;) 如果您正在使用带有自动映射或类似功能的 asp.net,那么您需要的是 @Curious 答案。 @Richard de Wit 如果你有 File 或 FormData 这样的数据,你会在 json.stringfy 中丢失它们 我更喜欢字符串化,更简单。因为您需要进行某种递归以使用 [] 传递数组数组,但很高兴知道可以这样做。【参考方案3】:打字稿版本:
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);
【讨论】:
非常感谢,它工作正常!对于那些不使用 Typescript 的人,您只需删除第一行和最后一行 + 将方法声明public static
替换为 function
+ 删除类型声明 : any
、: FormData
和 : FormData
。
到目前为止,该函数会跳过零和空字符串。要包含它们,请将第 7 行的 if
块替换为:if (!model.hasOwnProperty(propertyName) || (!model[propertyName] && model[propertyName]!==0 && model[propertyName]!=='')) continue;
【参考方案4】:
这是一个老问题,但我最近在发布对象和文件时遇到了这个问题。我需要能够发布一个对象,其子属性也是对象和数组。
下面的函数将遍历一个对象并创建正确的 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
【讨论】:
这对我很有用,只需要在附加内的值上应用字符串(值)(否则它会因真/假而失败)。它也应该是(value !== null) && formData.append(key, value)
而不仅仅是formData.append(key, value)
否则它会在空值上失败【参考方案5】:
将所有类型输入添加到 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]) ;
【讨论】:
【参考方案6】:这是convertModelToFormData
的另一个版本,因为我需要它也能够发送文件。
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;
我的客户端代码.js
import Utility from './utility'
...
someFunction(form_object)
...
let formData = Utility.convertModelToFormData(form_object);
...
【讨论】:
【参考方案7】:下一个版本适用于包含一系列简单值的模型:
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;
【讨论】:
【参考方案8】:如果您有嵌套对象和数组,填充 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);
【讨论】:
【参考方案9】:基于@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
【讨论】:
【参考方案10】:我已经修复了打字稿版本。对于 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;
【讨论】:
【参考方案11】:将三种格式的Data转化为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
【讨论】:
【参考方案12】: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]
【讨论】:
这可以使用一些解释说明它为什么以及如何工作,而不是仅仅显示你认为有效的代码。 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。以上是关于将数组附加到 FormData 并通过 AJAX 发送的主要内容,如果未能解决你的问题,请参考以下文章
如何在 javascript 中的 FormData 中附加对象?
我可以在javascript中将数组附加到“formdata”吗?
在没有ajax调用的情况下使用带有@HTML.BeginForm的formdata append