aggiungendo array a FormData e inviarli tramite AJAX


109

Sto usando ajax per inviare un modulo multiparte con array, campi di testo e file.

Aggiungo ogni VAR ai dati principali in questo modo

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

quindi utilizzo la funzione ajax per inviarlo a un file PHP da memorizzare all'interno di SQL DB.

$.ajax({    
    type: "post",
    url: 'php/submittionform.php',
    cache: false,
    processData: false,
    contentType: false,
    data: data,
    success: function(request) {$('#box').html(request); }
})

Ma sul lato PHP, la arrvariabile, che è un array, appare come una stringa.

Quando non lo invio con ajax come dati del modulo ma uso l' $.POSTopzione semplice , lo ottengo come array sul lato PHP, ma non posso inviare anche i file.

qualche soluzione?

Risposte:


93

Hai diverse opzioni:

Convertirlo in una stringa JSON, quindi analizzarlo in PHP (consigliato)

JS

var json_arr = JSON.stringify(arr);

PHP

$arr = json_decode($_POST['arr']);

Oppure usa il metodo di @ Curios

Invio di un array tramite FormData.


Non consigliato: serializzare i dati con, quindi deserializzarli in PHP

JS

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

PHP

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

1
il problema è che l'array contiene righe di testo REALE, con spazi e segni di punteggiatura. Non voglio rovinare tutto.
shultz

3
Quando lo codifichi e lo analizzi con JSON, i dati non vengono persi. Fai un tentativo;)
Richard de Wit

Se utilizzi asp.net con mappatura automatica o qualcosa di simile, la risposta @Curious è ciò di cui hai bisogno.
Martín Coll

1
@Richard de Wit Se disponi di dati come File o FormData, li perderai in json.stringfy
Mohsen

Mi piacciono le stringate di più, più semplici. Poiché è necessario eseguire una sorta di ricorsione per passare un array di array usando [], ma è bene sapere che può essere fatto in questo modo.
Chopnut

260

Puoi anche inviare un array in FormDataquesto modo:

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

Quindi puoi scrivere arr[]nello stesso modo in cui lo fai con un semplice modulo HTML. In caso di PHP dovrebbe funzionare.

Potresti trovare utile questo articolo: come passare un array all'interno di una stringa di query?


1
@Oleg Qual è la necessità di scrivere arr[]in formData.append('arr[]', arr[i]);? perché non è arrcorretto? Ho provato entrambi ma hanno arr[]funzionato.
Totoro

@Totoro perché nel caso in cui arrtu ridefinisci questo valore su ogni iterazione del ciclo, e alla fine, il valore finale sarà uguale all'ultimo elemento dell'array, ma non all'intero array
Oleg

@Oleg Se la ridefinizione è il caso, allora cosa c'è di diverso arr[], perché non viene arr[]ridefinito? arr[]è anche una stringa. E durante il test arrné né né è arr[]stato ridefinito nel mio caso. Ho più array in FormData con la stessa chiave ma un valore diverso. Quindi ho ottenuto arrcon valore 1e un altro arrcon valore 2.
Totoro

@Totoro si, hai ragione, errore mio. Credo che questa sia una domanda più specifica del server. Lingue diverse possono analizzare la stringa di query in modo diverso. Ad esempio, PHP si comporta come hai descritto, ma ho visto esempi (se la memoria serve, in Java), dove arrha funzionato anche per gli array. In questo argomento c'è una risposta più dettagliata a questa domanda
Oleg

Se qualcuno sta cercando di pubblicare una serie di oggetti, puoi estendere questa risposta come seguefor (var i = 0; i < myArr; i++) { var myItemInArr = myArr[i]; for (var prop in myItemInArr) { fileData.append(`myArr[${i}][${prop}]`, myItemInArr[prop]); } }
edqwerty

7

Questa è una vecchia domanda, ma recentemente mi sono imbattuto in questo problema con la pubblicazione di oggetti insieme ai file. Avevo bisogno di essere in grado di pubblicare un oggetto, con proprietà figlio che fossero anche oggetti e array.

La funzione seguente esplorerà un oggetto e creerà l'oggetto formData corretto.

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

Questo convertirà il seguente json -

{
  name: 'starwars',
  year: 1977,
  characters: {
    good: ['luke', 'leia'],
    bad: ['vader'],
  },
}

nel seguente FormData

 name, starwars
 year, 1977
 characters[good][], luke
 characters[good][], leia
 characters[bad][], vader

È stato utile per me, dovevo solo applicare String (value) sul valore all'interno di append (altrimenti fallisce per true / false). Inoltre dovrebbe essere (value !== null) && formData.append(key, value)invece che solo formData.append(key, value)altrimenti fallisce su valori nulli
Alexander

7

Versione dattiloscritto:

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

usando:

let formData = Utility.convertModelToFormData(model);

ottimo lavoro, super utile: D
Cosimo Chellini

3

aggiungere tutti gli input di tipo a 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

Se hai oggetti e array nidificati, il modo migliore per popolare l'oggetto FormData è usare la ricorsione.

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

Versione successiva valida per il modello contenente arays di valori semplici:

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

Basato sulla risposta @YackY versione di ricorsione più breve:

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

Esempio di utilizzo:

var data = {a: '1', b: 2, c: {d: '3'}};
var formData = new FormData();
createFormData(formData, 'data', data);

Dati inviati:

data[a]=1&
data[b]=2&
data[c][d]=3
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.