ChatGPT解决这个技术问题 Extra ChatGPT

将数组附加到 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 文件以存储在 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 端的一个数组,但是我也无法发送文件。

任何解决方案?


S
SuperDJ

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

var formData = 新的 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,它应该可以工作。

您可能会发现这篇文章很有用:How to pass an array within a query string?


@Oleg 需要在 formData.append('arr[]', arr[i]); 中写 arr[] 吗?为什么 arr 不正确?我都尝试了,但只有 arr[] 有效。
@Totoro 因为在 arr 的情况下,您只需在每次循环迭代时重新定义此值,最后,最终值将等于最后一个数组元素,而不是整个数组
@Oleg如果重新定义是这种情况,那么 arr[] 有什么不同,为什么不重新定义 arr[]arr[] 也是一个字符串。在我的情况下,在测试 arrarr[] 时都没有重新定义。我在 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]); } }
C
Community

你有几个选择:

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

问题是该数组包含真正的文本行,带有空格和标点符号。我不想搞砸了。
当您使用 JSON 对其进行编码和解析时,数据不会丢失。试试看 ;)
如果您使用带有自动映射或类似功能的 asp.net,那么 @Curious 答案就是您所需要的。
@Richard de Wit 如果您有诸如 File 或 FormData 之类的数据,您将在 json.stringfy 中丢失它们
我更喜欢stringified,更简单。因为您需要进行某种递归以使用 [] 传递数组数组,但很高兴知道可以这样做。
M
Mohammad Dayyan

打字稿版本:

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;
V
VtoCorleone

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

下面的函数将遍历一个对象并创建正确的 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) 否则它会在 null 值上失败
H
HamidNE

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

Z
Zombiesplat

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

实用程序.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);
  ...
}

M
Megabyte

下一个版本适用于包含一系列简单值的模型:

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

Y
YackY

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

d
dikirill

基于@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

m
mabdullahse

将三种格式的 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

k
kaya

我已经修复了打字稿版本。对于 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;
  }

T
Tomerikoo

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
N
Nima

就我而言,我得到了

{
    "category": [
        "Incorrect type. Expected pk value, received str."
    ]
}

错误所以

对于谁使用 React(前端)和 Django DRF(后端):


const category = [1,2,3,4,5]
formData.append("category", JSON.stringify(category));

import json
from .serializers import ArticleSerializer
from rest_framework.response import Response

class ArticleListCreateView(ListCreateAPIView):
    permission_classes = (
        IsSuperuserOrReadOnly,
        IsAutherOrReadOnly,
    )
    serializer_class = ArticleSerializer
    model = Article
    queryset = Article.objects.filter(article_honor='a', status='p')


    def create(self, request, *args, **kwargs):
        data = request.data
        article = Article('set all argumenst')
        
        image = request.data['image']
        # save image in local

        article.save()
        categorys = json.loads(data['category'])
        for catID in categorys:
            cat = Category.objects.get(id=catID)
            article.category.add(cat)

        article.save()

        return Response(ArticleSerializer(article).data)



B
Blue

简单的方法:

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

我试过了,效果很好


您的答案可以通过额外的支持信息得到改进。请edit添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。您可以找到有关如何写出好答案的更多信息in the help center
您的答案质量比其他人低得多

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅