JS Nesnesini form verilerine dönüştürün


128

JS Objectimi nasıl dönüştürebilirim FormData?

Bunu yapmak istememin nedeni, ~ 100 form alanı değerlerinden oluşturduğum bir nesnem var.

var item = {
   description: 'Some Item',
   price : '0.00',
   srate : '0.00',
   color : 'red',
   ...
   ...
}

Şimdi formuma dosya yükleme işlevini eklemem isteniyor ki bu tabii ki JSON aracılığıyla imkansız ve bu yüzden 'e geçmeyi planlıyorum FormData. Öyleyse JS nesnemi dönüştürebilmemin bir yolu var FormDatamı?


çalışmalarınızı / ilerlemenizi paylaşır mısınız?
Ritikesh

JSON.stringify () nasıl olur?
Sunny Sharma

1
@Sunny - Bu, bir dizede JSON metni üretecek. Bu bir FormDatanesne değil .
Quentin

Evet yapabilirsiniz, formData nesnelerine ekleyebilirsiniz.
adeneo

FormData ile ne demek istediğinizi bize gösterebilir misiniz? herhangi belirli bir format?
Sunny Sharma

Yanıtlar:


154

Bir nesneniz varsa, kolayca bir FormData nesnesi oluşturabilir ve bu nesnedeki adları ve değerleri formData'ya ekleyebilirsiniz.

Herhangi bir kod göndermediniz, bu nedenle bu genel bir örnek;

var form_data = new FormData();

for ( var key in item ) {
    form_data.append(key, item[key]);
}

$.ajax({
    url         : 'http://example.com/upload.php',
    data        : form_data,
    processData : false,
    contentType : false,
    type: 'POST'
}).done(function(data){
    // do stuff
});

MDN ile ilgili belgelerde daha fazla örnek var


4
@Lior - itemOP tarafından oluşturulan normal bir nesnedir, bu nedenle birisi Object yapıcısına bir şeyin prototipini oluşturma hatası yapmadıkça, kendi olmayan herhangi bir özelliğe sahip olmamalıdır, bu durumda bir sorun dünyasında olursunuz ve bu korumamız gereken bir şey değil.
adeneo

2
@Lior - sadece anahtar / değer çiftlerini FormData'ya eklemek, prototipli bir özellik eklemek hiçbir şeyi bozmaz Object.keysve anahtarları bir dizi olarak almanız gerekmediğinden, kullanmak bir cevap değildir, sonra almak için anahtarlar üzerinde yineleyin değerler, bir for..indöngü kullanmalısınız .
adeneo

2
Elbette, sunucunun ne beklediğini bilmiyorsunuz ... çünkü ... JS'de sorunlu, çözüm Object.keys () olmak zorunda değil, hasOwnProperty () olabilir, ancak en azından bir uyarı olması gerekiyor.
Lior

3
@Lior - Sunucunuz bir POST isteğinde bir anahtar / değer çifti daha aldığında bozulursa, yanlış yapıyorsunuz demektir. Cevabın iyi olduğunu düşünüyorum ve kullanmak için Object.keysveya hasOwnProperty()nesne soruda gönderildiği için değiştirmeyeceğim ve bunlardan herhangi birine ihtiyaç duymayacağım. Bazen hasOwnPropertyeklentilerde vb. Kullanıldığını görmenizin nedeni , bazı kişilerin kurucuya ne yapabileceğini asla bilememenizdir Object, ancak çoğu zaman, insanların oluşturdukları nesnelerde miras alınan özellikleri test etmek zorunda kalmaması gerekir, bu bir işarettir. muhtemelen yanlış bir şey yapıyorsun.
adeneo

5
@Lior, gökten yiyecekleri düşürecek daha gerçek uçakları çekeceğini umarak daha sonra samandan uçaklar yapmayı düşünüyor musunuz? Bir hasOwnProperty kontrolünün neden kullanıldığını anlamak önemlidir , sadece bazı şeylerin "en iyi uygulama" olarak kabul edildiğini söylemek önemlidir, çünkü birisinin kitabını (tahmin etmek, Crockford'un) kitabını okumak sizi çok uzağa götürmez, bir So üyesini 100'den fazla kez eğitmeye çalışın itibarınız ve aldığınız cevapların 100 katı sayınız da amacınıza pek yardımcı olmuyor. Ayrıca, isim tek prototip değiştirir yeni bir üçüncü parti lib? Bu gönderi farklı bir zamandan ...
Benjamin Gruenbaum

84

ES6 ve daha işlevsel bir programlama yaklaşımı ile @ adeneo'nun cevabı şöyle görünebilir:

function getFormData(object) {
    const formData = new FormData();
    Object.keys(object).forEach(key => formData.append(key, object[key]));
    return formData;
}

Ve alternatif olarak .reduce()ve ok işlevlerini kullanarak :

getFormData = object => Object.keys(object).reduce((formData, key) => {
    formData.append(key, object[key]);
    return formData;
}, new FormData());

44

Bu işlev, nesneden tüm verileri FormData'ya ekler

@ Developer033'ten ES6 sürümü:

function buildFormData(formData, data, parentKey) {
  if (data && typeof data === 'object' && !(data instanceof Date) && !(data instanceof File)) {
    Object.keys(data).forEach(key => {
      buildFormData(formData, data[key], parentKey ? `${parentKey}[${key}]` : key);
    });
  } else {
    const value = data == null ? '' : data;

    formData.append(parentKey, value);
  }
}

function jsonToFormData(data) {
  const formData = new FormData();

  buildFormData(formData, data);

  return formData;
}

const my_data = {
  num: 1,
  falseBool: false,
  trueBool: true,
  empty: '',
  und: undefined,
  nullable: null,
  date: new Date(),
  name: 'str',
  another_object: {
    name: 'my_name',
    value: 'whatever'
  },
  array: [
    {
      key1: {
        name: 'key1'
      }
    }
  ]
};

jsonToFormData(my_data)

jQuery sürümü:

function appendFormdata(FormData, data, name){
    name = name || '';
    if (typeof data === 'object'){
        $.each(data, function(index, value){
            if (name == ''){
                appendFormdata(FormData, value, index);
            } else {
                appendFormdata(FormData, value, name + '['+index+']');
            }
        })
    } else {
        FormData.append(name, data);
    }
}


var formData = new FormData(),
    your_object = {
        name: 'test object',
        another_object: {
            name: 'and other objects',
            value: 'whatever'
        }
    };
appendFormdata(formData, your_object);

Güzel devam et
Vivek Doshi

Çok iyi çalışıyor! Teşekkür ederim! && !(data instanceof Blob)Resimlerimi yüklemek için
durumuma

Benim için iyi çalışıyor, if (typeof data === 'nesne' && data! == null) {çünkü değer null ise istisna atıyordu
al000y

ES6 sürümü && !(Array.isArray(data) && !data.length)için "eğer" durumuna ekledim , yoksa boş dizi kaldırılacaktı.
Mtxz

15

Diğer cevaplar benim için eksikti. @Vladimir Novopashin cevabından başladım ve değiştirdim. İşte ihtiyacım olan ve bulduğum hatalar:

  • Dosya desteği
  • Dizi desteği
  • Hata: Karmaşık nesnelerin içindeki dosyanın .propyerine eklenmesi gerekiyor [prop]. Örneğin formData.append('photos[0][file]', file), çalışırken google chrome'da formData.append('photos[0].file', file)çalışmadı
  • Nesnemdeki bazı özellikleri yok say

Aşağıdaki kod, IE11 ve her zaman yeşil tarayıcılarda çalışmalıdır.

function objectToFormData(obj, rootName, ignoreList) {
    var formData = new FormData();

    function appendFormData(data, root) {
        if (!ignore(root)) {
            root = root || '';
            if (data instanceof File) {
                formData.append(root, data);
            } else if (Array.isArray(data)) {
                for (var i = 0; i < data.length; i++) {
                    appendFormData(data[i], root + '[' + i + ']');
                }
            } else if (typeof data === 'object' && data) {
                for (var key in data) {
                    if (data.hasOwnProperty(key)) {
                        if (root === '') {
                            appendFormData(data[key], key);
                        } else {
                            appendFormData(data[key], root + '.' + key);
                        }
                    }
                }
            } else {
                if (data !== null && typeof data !== 'undefined') {
                    formData.append(root, data);
                }
            }
        }
    }

    function ignore(root){
        return Array.isArray(ignoreList)
            && ignoreList.some(function(x) { return x === root; });
    }

    appendFormData(obj, rootName);

    return formData;
}

2
Dizileri, nesneleri ve dosyaları destekleyen tek cevap.
SOTN

Merhaba, Dosyayı neden köke ekliyorsunuz? Çocuğa da eklemek mümkün mü?
Cedric Arnould

@CedricArnould Bir yanlış anlaşılma olabilir, ancak yöntem özyinelemelidir, bu nedenle yazılsa bile formData.append(root, data), köke eklendiği anlamına gelmez.
Gudradain

Cevabınızı anlıyorum, garip bir şekilde sonucu sunucuda aldığımda, benzersiz bir Dosya ve veri Koleksiyonum var. Ama bir dosyada, adın hangi çocuğa bağlı olduğu bilgisini verdiğini görebiliyorum. Belki de sorun .Net Core'dan ve yükleme dosyalarını nasıl yönettiğinden kaynaklanmaktadır. Cevabınız için teşekkürler.
Cedric Arnould

bunu kullanmaya çalışıyorum ama kullanım örneği yok. ignoreList parametresinin beklenen biçimi oldukça yardımcı olacaktır.
jpro

9

JSON.stringify işlevini aşağıdaki gibi deneyin

var postData = JSON.stringify(item);
var formData = new FormData();
formData.append("postData",postData );

1
Bunu başarmanın en iyi yolu budur.
Rob

hata ayıklamadan birkaç kez sonra json'u ekler
Snow Bases

7

Sunucu değerleri böyle beklediğinden, form verileri oluşturulurken yuvalanmış JSON'un doğrusal bir şekilde serileştirilmesi gereken bir senaryom vardı. Bu yüzden, JSON'u şu şekilde çeviren küçük bir özyinelemeli fonksiyon yazdım:

{
   "orderPrice":"11",
   "cardNumber":"************1234",
   "id":"8796191359018",
   "accountHolderName":"Raj Pawan",
   "expiryMonth":"02",
   "expiryYear":"2019",
   "issueNumber":null,
   "billingAddress":{
      "city":"Wonderland",
      "code":"8796682911767",
      "firstname":"Raj Pawan",
      "lastname":"Gumdal",
      "line1":"Addr Line 1",
      "line2":null,
      "state":"US-AS",
      "region":{
         "isocode":"US-AS"
      },
      "zip":"76767-6776"
   }
}

Bunun gibi bir şeye:

{
   "orderPrice":"11",
   "cardNumber":"************1234",
   "id":"8796191359018",
   "accountHolderName":"Raj Pawan",
   "expiryMonth":"02",
   "expiryYear":"2019",
   "issueNumber":null,
   "billingAddress.city":"Wonderland",
   "billingAddress.code":"8796682911767",
   "billingAddress.firstname":"Raj Pawan",
   "billingAddress.lastname":"Gumdal",
   "billingAddress.line1":"Addr Line 1",
   "billingAddress.line2":null,
   "billingAddress.state":"US-AS",
   "billingAddress.region.isocode":"US-AS",
   "billingAddress.zip":"76767-6776"
}

Sunucu, bu dönüştürülmüş biçimdeki form verilerini kabul eder.

İşte fonksiyon:

function jsonToFormData (inJSON, inTestJSON, inFormData, parentKey) {
    // http://stackoverflow.com/a/22783314/260665
    // Raj: Converts any nested JSON to formData.
    var form_data = inFormData || new FormData();
    var testJSON = inTestJSON || {};
    for ( var key in inJSON ) {
        // 1. If it is a recursion, then key has to be constructed like "parent.child" where parent JSON contains a child JSON
        // 2. Perform append data only if the value for key is not a JSON, recurse otherwise!
        var constructedKey = key;
        if (parentKey) {
            constructedKey = parentKey + "." + key;
        }

        var value = inJSON[key];
        if (value && value.constructor === {}.constructor) {
            // This is a JSON, we now need to recurse!
            jsonToFormData (value, testJSON, form_data, constructedKey);
        } else {
            form_data.append(constructedKey, inJSON[key]);
            testJSON[constructedKey] = inJSON[key];
        }
    }
    return form_data;
}

çağırma:

        var testJSON = {};
        var form_data = jsonToFormData (jsonForPost, testJSON);

Form_data içeriğini ayıklayamayacağım için testJSON'u sadece dönüştürülen sonuçları görmek için kullanıyorum. AJAX görüşme sonrası:

        $.ajax({
            type: "POST",
            url: somePostURL,
            data: form_data,
            processData : false,
            contentType : false,
            success: function (data) {
            },
            error: function (e) {
            }
        });

Merhaba Raj, dizilere ne dersin? 1'den fazla fatura adresiniz olduğunu varsayalım. Bunu nasıl düzeltirsin?
Sam

1
Cevabı buldum! Gönderiniz gerçekten yardımcı oluyor. Teşekkürler!
Sam

3

Geç yanıt için özür dilerim, ancak Angular 2 şu anda dosya yüklemeyi desteklemediği için bununla uğraşıyordum. Yani, bunu yapmanın yolu bir XMLHttpRequestile göndermekti FormData. Ben de bunu yapmak için bir fonksiyon yarattım. Typescript kullanıyorum . Javascript'e dönüştürmek için veri türleri bildirimini kaldırmanız yeterlidir.

/**
     * Transforms the json data into form data.
     *
     * Example:
     *
     * Input:
     * 
     * fd = new FormData();
     * dob = {
     *  name: 'phone',
     *  photos: ['myphoto.jpg', 'myotherphoto.png'],
     *  price: '615.99',
     *  color: {
     *      front: 'red',
     *      back: 'blue'
     *  },
     *  buttons: ['power', 'volup', 'voldown'],
     *  cameras: [{
     *      name: 'front',
     *      res: '5Mpx'
     *  },{
     *      name: 'back',
     *      res: '10Mpx'
     *  }]
     * };
     * Say we want to replace 'myotherphoto.png'. We'll have this 'fob'.
     * fob = {
     *  photos: [null, <File object>]
     * };
     * Say we want to wrap the object (Rails way):
     * p = 'product';
     *
     * Output:
     *
     * 'fd' object updated. Now it will have these key-values "<key>, <value>":
     *
     * product[name], phone
     * product[photos][], myphoto.jpg
     * product[photos][], <File object>
     * product[color][front], red
     * product[color][back], blue
     * product[buttons][], power
     * product[buttons][], volup
     * product[buttons][], voldown
     * product[cameras][][name], front
     * product[cameras][][res], 5Mpx
     * product[cameras][][name], back
     * product[cameras][][res], 10Mpx
     * 
     * @param {FormData}  fd  FormData object where items will be appended to.
     * @param {Object}    dob Data object where items will be read from.
     * @param {Object =   null} fob File object where items will override dob's.
     * @param {string =   ''} p Prefix. Useful for wrapping objects and necessary for internal use (as this is a recursive method).
     */
    append(fd: FormData, dob: Object, fob: Object = null, p: string = ''){
        let apnd = this.append;

        function isObj(dob, fob, p){
            if(typeof dob == "object"){
                if(!!dob && dob.constructor === Array){
                    p += '[]';
                    for(let i = 0; i < dob.length; i++){
                        let aux_fob = !!fob ? fob[i] : fob;
                        isObj(dob[i], aux_fob, p);
                    }
                } else {
                    apnd(fd, dob, fob, p);
                }
            } else {
                let value = !!fob ? fob : dob;
                fd.append(p, value);
            }
        }

        for(let prop in dob){
            let aux_p = p == '' ? prop : `${p}[${prop}]`;
            let aux_fob = !!fob ? fob[prop] : fob;
            isObj(dob[prop], aux_fob, aux_p);
        }
    }


1

TypeScript sürümü:

static convertModelToFormData(model: any, form: FormData = null, namespace = ''): FormData {
    let formData = form || new FormData();
    for (let propertyName in model) {
      if (!model.hasOwnProperty(propertyName) || model[propertyName] == undefined) continue;
      let formKey = namespace ? `${namespace}[${propertyName}]` : propertyName;
      if (model[propertyName] instanceof Date) {        
        formData.append(formKey, this.dateTimeToString(model[propertyName]));
      }
      else if (model[propertyName] instanceof Array) {
        model[propertyName].forEach((element, index) => {
          if (typeof element != 'object')
            formData.append(`${formKey}[]`, element);
          else {
            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;
  }

https://gist.github.com/Mds92/091828ea857cc556db2ca0f991fee9f6


1
Her şeyden önce, ( typescriptlang.org/docs/handbook/namespaces.html ve github.com/Microsoft/TypeScript/issues/… ) namespaceiçinde ayrılmış bir anahtar kelimedir . Ayrıca, sen başa unuttum görünüyor son beri irade için . TypeScriptFileelseappend "[object File]"formData
Jyrkka

1

Basitçe kurabilirsiniz qs:

npm i qs

Basitçe içe aktarın:

import qs from 'qs'

Nesneyi şuraya iletin qs.stringify():

var item = {
   description: 'Some Item',
   price : '0.00',
   srate : '0.00',
   color : 'red',
   ...
   ...
}

qs.stringify(item)

1

Tekrarlı

const toFormData = (f => f(f))(h => f => f(x => h(h)(f)(x)))(f => fd => pk => d => {
  if (d instanceof Object) {
    Object.keys(d).forEach(k => {
      const v = d[k]
      if (pk) k = `${pk}[${k}]`
      if (v instanceof Object && !(v instanceof Date) && !(v instanceof File)) {
        return f(fd)(k)(v)
      } else {
        fd.append(k, v)
      }
    })
  }
  return fd
})(new FormData())()

let data = {
  name: 'John',
  age: 30,
  colors: ['red', 'green', 'blue'],
  children: [
    { name: 'Max', age: 3 },
    { name: 'Madonna', age: 10 }
  ]
}
console.log('data', data)
document.getElementById("data").insertAdjacentHTML('beforeend', JSON.stringify(data))

let formData = toFormData(data)

for (let key of formData.keys()) {
  console.log(key, formData.getAll(key).join(','))
  document.getElementById("item").insertAdjacentHTML('beforeend', `<li>${key} = ${formData.getAll(key).join(',')}</li>`)
}
<p id="data"></p>
<ul id="item"></ul>


en iyi cevap imho
ling

0

Bu yöntem, bir JS nesnesini FormData'ya dönüştürür:

function convertToFormData(params) {
    return Object.entries(params)
        .reduce((acc, [key, value]) => {
            if (Array.isArray(value)) {
                value.forEach((v, k) => acc.append(`${key}[${k}]`, value));
            } else if (typeof value === 'object' && !(value instanceof File) && !(value instanceof Date)) {
                Object.entries(value).forEach((v, k) => acc.append(`${key}[${k}]`, value));
            } else {
                acc.append(key, value);
            }

            return acc;
        }, new FormData());
}


Sadece iç içe geçmiş nesne girişleri çağrısını düzeltin: Object.entries(value).forEach((v, k) => acc.append(`${key}[${v[0]}]`, v[1]));
heber gentilin

0

Benim durumumda, nesnemin dosya dizisi olan özelliği de vardı. İkili olduklarından farklı şekilde ele alınmaları gerekir - dizinin anahtarın bir parçası olması gerekmez. Bu yüzden @Vladimir Novopashin'in ve @ developer033'ün cevabını değiştirdim:

export function convertToFormData(data, formData, parentKey) {
  if(data === null || data === undefined) return null;

  formData = formData || new FormData();

  if (typeof data === 'object' && !(data instanceof Date) && !(data instanceof File)) {
    Object.keys(data).forEach(key => 
      convertToFormData(data[key], formData, (!parentKey ? key : (data[key] instanceof File ? parentKey : `${parentKey}[${key}]`)))
    );
  } else {
    formData.append(parentKey, data);
  }

  return formData;
}

0

Bunu, nesne verilerimi Form Verileri olarak göndermek için kullandım.

const encodeData = require('querystring');

const object = {type: 'Authorization', username: 'test', password: '123456'};

console.log(object);
console.log(encodeData.stringify(object));

0

Belki bunu arıyorsunuz, javascript nesnenizi alan, ondan bir FormData nesnesi oluşturan ve ardından yeni Getirme API'sini kullanarak sunucunuza POST gönderen bir kod :

    let myJsObj = {'someIndex': 'a value'};

    let datos = new FormData();
    for (let i in myJsObj){
        datos.append( i, myJsObj[i] );
    }

    fetch('your.php', {
        method: 'POST',
        body: datos
    }).then(response => response.json())
        .then(objson => {
            console.log('Success:', objson);
        })
        .catch((error) => {
            console.error('Error:', error);
        });

0

Buna Gudradain'in cevabından referans veriyorum . Typecript formatında biraz düzenledim.

class UtilityService {
    private appendFormData(formData, data, rootName) {

        let root = rootName || '';
        if (data instanceof File) {
            formData.append(root, data);
        } else if (Array.isArray(data)) {
            for (var i = 0; i < data.length; i++) {
                this.appendFormData(formData, data[i], root + '[' + i + ']');
            }
        } else if (typeof data === 'object' && data) {
            for (var key in data) {
                if (data.hasOwnProperty(key)) {
                    if (root === '') {
                        this.appendFormData(formData, data[key], key);
                    } else {
                        this.appendFormData(formData, data[key], root + '.' + key);
                    }
                }
            }
        } else {
            if (data !== null && typeof data !== 'undefined') {
                formData.append(root, data);
            }
        }
    }

    getFormDataFromObj(data) {
        var formData = new FormData();

        this.appendFormData(formData, data, '');

        return formData;
    }
}

export let UtilityMan = new UtilityService();

0

Partiye biraz geç kalmış olabilirim ama tekil bir nesneyi FormData'ya dönüştürmek için yarattığım şey bu.

function formData(formData, filesIgnore = []) {
  let data = new FormData();

  let files = filesIgnore;

  Object.entries(formData).forEach(([key, value]) => {
    if (typeof value === 'object' && !files.includes(key)) {
      data.append(key, JSON.stringify(value) || null);
    } else if (files.includes(key)) {
      data.append(key, value[0] || null);
    } else {
      data.append(key, value || null);
    }
  })

  return data;
}

O nasıl çalışır? Yok sayma listesinde ayarladığınız Dosya nesnelerini (2. argüman. Biri bunu belirlemenin daha iyi bir yolunu söylerse bu yardımcı olur!) Kullanarak bir json dizesine dönüştürür ve döndürür JSON.stringify. Ardından sunucunuzda, onu tekrar bir JSON nesnesine dönüştürmeniz gerekecek.

Misal:

let form = {
  first_name: 'John',
  last_name: 'Doe',
  details: {
    phone_number: 1234 5678 910,
    address: '123 Some Street',
  },
  profile_picture: [object FileList] // set by your form file input. Currently only support 1 file per property.
}

function submit() {
  let data = formData(form, ['profile_picture']);

  axios.post('/url', data).then(res => {
    console.log('object uploaded');
  })
}

Http istekleri ve JavaScript konusunda hala yeniyim, bu nedenle herhangi bir geri bildirim çok takdir edilecektir!


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.