web-dev-qa-db-fra.com

ajout d'un tableau à FormData et envoi via AJAX

J'utilise ajax pour soumettre un formulaire en plusieurs parties avec des tableaux, des champs de texte et des fichiers.

J'ajoute chaque VAR aux données principales pour

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

j'utilise ensuite la fonction ajax pour l'envoyer dans un fichier PHP à stocker dans la base de données SQL.

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

Mais du côté PHP, la variable arr, qui est un tableau, apparaît sous forme de chaîne.

Lorsque je ne l'envoie pas avec ajax en tant que données de formulaire mais que j'utilise l'option simple $.POST, je l'obtiens sous forme de tableau du côté PHP, mais je ne peux pas envoyer les fichiers également.

des solutions? 

65
shultz

Vous avez plusieurs options:

Convertissez-le en chaîne JSON, puis analysez-le dans PHP (recommandé).

JS

var json_arr = JSON.stringify(arr);

PHP

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

Ou utilisez @ la méthode de Curios

Envoi d'un tableau via FormData.


Non recommandé: Sérialiser les données avec, puis désérialiser en PHP

JS

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

PHP

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

Vous pouvez également envoyer un tableau via FormData de cette façon:

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

Ainsi, vous pouvez écrire arr[] de la même manière qu'avec un simple formulaire HTML. Dans le cas de PHP, cela devrait fonctionner.

Vous pouvez trouver cet article utile: Comment passer un tableau dans une chaîne de requête?

187
Oleg

C'est une vieille question, mais j'ai récemment rencontré ce problème avec la publication d'objets avec des fichiers. J'avais besoin de pouvoir poster un objet, avec des propriétés enfants qui étaient aussi des objets et des tableaux. 

La fonction ci-dessous parcourt un objet et crée le bon objet 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);
      }
    });
  }
}

Cela va convertir le JSON suivant -

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

dans le FormData suivant

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

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

En utilisant:

let formData = Utility.convertModelToFormData(model);
4
Mohammad Dayyan

ajouter toutes les entrées de type à 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]) ;
}
1
HamidNE

Si vous avez des objets et des tableaux imbriqués, le meilleur moyen de renseigner un objet FormData consiste à utiliser la récursivité.

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

Basé sur @YackY, répondez à la version plus courte de la récursivité:

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

Exemple d'utilisation:

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

Données envoyées:

data[a]=1&
data[b]=2&
data[c][d]=3
0
dikirill

Version suivante valide pour les modèles contenant des tableaux de valeurs simples:

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