93

Going through the WebAPI documentation for URLSearchParams, I didn't find any documentation on passing array as an parameter.

Can anybody help with that?

13 Answers 13

134

In fact, you can't pass an array directly but you can use several times the append method:

let params = new URLSearchParams();
params.append('arrayparams', 'val1');
params.append('arrayparams', 'val2');
params.append('arrayparams', 'val3');
console.log(params.toString());

Sign up to request clarification or add additional context in comments.

11 Comments

No, by specification, multiple instance of the same key is automatically an array.
This is awesome, thanks! Note that you need to use params.getAll('arrayparams') in order to extract the array back out (for those accessing the parameter client side).
PHP does not see multiple instance of the same key as an array
Oneliner: [].reduce((acc, cur) => { acc.append('arrayparams', cur); return acc; }, new URLSearchParams()).toString()
simpler and short URL option: (I added an answer with this example) const url = new URL('http://localhost/') url.searchParams.append('date[0]', date1) url.searchParams.append('date[1]', date2) console.log(url.toString())
|
39

URLSearchParams can be passed a sequence of pairs, so to have an array of values:

var ids = [1,2,3,4]
var search = new URLSearchParams(ids.map(s=>['id',s]))
var searchString = search.toString()
// "id=1&id=2&id=3&id=4"
// To get the ids from the URL search string
var search_ids = [...search.getAll('id')]

1 Comment

Nice way to go, but you need to remove the toString() from search.
21

If you want to use @washington-braga's approach but don't want to install lodash:

function buildParams(data) {
    const params = new URLSearchParams()

    Object.entries(data).forEach(([key, value]) => {
        if (Array.isArray(value)) {
            value.forEach(value => params.append(key, value.toString()))
        } else {
            params.append(key, value.toString())
        }
    });

    return params.toString()
}

Comments

7

In fact this is the simplest functional way:

const url = new URL('http://localhost/')
url.searchParams.append('date[0]', date1)
url.searchParams.append('date[1]', date2)
console.log(url.toString())

For sure you can iterate through an array.

1 Comment

Example URL outout after you run decodeURIComponent on the string: http://localhost/?date[0]=1662178968266&date[1]=1662178968266' I prefer @thierry-templier's response since its more in line with browser's default behavior / spec. To have it be similar to @thierry-templier's answer all you need to do is remove the square brackets from the date string above. The browser allows multiple instance of the same key in the URL - this automatically represents an array
5

I've used Lodash map to iterate over objects/arrays and append the params dynamically.


const buildParams = (data) => {
  const params = new URLSearchParams();

  map(data, (value, key) => {
    if (Array.isArray(data[key])) {
      map(value, item => params.append(key, item));
    } else {
      params.append(key, value);
    }
  });

  return params;
};

const params = {
  foo: ['a', 'b', 'c'],
  bar: 'xyz'
}

const doFetch = fetch(`http://api.com/search?${buildParams(params)}`)

So the final URL will look like: http://api.com/search?foo=a&foo=b&foo=c&bar=xyz

Comments

3

An array of key/value pair arrays should work:

let params = new URLSearchParams([['params', 'v1'], ['params', 'v2']]).toString();
console.log(params);

Comments

3
makeSearchParams(link) {
    var url = new URL(window.location.protocol + '//' + window.location.host + link);
    const params = this.getSearchParams();

    for (let key in params) {
        if (Array.isArray(params[key])) {
            for (let key1 in params[key]) {
                url.searchParams.append(key + '[]', params[key][key1]);
            }
        } else {
            url.searchParams.append(key, params[key]);
        }

        return url;
    }
}

Comments

2
const buildParams = (search) => {
  if (!search) return "";

  const params = new URLSearchParams();

  Object.entries(search).forEach(([key, value]) => {
    if (Array.isArray(value)) params.append(key, value.join(","));
    else params.append(key, value.toString());
  });

  return `?${params}`;
};

const search = {
  types: ['good', 'bad', 'normal'],
  id: 777
}

const url = `http://good.com/${buildParams(search)}`;

As a result, you will get http://good.com/?types=good,bad,normal&id=777

Comments

2
const objectToQuery = (field, obj, prefix = null) => {
    let query = "";
    if (obj) {
        let keys = Object.keys(obj);
        keys.forEach((key) => {
            if (Array.isArray(obj[key])) {
                obj[key].forEach((e) => {
                    query += "&" + field + (prefix ?? "") + "[" + key + "]" + "[]=" + e;
                });
            } else if (typeof obj[key] === "object" && !Array.isArray(obj[key])) {
                query += objectToQuery(field, obj[key], (prefix ?? "") + "[" + key + "]");
            } else {
                query += "&" + field + (prefix ?? "") + "[" + key + "]=" + obj[key];
            }
        });
    }
    return query;
};

this will convert even complex objects to query e.g

const filter = {
  name:'sample',
  status:['open','closed'],
  attributes:{
    color:['red','blue'], 
    misc:{
      other:'someval'
    }
  }
}
const baseURL = 'http://localhost'
const query = baseURL+'?page=1'+ objectToQuery('filter',filter)
//http://localhost?page=1&filter[name]=sample
//&filter[status][]=open
//&filter[status][]=closed
//&filter[attributes][color][]=red
//&filter[attributes][color][]=blue
//&filter[attributes][misc][other]=someval

Comments

1

Here is a function that automatically appends array values as multiple entries/keys in the query string.

The difference to other solutions posted already is, that it is simpler to read and only considers arrays - without appending all other object keys again.

function convertToQueryUrl(obj: never): string {
    const params = new URLSearchParams(obj);
    for (const [key, value] of Object.entries(obj)) {
        if (Array.isArray(value)) {
            params.delete(key);
            value.forEach((v) => params.append(key, v));
        }
    }
    return params.toString();
}

Comments

1

With a simple reduce you can obtain this natively without installing any third party module

function serializeParams<T extends object>(params: T): string {
    return Object.entries(params)
        .reduce((acc, [k, v]) => {
            if (Array.isArray(v)) {
                for (const val of v) {
                    acc.append(k, val);
                }

                return acc;
            }

            acc.append(k, v);

            return acc;
        }, new URLSearchParams())
        .toString();
}

Comments

1

You cannot do it by itself, but you can use forEach or a loop to pass it:

let params = new URLSearchParams();
[2, 3, 5, 7, 11, 13, 17, 19, 'etc'].forEach(item => params.append("primes", item));
console.log(params.toString());

Or, you can even polyfill this:

    URLSearchParams.prototype.appendArray = function(array) {
        [2, 3, 5, 7, 11, 13, 17, 19, 'etc'].forEach(item => this.append("primes", item))
    }
    let params = new URLSearchParams();
    params.appendArray([2, 3, 5, 7, 11, 13, 17, 19, 'etc']);
    console.log(params.toString());

You see, I added an appendArray function to the URLSearchParams prototype, so from now on any object instantiated as a URLSearchParams object will have an appendArray function that expects an array and add append it. But, if you polyfill, make sure you polyfill before you are to use the method... :)

Comments

-2

The top answers had me thinking you couldn't pass multiple params at once, and that you had to resort to calling .append() once per param

That's not the case. You can pass an object with keys and values.

const params = new URLSearchParams({name:"Phil Collins",age:72,role:"musician"});
console.log(params.toString());

Output: name=Phil+Collins&age=72&role=musician

Or you can pass an array of keyvaluepair-arrays

const params = new URLSearchParams([["name","Phil Collins"], ["age",72], ["role","musician"]]);
console.log(params.toString());

1 Comment

This point misses the OP request about a single parameter being defined multiple times (an array). But yes, you can define singular properties as a single object then use append for the array property only.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.