255

Just wondering if there is anything built-in to Javascript that can take a Form and return the query parameters, eg: "var1=value&var2=value2&arr[]=foo&arr[]=bar..."

I've been wondering this for years.

Liam
  • 27,717
  • 28
  • 128
  • 190
  • 1
    FYI: http://phpjs.org/functions/http_build_query/ –  Dec 22 '14 at 05:54
  • 2
    possible duplicate of [Create query parameters in javascript](http://stackoverflow.com/questions/111529/create-query-parameters-in-javascript) – Nerdroid Apr 22 '15 at 01:19
  • This has been an exact duplicate of http://stackoverflow.com/questions/111529/create-query-parameters-in-javascript for 7+ years, and should be closed. – Dan Dascalescu Oct 13 '22 at 08:15

22 Answers22

380

The URLSearchParams API is available in all modern browsers. For example:

const params = new URLSearchParams({
  var1: "value",
  var2: "value2",
  arr: "foo",
});
console.log(params.toString());
//Prints "var1=value&var2=value2&arr=foo"
pomber
  • 23,132
  • 10
  • 81
  • 94
Josh
  • 4,078
  • 1
  • 12
  • 7
  • 14
    Best answer here imo. Just to add to it, you can do `params.append(key, value)` later for adding new search params in more complicated scenarios. – Mingwei Zhang Nov 21 '19 at 18:02
  • 13
    Note that undefined and null values are included on the final string: `x=null&y=undefined` – pomber Feb 17 '20 at 02:18
  • 13
    Also, if you already have an URL object (for example `const url = new URL("https://stackoverflow.com")`), you can set its query strings `url.search = new URLSearchParams({foo: "bar"})` or `url.searchParams.append("foo", "bar")` – pmiguelpinto90 Jun 01 '20 at 12:13
  • 2
    Note that TS will warn about using a plain object, but it works fine nonetheless – Vadorequest Jun 11 '20 at 19:55
  • @pomber Any good ideas on filtering those undefined items out? – Dan Gayle Jul 16 '20 at 02:34
  • 2
    Note, it encodes entities differently than `encodeURIComponent()`: spaces here are encoded as `+` rather than `%20`. Not sure if that may be the reason of issues with some services. – Klesun Aug 11 '20 at 16:51
  • Also note that some entities such as Brackets `[]` will be %-encoded as `%5B` and `%5D` – Edgar Ortega Dec 27 '21 at 18:06
  • How are array values handled? – Kevin Wheeler Nov 07 '22 at 14:09
  • 1
    Well, when I do `console.log(new URLSearchParams({"arrayPlain": ["a","b","c"],"arrayBrackets[]": ["a","b","c"]}).toString());` I get `arrayPlain=a%2Cb%2Cc&arrayBrackets%5B%5D=a%2Cb%2Cc` which when URL decoded equals `arrayPlain=a,b,c&arrayBrackets[]=a,b,c` Not sure if this is browser/environment dependent though. – Kevin Wheeler Nov 07 '22 at 15:30
261

2k20 update: use Josh's solution with URLSearchParams.toString().

Old answer:


Without jQuery

var params = {
    parameter1: 'value_1',
    parameter2: 'value 2',
    parameter3: 'value&3' 
};

var esc = encodeURIComponent;
var query = Object.keys(params)
    .map(k => esc(k) + '=' + esc(params[k]))
    .join('&');

For browsers that don't support arrow function syntax which requires ES5, change the .map... line to

    .map(function(k) {return esc(k) + '=' + esc(params[k]);})
Klesun
  • 12,280
  • 5
  • 59
  • 52
  • 8
    Best solution I've seen yet - very clean and concise. A couple of caveats, though. 1) in the .map(), both k and params[k] should be encoded, e.g. encodeURIComponent(k) and encodeURIComponent(params[k]). 2) You are allowed to have more than one instance of a named parameter in a query string. If you want that capability, you'll have to use an array instead of an object (most applications won't want or need that). – John Deighan Mar 04 '16 at 14:13
  • 9
    3) Not all browsers will support arrow function syntax (that requires ES5). If you want to support all browsers (and encode the parts), replace the above .map() with .map(function(k) {return encodeURIComponent(k) + '=' + encodeURIComponent(params[k]);}) – John Deighan Mar 04 '16 at 14:13
  • The `&` in the third value `value&3` is not intentional, right? Or is it just there to demonstrate the encoding is working? – Taylor D. Edmiston Jul 30 '18 at 19:16
  • 1
    @user1738579 I edited the answer to also include your example for non-ES5. – Taylor D. Edmiston Jul 30 '18 at 19:42
  • If you're going the ES6 route, you can also use template strings to get rid of the concat: `.map( k => \`${esc(k)}=${esc(params[k])}\` )` – divillysausages Aug 09 '18 at 09:23
148

If you're using jQuery you might want to check out jQuery.param() http://api.jquery.com/jQuery.param/

Example:

var params = {
    parameter1: 'value1',
    parameter2: 'value2',
    parameter3: 'value3' 
};
var query = $.param(params);
console.log(query);

This will print out:

parameter1=value1&parameter2=value2&parameter3=value3
KARASZI István
  • 30,900
  • 8
  • 101
  • 128
Klemen Tusar
  • 9,261
  • 4
  • 31
  • 28
  • 14
    This is actually the correct answer! The query string for a form is `$.param($('#myform').serializeArray())`. – Jesse Mar 05 '14 at 06:26
  • 7
    @Jesse, that would be the same result as: `$('#myform').serialize()` – cleaver May 29 '14 at 17:26
  • 115
    `jQuery !== JavaScript` – gphilip Sep 03 '14 at 09:31
  • 18
    @gphilip Well that's why I started the response with "If you're using jQuery ...". Otherwise if you want to implement it in vanilla JS you can examine the implementation of `jQuery.param()` here https://github.com/jquery/jquery/blob/master/src/serialize.js :) – Klemen Tusar Oct 25 '16 at 14:23
  • 2
    Unlike my answer this one supports nested objects like `someStr=value1&someObj[a]=5&someObj[b]=6&someArr[]=1&someArr[]=2` – Klesun Oct 25 '18 at 17:23
  • How to prevent a null value from being appended in the resulting query string? – Junaid Apr 26 '21 at 10:10
  • Use an Array.prototype.filter maybe? – Klemen Tusar Apr 26 '21 at 18:15
58

This doesn't directly answer your question, but here's a generic function which will create a URL that contains query string parameters. The parameters (names and values) are safely escaped for inclusion in a URL.

function buildUrl(url, parameters){
  var qs = "";
  for(var key in parameters) {
    var value = parameters[key];
    qs += encodeURIComponent(key) + "=" + encodeURIComponent(value) + "&";
  }
  if (qs.length > 0){
    qs = qs.substring(0, qs.length-1); //chop off last "&"
    url = url + "?" + qs;
  }
  return url;
}

// example:
var url = "http://example.com/";

var parameters = {
  name: "George Washington",
  dob: "17320222"
};

console.log(buildUrl(url, parameters));
// => http://www.example.com/?name=George%20Washington&dob=17320222
Umut Sirin
  • 2,462
  • 1
  • 21
  • 31
Michael
  • 34,873
  • 17
  • 75
  • 109
37

Create an URL object and append the values to seachParameters

let stringUrl = "http://www.google.com/search";
let url = new URL(stringUrl);
let params = url.searchParams;
params.append("q", "This is seach query");

console.log(url.toString());

The output will be

http://www.google.com/search?q=This+is+seach+query
Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
Tinsae
  • 577
  • 5
  • 10
22

With jQuery you can do this by $.param

$.param({ action: 'ship', order_id: 123, fees: ['f1', 'f2'], 'label': 'a demo' })

// -> "action=ship&order_id=123&fees%5B%5D=f1&fees%5B%5D=f2&label=a+demo"
Manish Singh
  • 5,848
  • 4
  • 43
  • 31
22

ES2017 (ES8)

Making use of Object.entries(), which returns an array of object's [key, value] pairs. For example, for {a: 1, b: 2} it would return [['a', 1], ['b', 2]]. It is not supported (and won't be) only by IE.

Code:

const buildURLQuery = obj =>
      Object.entries(obj)
            .map(pair => pair.map(encodeURIComponent).join('='))
            .join('&');

Example:

buildURLQuery({name: 'John', gender: 'male'});

Result:

"name=John&gender=male"
Przemek
  • 3,855
  • 2
  • 25
  • 33
14

querystring can help.

So, you can

const querystring = require('querystring')

url += '?' + querystring.stringify(parameters)
ImLeo
  • 991
  • 10
  • 17
10

No, I don't think standard JavaScript has that built in, but Prototype JS has that function (surely most other JS frameworks have too, but I don't know them), they call it serialize.

I can reccomend Prototype JS, it works quite okay. The only drawback I've really noticed it it's size (a few hundred kb) and scope (lots of code for ajax, dom, etc.). Thus if you only want a form serializer it's overkill, and strictly speaking if you only want it's Ajax functionality (wich is mainly what I used it for) it's overkill. Unless you're careful you may find that it does a little too much "magic" (like extending every dom element it touches with Prototype JS functions just to find elements) making it slow on extreme cases.

Stein G. Strindhaug
  • 5,077
  • 2
  • 28
  • 41
  • Just wondering if there's anything built-in. Seems like there should be. I hate prototype, but I'm not holding that against you :) –  Nov 25 '08 at 09:53
  • When JavaScript was designed, Ajax was not yet discovered, therfore parsing a form just to get the querystring (that it would creati itself when submitted) probably did not make much sense. Today it does, tough... Btw, compared to script.aculo.us, prototype is *nice*. :) – Stein G. Strindhaug Nov 25 '08 at 10:34
7

If you don't want to use a library, this should cover most/all of the same form element types.

function serialize(form) {
  if (!form || !form.elements) return;

  var serial = [], i, j, first;
  var add = function (name, value) {
    serial.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
  }

  var elems = form.elements;
  for (i = 0; i < elems.length; i += 1, first = false) {
    if (elems[i].name.length > 0) { /* don't include unnamed elements */
      switch (elems[i].type) {
        case 'select-one': first = true;
        case 'select-multiple':
          for (j = 0; j < elems[i].options.length; j += 1)
            if (elems[i].options[j].selected) {
              add(elems[i].name, elems[i].options[j].value);
              if (first) break; /* stop searching for select-one */
            }
          break;
        case 'checkbox':
        case 'radio': if (!elems[i].checked) break; /* else continue */
        default: add(elems[i].name, elems[i].value); break;
      }
    }
  }

  return serial.join('&');
}
Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
  • Thanks! I was just facing the same problem as the original poster, and your function was exactly what I needed. – dagw Feb 03 '09 at 10:31
5

You can do that nowadays with FormData and URLSearchParams without the need to loop over anything.

const formData = new FormData(form);
const searchParams = new URLSearchParams(formData);
const queryString = searchParams.toString();

Older browsers will need a polyfill, though.

Björn Tantau
  • 1,564
  • 14
  • 13
5

Might be a bit redundant but the cleanest way i found which builds on some of the answers here:

const params: {
   key1: 'value1',
   key2: 'value2',
   key3: 'value3',
}

const esc = encodeURIComponent;
const query = Object.keys(params)
  .map(k => esc(k) + '=' + esc(params[k]))
  .join('&');

return fetch('my-url', {
  method: 'POST',
  headers: {'Content-Type': 'application/x-www-form-urlencoded'},
  body: query,
})

Source

David Pascoal
  • 1,431
  • 3
  • 21
  • 26
5

The UrlSearchParams API is a great suggestion, but I can't believe nobody mentioned the incredibly useful .get and .set methods. They can be used to manipulate the query string and not only they're very easy to use, they also solve a number of issues you might encounter. For example, in my case I wanted to build a query string without duplicate keys. .set solves this problem for you. Quoting from the MDN docs:

URLSearchParams.set() Sets the value associated with a given search parameter to the given value. If there are several values, the others are deleted.

Example (from MDN):

let url = new URL('https://example.com?foo=1&bar=2');
let params = new URLSearchParams(url.search);

// Add a third parameter
params.set('baz', 3);

params.toString(); // "foo=1&bar=2&baz=3"

Alternative, shorter syntax:

let url = new URL('https://example.com?foo=1&bar=2');

// Add a third parameter
url.searchParams.set('baz', 3);

url.searchParams.toString(); // "foo=1&bar=2&baz=3"
Simone
  • 20,302
  • 14
  • 79
  • 103
  • The last line should probably be `url.searchParams.toString();` – MEMark Aug 06 '22 at 10:10
  • Actually, it's still wrong. You changed `params.toString();` to `url.toString();`. In my opinion it should be `url.searchParams.toString();` (since the OP wants only the query string, not the whole URL). – MEMark Aug 08 '22 at 17:19
  • 1
    Oh, sorry, I guess I should have re-read the question! Fixed now. – Simone Aug 08 '22 at 18:25
3

I'm not entirely certain myself, I recall seeing jQuery did it to an extent, but it doesn't handle hierarchical records at all, let alone in a php friendly way.

One thing I do know for certain, is when building URLs and sticking the product into the dom, don't just use string-glue to do it, or you'll be opening yourself to a handy page breaker.

For instance, certain advertising software in-lines the version string from whatever runs your flash. This is fine when its adobes generic simple string, but however, that's very naive, and blows up in an embarrasing mess for people whom have installed Gnash, as gnash'es version string happens to contain a full blown GPL copyright licences, complete with URLs and <a href> tags. Using this in your string-glue advertiser generator, results in the page blowing open and having imbalanced HTML turning up in the dom.

The moral of the story:

   var foo = document.createElement("elementnamehere"); 
   foo.attribute = allUserSpecifiedDataConsideredDangerousHere; 
   somenode.appendChild(foo); 

Not:

   document.write("<elementnamehere attribute=\"" 
        + ilovebrokenwebsites 
        + "\">" 
        + stringdata 
        + "</elementnamehere>");

Google need to learn this trick. I tried to report the problem, they appear not to care.

Kent Fredric
  • 56,416
  • 14
  • 107
  • 150
3

You don't actually need a form to do this with Prototype. Just use Object.toQueryString function:

Object.toQueryString({ action: 'ship', order_id: 123, fees: ['f1', 'f2'], 'label': 'a demo' })

// -> 'action=ship&order_id=123&fees=f1&fees=f2&label=a%20demo'
Rimian
  • 36,864
  • 16
  • 117
  • 117
Thibaut Barrère
  • 8,845
  • 2
  • 22
  • 27
3

I know this is very late answer but works very well...

var obj = {
a:"a",
b:"b"
}

Object.entries(obj).map(([key, val])=>`${key}=${val}`).join("&");

note: object.entries will return key,values pairs

output from above line will be a=a&b=b

Hope its helps someone.

Happy Coding...

ajaykumar mp
  • 487
  • 5
  • 12
2

As Stein says, you can use the prototype javascript library from http://www.prototypejs.org. Include the JS and it is very simple then, $('formName').serialize() will return what you want!

Shyam Kumar Sundarakumar
  • 5,649
  • 13
  • 42
  • 69
2

For those of us who prefer jQuery, you would use the form plugin: http://plugins.jquery.com/project/form, which contains a formSerialize method.

Cugel
  • 349
  • 1
  • 4
1

Is is probably too late to answer your question.
I had the same question and I didn't like to keep appending strings to create a URL. So, I started using $.param as techhouse explained.
I also found a URI.js library that creates the URLs easily for you. There are several examples that will help you: URI.js Documentation.
Here is one of them:

var uri = new URI("?hello=world");
uri.setSearch("hello", "mars"); // returns the URI instance for chaining
// uri == "?hello=mars"

uri.setSearch({ foo: "bar", goodbye : ["world", "mars"] });
// uri == "?hello=mars&foo=bar&goodbye=world&goodbye=mars"

uri.setSearch("goodbye", "sun");
// uri == "?hello=mars&foo=bar&goodbye=sun"

// CAUTION: beware of arrays, the following are not quite the same
// If you're dealing with PHP, you probably want the latter…
uri.setSearch("foo", ["bar", "baz"]);
uri.setSearch("foo[]", ["bar", "baz"]);`
Community
  • 1
  • 1
SaraNa
  • 76
  • 4
1

These answers are very helpful, but i want to add another answer, that may help you build full URL. This can help you concat base url, path, hash and parameters.

var url = buildUrl('http://mywebsite.com', {
        path: 'about',
        hash: 'contact',
        queryParams: {
            'var1': 'value',
            'var2': 'value2',
            'arr[]' : 'foo'
        }
    });
    console.log(url);

You can download via npm https://www.npmjs.com/package/build-url

Demo:

;(function () {
  'use strict';

  var root = this;
  var previousBuildUrl = root.buildUrl;

  var buildUrl = function (url, options) {
    var queryString = [];
    var key;
    var builtUrl;
    var caseChange; 
    
    // 'lowerCase' parameter default = false,  
    if (options && options.lowerCase) {
        caseChange = !!options.lowerCase;
    } else {
        caseChange = false;
    }

    if (url === null) {
      builtUrl = '';
    } else if (typeof(url) === 'object') {
      builtUrl = '';
      options = url;
    } else {
      builtUrl = url;
    }

    if(builtUrl && builtUrl[builtUrl.length - 1] === '/') {
      builtUrl = builtUrl.slice(0, -1);
    } 

    if (options) {
      if (options.path) {
          var localVar = String(options.path).trim(); 
          if (caseChange) {
            localVar = localVar.toLowerCase();
          }
          if (localVar.indexOf('/') === 0) {
              builtUrl += localVar;
          } else {
            builtUrl += '/' + localVar;
          }
      }

      if (options.queryParams) {
        for (key in options.queryParams) {
          if (options.queryParams.hasOwnProperty(key) && options.queryParams[key] !== void 0) {
            var encodedParam;
            if (options.disableCSV && Array.isArray(options.queryParams[key]) && options.queryParams[key].length) {
              for(var i = 0; i < options.queryParams[key].length; i++) {
                encodedParam = encodeURIComponent(String(options.queryParams[key][i]).trim());
                queryString.push(key + '=' + encodedParam);
              }
            } else {              
              if (caseChange) {
                encodedParam = encodeURIComponent(String(options.queryParams[key]).trim().toLowerCase());
              }
              else {
                encodedParam = encodeURIComponent(String(options.queryParams[key]).trim());
              }
              queryString.push(key + '=' + encodedParam);
            }
          }
        }
        builtUrl += '?' + queryString.join('&');
      }

      if (options.hash) {
        if(caseChange)
            builtUrl += '#' + String(options.hash).trim().toLowerCase();
        else
            builtUrl += '#' + String(options.hash).trim();
      }
    } 
    return builtUrl;
  };

  buildUrl.noConflict = function () {
    root.buildUrl = previousBuildUrl;
    return buildUrl;
  };

  if (typeof(exports) !== 'undefined') {
    if (typeof(module) !== 'undefined' && module.exports) {
      exports = module.exports = buildUrl;
    }
    exports.buildUrl = buildUrl;
  } else {
    root.buildUrl = buildUrl;
  }
}).call(this);


var url = buildUrl('http://mywebsite.com', {
  path: 'about',
  hash: 'contact',
  queryParams: {
   'var1': 'value',
   'var2': 'value2',
   'arr[]' : 'foo'
  }
 });
 console.log(url);
Hien Nguyen
  • 24,551
  • 7
  • 52
  • 62
0

var params = { width:1680, height:1050 };
var str = jQuery.param( params );

console.log(str)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Mahdi Bashirpour
  • 17,147
  • 12
  • 117
  • 144
0

Remove undefined params

    urlParams = obj =>{
        const removeUndefined = JSON.parse(JSON.stringify(obj))
        const result = new URLSearchParams(removeUndefined).toString();
        return result ? `?${result}`: '';
    }
    console.log(urlParams({qwe: undefined, txt: 'asd'})) // '?txt=asd'
    console.log(urlParams({qwe: undefined})) // ''
Liam
  • 6,517
  • 7
  • 25
  • 47