Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/437.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 将数组追加到FormData并通过AJAX发送_Javascript_Ajax_Arrays_Form Data - Fatal编程技术网

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

Javascript 将数组追加到FormData并通过AJAX发送,javascript,ajax,arrays,form-data,Javascript,Ajax,Arrays,Form Data,我正在使用ajax提交一个包含数组、文本字段和文件的多部分表单 我将每个变量附加到主数据中,如下所示 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(attachme

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

我将每个变量附加到主数据中,如下所示

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);
但是在PHP端,
arr
变量(数组)显示为字符串

当我不使用ajax作为表单数据发送它,而是使用简单的
$.POST
选项时,我确实会在PHP端将其作为数组发送,但是我也不能发送文件


有什么解决办法吗

您有几种选择:

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

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

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

或使用 通过
FormData
发送数组


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

var json_arr = JSON.stringify(arr);
// Use <#> or any other delimiter you want
var serial_arr = arr.join("<#>"); 
//使用或任何其他所需的分隔符
var serial_arr=arr.join(“”);
PHP

$arr = json_decode($_POST['arr']);
$arr = explode("<#>", $_POST['arr']);
$arr=explode(“,$u 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]);
}
var formData=new formData;
var arr=['this','is','an','array'];
对于(变量i=0;i
因此,您可以使用与使用简单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'],
  },
}
进入以下表单数据

 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 answer更短的递归版本:

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
,因为我需要它也能够发送文件

utility.js

const实用程序={
convertModelToFormData(val,formData=新formData,命名空间=“”){
if((typeof val!==“未定义”)&&val!==null){
if(val instanceof Date){
append(名称空间,val.toISOString());
}else if(数组的val实例){
for(设i=0;i
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;
  }

问题在于数组包含实数文本行,带有空格和标点符号。我不想把它搞砸。当你用JSON编码和解析它时,数据不会丢失。试试看;)如果您使用asp.net进行自动映射或类似的操作,那么@好奇的答案就是您所需要的。@Richard de Wit如果您有诸如文件或表单数据之类的数据,您将在json中丢失它们。stringfyI更喜欢字符串化,更简单。因为您需要使用[]执行某种递归来传递数组数组,但很高兴知道可以这样做。这对我很有用,只需在append中的值上应用字符串(value)(否则,true/false将失败)。另外,它应该是
(value!==null)&&formData.append(key,value)
,而不仅仅是
formData.append(key,value)
,否则它在null时失败values@Oleg在
formData.append('arr[],arr[i])中写入
arr[]
需要什么?为什么arr不正确?我尝试了这两种方法,但只有
arr[]
有效。@Totoro因为在
arr
的情况下,您只需在每次循环迭代中重新定义这个值,最终的值将等于最后一个数组元素,而不是整个数组元素array@Oleg如果是重新定义,那么
arr[]
有什么不同,为什么
arr[]
重新定义
arr[]
也是一个字符串。在我的案例中,在测试
arr
arr[]
时,都没有重新定义。我在FormData中得到了多个具有相同键但不同值的数组。所以我得到了值为
1
arr
和值为
2
的另一个
arr
@Totoro是的,你是对的,我错了。我认为这是一个更具体的服务器端问题。不同的语言可能会以不同的方式解析查询字符串。例如,PHP的行为与您描述的类似,但我看到了一些示例(如果内存可用,在Java中),
arr
也适用于数组。这个问题有一个更详细的答案,如果有人想发布一个对象数组,你可以将这个答案扩展如下:
for(var i=0;i