39

I realize that fundamentally I'm probably going about this the wrong way so I'm open to any pushes in the right direction.

I'm trying to use the HipChat API to send a notification to a room like so:

https://www.hipchat.com/docs/api/method/rooms/message

I'm trying to build the URL in the example with a js object's parameters, so basically I'm trying to convert this:

var hipChatSettings = {
            format:"json",
            auth_token:token,
            room_id: 1,
            from: "Notifications",
            message: "Message"
        }

To this:

https://api.hipchat.com/v1/rooms/message?format=json&auth_token=token&room_id=1&from=Notifications&message=Message

maček
  • 76,434
  • 37
  • 167
  • 198
user2865446
  • 633
  • 1
  • 6
  • 10
  • Possible duplicate of [How to serialize an Object into a list of parameters?](https://stackoverflow.com/questions/6566456/how-to-serialize-an-object-into-a-list-of-parameters) – Koen. Jan 10 '18 at 23:30

5 Answers5

51

You should check this jQuery.param function.

var params = { width:1680, height:1050 };
var str = jQuery.param( params );
console.log(str);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Alec Rust
  • 10,532
  • 12
  • 48
  • 63
Mithun Satheesh
  • 27,240
  • 14
  • 77
  • 101
  • (I should have stated I was using jQuery but you oobviously read my mind) :) – user2865446 Mar 27 '14 at 05:39
  • 13
    He didn't read your mind. Just that on Stack Overflow when you ask something about JavaScript, you will get ninety jQuery answers, even if you explicitly say you don't want jQuery answers. Remember this in the future when you want a non-jQuery JavaScript answer. ;) – L0j1k Jan 12 '15 at 06:50
  • @L0j1k You are right, but jQuery answers can be useful for other people coming here from google even when they are useless for OP. So I think it is good fashion. – Vadim Ovchinnikov May 08 '18 at 17:01
  • He didn't read your mind. He looked at your key words. So this escaped my usual downvote for such a practice. – Adrian Bartholomew Jul 20 '19 at 12:11
  • @AdrianBartholomew I assume by "key words" you mean the tags, but the jQuery tag wasn't added until after this answer was posted – Elezar Aug 23 '23 at 22:21
  • Well I didnt calculate the timeline but … not in the mood to downvote :-) – Adrian Bartholomew Aug 24 '23 at 23:08
46
Object.keys(hipChatSettings).map(function(k) {
    return encodeURIComponent(k) + "=" + encodeURIComponent(hipChatSettings[k]);
}).join('&')
// => "format=json&auth_token=token&room_id=1&from=Notifications&message=Message"

Warning: newish JavaScript. If you want it to work on ancients, shim or rewrite into for.

Amadan
  • 191,408
  • 23
  • 240
  • 301
13

Something like this could work for you

var str = "?" + Object.keys(hipChatSettings).map(function(prop) {
  return [prop, hipChatSettings[prop]].map(encodeURIComponent).join("=");
}).join("&");

// "?format=json&auth_token=token&room_id=1&from=Notifications&message=Message"

If you can't depend on ECMAScript 5, you can use a simple for loop

var pairs = [];

for (var prop in hipChatSettings) {
  if (hipChatSettings.hasOwnProperty(prop)) {
    var k = encodeURIComponent(prop),
        v = encodeURIComponent(hipChatSettings[prop]);
    pairs.push( k + "=" + v);
  }
}

var str = "?" + pairs.join("&");
maček
  • 76,434
  • 37
  • 167
  • 198
  • 2
    I like this answer. For ES6 you can tweak a bit further to `function makeParams(params) => { return params ? '?' + Object.keys(params).map((key) => ([key, params[key]].map(encodeURIComponent).join("="))).join("&") : '' }` which you can just append onto your path, `path + makeParams(params)` and it handles undefined, null and `{}` – jlyonsmith Jul 22 '17 at 04:08
4

ES6 version, can do really nested objects with arrays

encodeURI(getUrlString({a: 1, b: [true, 12.3, "string"]}))

getUrlString (params, keys = [], isArray = false) {
  const p = Object.keys(params).map(key => {
    let val = params[key]

    if ("[object Object]" === Object.prototype.toString.call(val) || Array.isArray(val)) {
      if (Array.isArray(params)) {
        keys.push("")
      } else {
        keys.push(key)
      }
      return getUrlString(val, keys, Array.isArray(val))
    } else {
      let tKey = key

      if (keys.length > 0) {
        const tKeys = isArray ? keys : [...keys, key]
        tKey = tKeys.reduce((str, k) => { return "" === str ? k : `${str}[${k}]` }, "")
      }
      if (isArray) {
        return `${ tKey }[]=${ val }`
      } else {
        return `${ tKey }=${ val }`
      }

    }
  }).join('&')

  keys.pop()
  return p
}
Boris Barroso
  • 1,802
  • 2
  • 22
  • 41
  • actually only this answer works for multi level nested objects/arrays, except jQuery one, but jQuery lib is too big if used only for this single purpose – Titenis Jun 17 '19 at 12:45
  • Works great with nested objects, this is the best I found, I only added encodeURIComponent(val). – Juan Angel Jul 26 '19 at 13:18
4

Late to the dance but I quite enjoyed the brevity of this:

  Object.entries(hipChatSettings)
    .map(
      ([key, val]) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`
    )
    .join("&");
Adrian Bartholomew
  • 2,506
  • 6
  • 29
  • 37