Angular 4.3 – Parámetros de HttpClient params

let httpParams = new HttpParams().set('aaa', '111'); httpParams.set('bbb', '222'); 

¿Por qué esto no funciona? Solo configuró el ‘aaa’ y NO el ‘bbb’

Además, tengo un objeto {aaa: 111, bbb: 222} ¿Cómo puedo establecer todos los valores sin bucle?

ACTUALIZAR (esto parece funcionar, pero ¿cómo se puede evitar el ciclo?)

 let httpParams = new HttpParams(); Object.keys(data).forEach(function (key) { httpParams = httpParams.append(key, data[key]); }); 

Antes de 5.0.0-beta.6

 let httpParams = new HttpParams(); Object.keys(data).forEach(function (key) { httpParams = httpParams.append(key, data[key]); }); 

Desde 5.0.0-beta.6

Desde 5.0.0-beta.6 (2017-09-03) agregaron una nueva característica (aceptar mapa de objetos para HttpClient headers & params)

En el futuro, el objeto se puede pasar directamente en lugar de HttpParams.

 getCountries(data: any) { // We don't need any more these lines // let httpParams = new HttpParams(); // Object.keys(data).forEach(function (key) { // httpParams = httpParams.append(key, data[key]); // }); return this.httpClient.get("/api/countries", {params: data}) } 

HttpParams está destinado a ser inmutable. Los métodos set y append no modifican la instancia existente. En su lugar, devuelven nuevas instancias, con los cambios aplicados.

 let params = new HttpParams().set('aaa', 'A'); // now it has aaa params = params.set('bbb', 'B'); // now it has both 

Este enfoque funciona bien con el método de encadenamiento:

 const params = new HttpParams() .set('one', '1') .set('two', '2'); 

… aunque eso podría ser incómodo si necesitas envolver a alguno de ellos en condiciones.

Su bucle funciona porque está tomando una referencia a la nueva instancia devuelta. El código que publicaste que no funciona, no lo hace. Simplemente llama a set () pero no capta el resultado.

 let httpParams = new HttpParams().set('aaa', '111'); // now it has aaa httpParams.set('bbb', '222'); // result has both but is discarded 

En versiones más recientes de @angular/common/http (5.0 y superior, por lo que se ve), puede usar la clave HttpParamsOptions de HttpParamsOptions para pasar el objeto directamente:

 let httpParams = new HttpParams({ fromObject: { aaa: 111, bbb: 222 } }); 

Sin embargo, esto solo ejecuta un ciclo forEach bajo el capó :

 this.map = new Map(); Object.keys(options.fromObject).forEach(key => { const value = (options.fromObject as any)[key]; this.map !.set(key, Array.isArray(value) ? value : [value]); }); 

En cuanto a mí, encadenar los métodos set es la forma más limpia

 const params = new HttpParams() .set('aaa', '111') .set('bbb', "222"); 

Otra opción para hacerlo es:

 this.httpClient.get('path', { params: Object.entries(data).reduce( (params, [key, value]) => params.set(key, value), new HttpParams()); }); 

Usando esto puedes evitar el ciclo.

 // obj is the params object with key-value pair. // This is how you convert that to HttpParams and pass this to GET API. const params = Object.getOwnPropertyNames(obj) .reduce((p, key) => p.set(key, obj[key]), new HttpParams()); 

Además, sugiero hacer la función de HttpParams en su servicio de uso común. Entonces puede llamar a la función para convertir el objeto a HttpParams .

 /** * Convert Object to HttpParams * @param {Object} obj * @returns {HttpParams} */ toHttpParams(obj: Object): HttpParams { return Object.getOwnPropertyNames(obj) .reduce((p, key) => p.set(key, obj[key]), new HttpParams()); } 

Actualizar:

Desde 5.0.0-beta.6 (2017-09-03) agregaron una nueva característica ( aceptar mapa de objetos para HttpClient headers & params )

En el futuro, el objeto se puede pasar directamente en lugar de HttpParams.

Esta es la otra razón por la que si ha utilizado una función común como HttpParams mencionada anteriormente, puede quitarla fácilmente o hacer cambios si es necesario.

Por lo que puedo ver en la implementación en https://github.com/angular/angular/blob/master/packages/common/http/src/params.ts

Debe proporcionar valores por separado: no puede evitar su ciclo.

También hay un constructor que toma una cadena como parámetro, pero está en forma param=value&param2=value2 por lo que no hay ningún acuerdo para usted (en ambos casos terminará con el bucle de su objeto).

Siempre puede informar una solicitud de problema / función a angular, lo que recomiendo encarecidamente: https://github.com/angular/angular/issues

PD: recuerde la diferencia entre los métodos set y append 😉

2 alternativas fáciles

Sin objetos HttpParams

 let body = { params : { 'email' : emailId, 'password' : password } } this.http.post(url,body); 

Con objetos HttpParams

 let body = new HttpParams({ fromObject : { 'email' : emailId, 'password' : password } } this.http.post(url,body); 

Dado que @MaciejTreder confirmó que tenemos que buclear, aquí hay un contenedor que opcionalmente le permitirá agregar a un conjunto de parámetros predeterminados:

 function genParams(params: object, httpParams = new HttpParams()): object { Object.keys(params) .filter(key => { let v = params[key]; return (Array.isArray(v) || typeof v === 'string') ? (v.length > 0) : (v !== null && v !== undefined); }) .forEach(key => { httpParams = httpParams.set(key, params[key]); }); return { params: httpParams }; } 

Puedes usarlo así:

 const OPTIONS = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }), params: new HttpParams().set('verbose', 'true') }; let opts = Object.assign({}, OPTIONS, genParams({ id: 1 }, OPTIONS.params)); this.http.get(BASE_URL, opts); // --> ...?verbose=true&id=1 

Como la clase HTTP Params es inmutable, debe encadenar el método set:

 const params = new HttpParams() .set('aaa', '111') .set('bbb', "222");