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

IT技术 javascript ajax arrays form-data
2021-01-15 06:19:24

我正在使用 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 端的数组获取,但是我也无法发送文件。

任何解决方案?

6个回答

您还可以通过FormData这种方式发送数组

var formData = new FormData;
var arr = ['this', 'is', 'an', 'array'];
for (var i = 0; i < arr.length; i++) {
    formData.append('arr[]', arr[i]);
}

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

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

@Totoro 因为如果arr你只是在每次循环迭代中重新定义这个值,最后,最终值将等于最后一个数组元素,而不是整个数组
2021-03-17 06:19:24
@Oleg是编写需要arr[]formData.append('arr[]', arr[i]);为什么不arr正确?我两个都试过,但都arr[]有效。
2021-03-23 06:19:24
@Totoro 是的,你说得对,我错了。我相信这是更多特定于服务器端的问题。不同的语言可能会以不同的方式解析查询字符串。例如,PHP 的行为与您描述的一样,但我看到了一些示例(如果没有记错的话,在 Java 中),其中arr也适用于数组。这个主题中有这个问题的更详细的答案
2021-03-29 06:19:24
@Oleg 如果是重新定义,那么 有什么不同arr[],为什么不arr[]重新定义?arr[]也是一个字符串。并且在我的情况下arr没有测试也没有arr[]重新定义。我在 FormData 中得到了多个具有相同键但不同值的数组。所以我得到arr了value1,另一个arr有value2
2021-03-31 06:19:24
如果有人想发布一组对象,您可以按如下方式扩展此答案 for (var i = 0; i < myArr; i++) { var myItemInArr = myArr[i]; for (var prop in myItemInArr) { fileData.append(`myArr[${i}][${prop}]`, myItemInArr[prop]); } }
2021-04-09 06:19:24

您有多种选择:

将其转换为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']);
我更喜欢字符串化,更简单。因为您需要进行某种递归以使用 [] 传递数组数组,但很高兴知道可以通过这种方式完成。
2021-03-23 06:19:24
如果您将 asp.net 与自动映射或类似的东西一起使用,那么@Curious 答案就是您所需要的。
2021-03-27 06:19:24
问题是数组包含真实文本行,带有空格和标点符号。我不想搞砸。
2021-03-31 06:19:24
当您使用 JSON 对其进行编码和解析时,数据不会丢失。试一试 ;)
2021-04-03 06:19:24
@Richard de Wit 如果您有 File 或 FormData 等数据,您将在 json.stringfy 中丢失它们
2021-04-05 06:19:24

typescript版本:

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 staticfunction+删除类型声明: any: FormData: FormData
2021-03-20 06:19:24
截至目前,该函数会跳过零和空字符串。要包含它们,请将第if7 行替换为if (!model.hasOwnProperty(propertyName) || (!model[propertyName] && model[propertyName]!==0 && model[propertyName]!=='')) continue;
2021-03-20 06:19:24

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

下面的函数将遍历一个对象并创建正确的 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
这对我很有用,只需要在 append 内部的值上应用 String(value) (否则它会因真/假而失败)。它也应该(value !== null) && formData.append(key, value)而不是仅仅formData.append(key, value)否则它在空值上失败
2021-03-17 06:19:24

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