Array an FormData anhängen und über AJAX senden

108

Ich verwende Ajax, um ein mehrteiliges Formular mit Array, Textfeldern und Dateien einzureichen.

Ich hänge jeden VAR so an die Hauptdaten an

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

dann benutze ich die Ajax-Funktion, um es an eine PHP-Datei zu senden, um es in der SQL-Datenbank zu speichern.

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

Auf der PHP-Seite wird die arrVariable, bei der es sich um ein Array handelt, als Zeichenfolge angezeigt.

Wenn ich es nicht mit Ajax als Formulardaten sende, sondern die einfache $.POSTOption verwende, bekomme ich es als Array auf der PHP-Seite, aber dann kann ich die Dateien auch nicht senden.

irgendwelche Lösungen?

shultz
quelle

Antworten:

92

Sie haben mehrere Möglichkeiten:

Konvertieren Sie es in eine JSON-Zeichenfolge und analysieren Sie es dann in PHP (empfohlen).

JS

var json_arr = JSON.stringify(arr);

PHP

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

Oder verwenden Sie die Methode von @ Curios

Senden eines Arrays über FormData.


Nicht empfohlen: Serialisieren Sie die Daten mit und deserialisieren Sie sie dann in PHP

JS

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

PHP

$arr = explode("<#>", $_POST['arr']);
Richard de Wit
quelle
1
Das Problem ist, dass das Array Zeilen mit REALEM Text mit Leerzeichen und Satzzeichen enthält. Ich will es nicht vermasseln.
Shultz
3
Wenn Sie es mit JSON codieren und analysieren, gehen keine Daten verloren. Probieren Sie es aus;)
Richard de Wit
Wenn Sie asp.net mit automatischer Zuordnung oder ähnlichem verwenden, ist die Antwort von @Curious genau das Richtige für Sie.
Martín Coll
1
@ Richard de Wit Wenn Sie Daten wie Datei oder FormData haben, verlieren Sie sie in json.stringfy
Mohsen
Ich mag es besser, einfacher zu fädeln. Da Sie eine Art Rekursion durchführen müssen, um ein Array von Arrays mit [] zu übergeben, ist es gut zu wissen, dass dies auf diese Weise möglich ist.
Chopnut
260

Sie können ein Array auch folgendermaßen senden FormData:

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

Sie können also arr[]genauso schreiben wie mit einem einfachen HTML-Formular. Im Falle von PHP sollte es funktionieren.

Dieser Artikel ist möglicherweise hilfreich: Wie übergebe ich ein Array innerhalb einer Abfragezeichenfolge?

Oleg
quelle
1
@Oleg Was ist die Notwendigkeit zu schreiben , arr[]in formData.append('arr[]', arr[i]);? warum ist das nicht arrrichtig Ich habe beides versucht, aber nur arr[]funktioniert.
Totoro
@ Motoro, weil im Falle, dass arrSie diesen Wert bei jeder Schleifeniteration neu definieren, und am Ende der endgültige Wert gleich dem letzten Array-Element, aber nicht dem gesamten Array
Oleg
@Oleg Wenn eine Neudefinition der Fall ist, was ist dann anders arr[], warum wird nicht arr[]neu definiert? arr[]ist auch eine Zeichenfolge. Und während der Prüfung beide weder arrnoch arr[]in meinem Fall neu definiert. Ich habe mehrere Arrays in FormData mit demselben Schlüssel, aber unterschiedlichem Wert. Also habe ich arrmit Wert 1und ein anderer arrmit Wert 2.
Totoro
@ Motoro ja, du hast recht, mein Fehler. Ich glaube, das ist eher eine serverseitige Frage. Verschiedene Sprachen können Abfragezeichenfolgen unterschiedlich analysieren. Zum Beispiel verhält sich PHP wie von Ihnen beschrieben, aber ich habe Beispiele gesehen (wenn Speicher dient, in Java), in denen arrauch für Arrays gearbeitet wurde. In diesem Thema gibt es eine detailliertere Antwort auf diese Frage
Oleg
Wenn jemand eine Reihe von Objekten veröffentlichen for (var i = 0; i < myArr; i++) { var myItemInArr = myArr[i]; for (var prop in myItemInArr) { fileData.append(`myArr[${i}][${prop}]`, myItemInArr[prop]); } }
möchte
7

Dies ist eine alte Frage, aber ich bin kürzlich auf dieses Problem gestoßen, als ich Objekte zusammen mit Dateien gepostet habe. Ich musste in der Lage sein, ein Objekt mit untergeordneten Eigenschaften zu veröffentlichen, die auch Objekte und Arrays waren.

Die folgende Funktion geht durch ein Objekt und erstellt das richtige formData-Objekt.

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

Dies konvertiert den folgenden json -

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

in die folgenden FormData

 name, starwars
 year, 1977
 characters[good][], luke
 characters[good][], leia
 characters[bad][], vader
VtoCorleone
quelle
Es war nützlich für mich, musste nur String (Wert) auf Wert innerhalb von Anhängen anwenden (andernfalls schlägt es für wahr / falsch fehl). Auch sollte es (value !== null) && formData.append(key, value)statt nur formData.append(key, value)sonst sein, es scheitert an Nullwerten
Alexander
7

Typoskript-Version:

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

Verwenden von:

let formData = Utility.convertModelToFormData(model);
Mohammad Dayyan
quelle
tolle Arbeit, super nützlich: D
Cosimo Chellini
2

Fügen Sie FormData alle Typeneingaben hinzu

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]) ;
}
HamidNE
quelle
2

Wenn Sie verschachtelte Objekte und Arrays haben, können Sie das FormData-Objekt am besten mithilfe der Rekursion füllen.

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
quelle
1

Nächste Version gültig für Modell mit Arays einfacher Werte:

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;
}
Megabyte
quelle
1

Basierend auf @YackY Antwort kürzere Rekursionsversion:

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

Anwendungsbeispiel:

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

Gesendete Daten:

data[a]=1&
data[b]=2&
data[c][d]=3
Dikirill
quelle