Search code examples
javascriptbracketsobject-literal

Turn an object to a square bracket string (not using JSON.stringify)


I have this Javascript object (that is created on-the-fly by my plugin code):

{
   "field": {
      "name": "Name",
      "surname": "Surname"
   },
   "address": {
      "street": "Street",
      "number": 0,
      "postcode": 0,
      "geo": {
        "city": "City",
        "country": "Country",   
        "state": "State"   
      }
   },
   "options": [1,4,6,8,11]
 }

I don't want to turn this object to a JSON string, but I want to turn this object into another object, but with each field represented by a string, like this:

{
  "field[name]": "Name",
  "field[surname]": "Surname",
  "address[street]": "Street",
  "address[number]": 0,
  "address[postcode]": 0,
  "address[geo][city]": "City",
  "address[geo][country]": "Country",   
  "address[geo][state]": "State",   
  "options[0]":1,
  "options[1]":4,
  "options[2]":6,
  "options[3]":8,
  "options[4]":11
}

Scenario:

  • I dont know how the original object will look like (or how deep it'll be), since it's part of a plugin and I have no idea how people will build their forms
  • I'm going to put this new object inside a FormData object, if it would only accept objects, it would be easier, because JSON can't upload files, but FormData object can

Solution

  • As I said in the comments, you need a for...in [MDN] loop to iterate over the properties of the object and can use recursion to subsequently convert nested objects:

    function convert(obj, prefix, result) {
        result = result || {};
    
        // iterate over all properties
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                var value = obj[prop];
                // build the property name for the result object
                // first level is without square brackets
                var name = prefix ? prefix + '[' + prop + ']' : prop;
                if (typeof value !== 'object') {
                    // not an object, add value to final result
                    result[name] = value;
                }
                else {
                    // object, go deeper
                    convert(value, name, result);
                }
            }
        }
    
        return result;
    }
    
    // Usage:
    var converted_data = convert(data);
    

    DEMO

    Still, I would recommend using JSON.

    If you want to handle files as well, you might have to add an additional check for File objects. You'd want them raw in the result object:

    else if (window.File && value instanceof File) {
        result[name] = value;
    }
    
    // and for file lists
    
    else if (window.FileList && value instanceof FileList) {
        for (var i = 0, l = value.length; i < l; i++) {
            result[name + '[' + i + ']'] = value.item(i);
        }
    }
    

    It could be that the File (FileList) constructor is named differently in IE, but it should give you a start.