ผนวกอาร์เรย์เข้ากับ FormData และส่งผ่าน AJAX


110

ฉันใช้ 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 แต่ฉันก็ไม่สามารถส่งไฟล์ได้เช่นกัน

วิธีแก้ปัญหาใด ๆ

คำตอบ:


93

คุณมีหลายทางเลือก:

แปลงเป็นสตริง 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
ปัญหาคืออาร์เรย์มีบรรทัดของข้อความจริงพร้อมช่องว่างและเครื่องหมายวรรคตอน ฉันไม่อยากยุ่งกับมัน
shultz

3
เมื่อคุณเข้ารหัสและแยกวิเคราะห์ด้วย JSON ข้อมูลจะไม่สูญหาย ลองดูสิ;)
Richard de Wit

หากคุณใช้ asp.net กับการทำแผนที่อัตโนมัติหรือสิ่งที่คล้ายกันคำตอบ @Curious คือสิ่งที่คุณต้องการ
Martín Coll

1
@Richard de Wit หากคุณมีข้อมูลเช่นไฟล์หรือ FormData คุณจะสูญเสียข้อมูลเหล่านี้ใน json.stringfy
Mohsen

ฉันชอบสตริงที่ดีกว่าง่ายกว่า ในขณะที่คุณต้องทำการเรียกซ้ำบางอย่างเพื่อส่งอาร์เรย์อาร์เรย์โดยใช้ [] แต่ควรรู้ว่าสามารถทำได้ด้วยวิธีนั้น
Chopnut

261

คุณยังสามารถส่งอาร์เรย์ด้วย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

@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]); } }
edqwerty

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

มันมีประโยชน์สำหรับฉันเพียงแค่ต้องใช้ String (value) กับค่าภายในผนวก (มิฉะนั้นจะล้มเหลวสำหรับ true / false) นอกจากนี้ควรเป็นอย่างอื่น(value !== null) && formData.append(key, value)แทนที่จะformData.append(key, value)ล้มเหลวในค่า null
Alexander

7

รุ่น 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);

งานดีมีประโยชน์สุด ๆ : D
Cosimo Chellini

3

เพิ่มอินพุตประเภททั้งหมดใน 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

เวอร์ชันถัดไปใช้ได้สำหรับรุ่นที่มี arays ของค่าง่าย:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.