Madhu Ranjan
Madhu Ranjan

Reputation: 17894

Passing array into URLSearchParams while consuming http call for get request

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

Can anybody help with that?

Upvotes: 88

Views: 110826

Answers (13)

Lajos Arpad
Lajos Arpad

Reputation: 76454

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... :)

Upvotes: 1

xan j
xan j

Reputation: 1

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

Upvotes: 0

Drkawashima
Drkawashima

Reputation: 9762

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());

Upvotes: -1

Waqas Ahmad
Waqas Ahmad

Reputation: 21

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;
    }
}

Upvotes: 2

Federico Vitale
Federico Vitale

Reputation: 380

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();
}

Upvotes: 0

ugate
ugate

Reputation: 101

An array of key/value pair arrays should work:

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

Upvotes: 3

Richard Oliver Bray
Richard Oliver Bray

Reputation: 1123

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()
}

Upvotes: 21

Tom B&#246;ttger
Tom B&#246;ttger

Reputation: 655

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();
}

Upvotes: 1

Thierry Templier
Thierry Templier

Reputation: 202156

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());

Upvotes: 130

Gabriel Fernandez
Gabriel Fernandez

Reputation: 383

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.

Upvotes: 7

Anton
Anton

Reputation: 51

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

Upvotes: 2

nmattise
nmattise

Reputation: 526

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')]

Upvotes: 38

Washington Braga
Washington Braga

Reputation: 1803

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

Upvotes: 5

Related Questions