Tengo varios URLSearchParams creados a partir de un objeto principalmente porque es más fácil escribir y leer, pero para algunos de ellos, necesito varios valores para una "variable" como esta: foo=bar&foo=baz .
Por ahora lo hago con .append pero es difícil de leer con varias líneas bastante idénticas.
¿Hay alguna forma de hacerlo desde el constructor, con un objeto?
let params; // Currently used (and working) code params = new URLSearchParams() params.append("foo", "bar"); params.append("foo", "baz"); console.log(params.toString()); //Wanted result but heavy to read with more values // Wanted code (but not the wanted result for now) params = new URLSearchParams({ "foo": ["bar", "baz"] }); console.log(params.toString()); params = new URLSearchParams({ "foo": "bar", "foo": "baz" }); console.log(params.toString());URLSearchParams puede tomar un valor de init como argumento para su constructor que contiene lo siguiente:
Uno de:
Una cadena, que se analizará desde el formato
application/x-www-form-urlencoded. Un'?'se ignora el carácter.Una secuencia literal de pares de cadenas de nombre y valor, o cualquier objeto, como un objeto
FormData, con un iterador que produce una secuencia de pares de cadenas. Tenga en cuenta que las entradas deFilese serializarán como[object File]en lugar de su nombre de archivo (como lo harían en unapplication/x-www-form-urlencoded).Un registro de claves de cadena y valores de cadena.
En su caso, el segundo parece funcionar mejor y se puede hacer así:
const searchParams = new URLSearchParams([['foo', 'bar'],['foo', 'baz'],['foo', 'qux']]) console.log(searchParams.toString())Si desea tratar con objetos, puede crear su propia estructura y utilizar una función para crear los datos deseados.
Por ejemplo :
const params = [ {name: "foo", values: ["bar", "baz", "qux"]}, {name: "bar", values: ["foo", "foo2", "foo3"]}, ] const initParams = (params) => params.reduce((acc, curr) => { const arr = curr.values.map(x => [curr.name, x]) return acc.concat(arr) }, []) const searchParams = new URLSearchParams(initParams(params)) console.log(searchParams.toString())Introduciría una función para crear lo que necesita ( URLSearchParams ) a partir de la estructura que desea (un objeto que contiene cadenas o matrices de cadenas), empujando los detalles "pesados" debajo de una interfaz de su propiedad. Una implementación simple simplemente usaría .append según corresponda:
// For TypeScript (eg Angular) users: // function createSearchParams(params: { [key: string]: string | string[] }): URLSearchParams { function createSearchParams(params) { const searchParams = new URLSearchParams(); Object.entries(params).forEach(([key, values]) => { if (Array.isArray(values)) { values.forEach((value) => { searchParams.append(key, value); }); } else { searchParams.append(key, values); } }); return searchParams; } console.log(createSearchParams({ foo: ["bar", "baz"], hello: "world", }).toString()); Esto proporciona una abstracción , por lo que si decide que prefiere usar el enfoque init bajo el capó, puede hacerlo, por ejemplo:
function createSearchParams(params) { return new URLSearchParams(Object.entries(params).flatMap(([key, values]) => Array.isArray(values) ? values.map((value) => [key, value]) : [[key, values]])); } console.log(createSearchParams({ foo: ["bar", "baz"], hello: "world", }).toString()); Todas sus pruebas continuarán pasando, no tiene que cambiar el código de consumo. Esto es mucho más ordenado que definir una función para convertir la estructura que desea en lo que necesita URLSearchParams , como se muestra en la respuesta de RenaudC5 .