我怎样才能将我的JS对象转换为FormData?

我这样做的原因是,我有一个用~100个表单字段值构造的对象。

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

现在我被要求将上传文件功能添加到我的表单,当然,通过JSON是不可能的,所以我计划移动到FormData。那么有什么方法可以将我的JS对象转换为FormData呢?


当前回答

我可能有点晚了,但这就是我创建的将单个对象转换为FormData的方法。

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

它是如何工作的? 它将转换并返回所有属性,除了您在忽略列表中设置的File对象(第二个参数)。如果有人能告诉我一个更好的方法来确定这将有帮助!)变成一个json字符串使用json .stringify。然后在您的服务器上,您只需要将其转换回JSON对象。

例子:

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请求和JavaScript,所以任何反馈将高度赞赏!

其他回答

我参考了古德拉丹的回答。我用Typescript格式编辑了一下。

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

抱歉这么晚才回答,我一直在纠结这个问题,因为Angular 2目前不支持文件上传。方法是用FormData发送一个XMLHttpRequest。我创建了一个函数来做这个。我用的是Typescript。要将其转换为Javascript只需删除数据类型声明。

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

很简单,可以这样做:

var item: { some1: "ajbd" , some2: "dds".. }
let myFormData = new FormData();
      
       const abc = item.some1;
       const xyz = item.some2;

          myFormData.append('field1', abc);
          myFormData.append('field2', xyz);
    
    fetch('http:url', {
      method: 'POST',
      headers: {
        'Content-Type': false,
      },
      body: myFormData,
    }).
do promise ..

我可能有点晚了,但这就是我创建的将单个对象转换为FormData的方法。

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

它是如何工作的? 它将转换并返回所有属性,除了您在忽略列表中设置的File对象(第二个参数)。如果有人能告诉我一个更好的方法来确定这将有帮助!)变成一个json字符串使用json .stringify。然后在您的服务器上,您只需要将其转换回JSON对象。

例子:

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请求和JavaScript,所以任何反馈将高度赞赏!

其他的答案对我来说是不完整的。我从@Vladimir Novopashin的回答开始修改。以下是我需要的东西和我发现的bug:

文件支持 支持数组 Bug:复杂对象内的文件需要添加。prop而不是[prop]。例如,formData。附加('照片[0][文件]',文件)不工作在谷歌chrome,而 formData.append('照片[0]。文件',文件)工作 忽略对象中的某些属性

下面的代码应该可以在IE11和常绿浏览器上运行。

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