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


108

我正在使用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端将它作为数组获得,但是后来我也无法发送文件。

有什么办法吗?

Answers:


92

您有几种选择:

将其转换为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']);

1
问题在于数组包含带有空格和标点符号的REAL文本行。我不想弄乱它。
shultz

3
当您使用JSON进行编码和解析时,数据不会丢失。试试看;)
理查德·德·威特

如果您使用带有自动映射或类似功能的asp.net,则需要@Curious答案。
马丁科尔

1
@Richard de Wit如果您拥有诸如File或FormData之类的数据,则将在json.stringfy中丢失它们
Mohsen

我喜欢更好,更简单的字符串化。因为您需要进行某种递归才能使用[]传递数组数组,但很高兴知道可以那样做。
Chopnut

260

您也可以通过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,它应该可以工作。

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


1
@Oleg是编写需要arr[]formData.append('arr[]', arr[i]);?为什么不arr正确?我都尝试过,但只arr[]奏效。
龙猫

@Totoro,因为如果arr您只是在每次循环迭代中重新定义此值,最后,最终值将等于最后一个数组元素,但不等于整个数组
Oleg

@Oleg如果需要重新定义,则中的区别arr[]是什么,为什么不arr[]重新定义?arr[]也是一个字符串。在测试时,在我的案例中,都arr没有arr[]重新定义。我在FormData中得到了多个具有相同键但值不同的数组。所以我arr拥有价值1,另一个arr拥有价值2
龙猫

@Totoro是的,你是对的,我的错。我相信这是服务器端特定的问题。不同的语言可能会不同地解析查询字符串。例如,PHP的行为与您所描述的相同,但是我看到了一些示例(如果在Java中提供了内存),其中的示例arr也适用于数组。在本主题中该问题有更详细的答案
Oleg

如果有人希望发布对象数组,则可以按以下方式扩展此答案for (var i = 0; i < myArr; i++) { var myItemInArr = myArr[i]; for (var prop in myItemInArr) { fileData.append(`myArr[${i}][${prop}]`, myItemInArr[prop]); } }
edqwerty18

7

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

下面的函数将遍历一个对象并创建正确的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)(否则对true / false失败)。同样,它应该(value !== null) && formData.append(key, value)不是formData.append(key, value)空值失败,而不是其他的情况
亚历山大

7

打字稿版本:

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

伟大的工作,超级有用:D
Cosimo Chellini

2

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

2

如果您有嵌套的对象和数组,则填充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);
    }
}

1

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

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

1

根据@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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.