2

I want to use JavaScript to convert an object into a query string.

For example, I want to convert:

{
    a: 'hello',
    b: {
      b1: 'my',
      b2: 'friend',
      b3: {
          c: 90
      }
    }
}

to:

?a=hello&b%5Bb1%5D=my&b%5Bb2%5D=friend&b%5Bb3%5D%5Bc%5D=90

I have found quite a few answers to this here: Flatten a javascript object to pass as querystring , but they don't seem to deal with the issue of associative arrays (or objects within objects).

I found a good answer for JQuery which works fine by using jQuery.param, but i would like an answer using either native JS or Underscore.js.

How can I do this?

Aakash
  • 21,375
  • 7
  • 100
  • 81
Yahya Uddin
  • 26,997
  • 35
  • 140
  • 231

3 Answers3

3

I highly recommend not trying to reinvent existing wheels. Your own implementation is probably going to be much less flexible and way more error-prone (have you thought about encoding the query string parameters correctly, for instance?) Instead, take a look at the query-string module.

Tobi Kremer
  • 618
  • 6
  • 22
  • What do you mean? I didn't add an implementation. I'm asking for an implementation. Also I believe that the URL I provided was encoded fine. Have a look at: http://www.freeformatter.com/url-parser-query-string-splitter.html and paste the URL and see for yourself. – Yahya Uddin Feb 08 '17 at 09:53
  • All I'm saying is that the implementation you're GOING TO BE MAKING has a high probability of ending up much worse than already existing modules which pay attention to funky edge-cases and come with proper test suites. – Tobi Kremer Feb 08 '17 at 10:01
  • Oh you mean just use a library – Yahya Uddin Feb 08 '17 at 10:02
  • Exactly! :) query-string will solve your problem in no time. It comes from a well-known developer and if you take a look at the [source](https://github.com/sindresorhus/query-string/blob/master/index.js) you'll see it's not trivial to get these things right. – Tobi Kremer Feb 08 '17 at 10:04
  • Unfortunately I can't use node_modules as I am creating an Alloy/Titanium mobile app, which doesn't easily support it. – Yahya Uddin Feb 10 '17 at 16:48
  • 1
    I have neither used Alloy nor Titanium, but if they really make it impossible/too hard to use third-party npm modules, I'd probably extract the relevant parts from the query-string module or just copy it altogether. It only has two dependencies: One brings the Object.assign method to Node-versions 4 and under (hoping you don't need this in Titanium/Alloy), and the other one (strict-uri-encode) is basically [one line of code](https://github.com/kevva/strict-uri-encode/blob/master/index.js). – Tobi Kremer Feb 14 '17 at 08:51
  • `query-string` library doesn't support [nested](https://github.com/sindresorhus/query-string#nesting) objects. – jayarjo Oct 16 '22 at 19:45
3

you can do this:

let obj = {
        a: 'hello',
        b: {
          b1: 'my',
          b2: 'friend',
          b3: {
              c: 90
          }
        }
    }

function getQueryString(obj, encode) {

      function getPathToObj(obj, path = []) {
        let result = [];

        for (let key in obj) {
          if (!obj.hasOwnProperty(key)) return;

          //deep copy
          let newPath = path.slice();
          newPath.push(key);

          let everyPath = [];
          if (typeof obj[key] === "object") {
            everyPath = getPathToObj(obj[key], newPath);
          } else {
            everyPath.push({
              path: newPath,
              val: obj[key]
            });
          }

          everyPath.map((item) => result.push(item))
        }

        return result;
      }

      function composeQueryString(paths) {
        let result = "";
        paths.map((item) => {
          let pathString = "";
          if (item.path.length > 1) {
            pathString = item.path.reduce((a, b, index) => {
              return a + '['+ b +']';
            })
          } else {
            pathString = item.path[0];
          }

          if (result) {
            pathString = "&" + pathString + '=' + item.val;
          } else {
            pathString = "?" + pathString + '=' + item.val;
          }

          result += pathString;
        });

        return result;
      }

      const str = composeQueryString(getPathToObj(obj));
      return encode === true ? encodeURI(str) : str;
    }
    console.log(getQueryString(obj, true));

get: ?a=hello&b%5Bb1%5D=my&b%5Bb2%5D=friend&b%5Bb3%5D%5Bc%5D=90

daiqingyun
  • 31
  • 1
1

With Axios you can easily achieve this:

const instance = axios.create({
  url: '/user',
  baseUrl: 'https://my-api-server'
});
const config = {
  params: {
    a: 'hello',
    b: {
      b1: 'my',
      b2: 'friend',
      b3: {
        c: 90
      }
    }
  }
}
const uri = instance.getUri(config)
document.write(uri)
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

For more information you can visit this answer.

Good Luck...

Aakash
  • 21,375
  • 7
  • 100
  • 81