'Angular 4.3 - HttpClient set params
let httpParams = new HttpParams().set('aaa', '111');
httpParams.set('bbb', '222');
Why this doesn't work? It only set the 'aaa' and NOT the 'bbb'
Also, I have an object { aaa: 111, bbb: 222 } How can I set all the values without looping?
UPDATE (this seems to work, but how can avoid the loop?)
let httpParams = new HttpParams();
Object.keys(data).forEach(function (key) {
httpParams = httpParams.append(key, data[key]);
});
Solution 1:[1]
Before 5.0.0-beta.6
let httpParams = new HttpParams();
Object.keys(data).forEach(function (key) {
httpParams = httpParams.append(key, data[key]);
});
Since 5.0.0-beta.6
Since 5.0.0-beta.6 (2017-09-03) they added new feature (accept object map for HttpClient headers & params)
Going forward the object can be passed directly instead of 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})
}
Solution 2:[2]
HttpParams is intended to be immutable. The set
and append
methods don't modify the existing instance. Instead they return new instances, with the changes applied.
let params = new HttpParams().set('aaa', 'A'); // now it has aaa
params = params.set('bbb', 'B'); // now it has both
This approach works well with method chaining:
const params = new HttpParams()
.set('one', '1')
.set('two', '2');
...though that might be awkward if you need to wrap any of them in conditions.
Your loop works because you're grabbing a reference to the returned new instance. The code you posted that doesn't work, doesn't. It just calls set() but doesn't grab the result.
let httpParams = new HttpParams().set('aaa', '111'); // now it has aaa
httpParams.set('bbb', '222'); // result has both but is discarded
Solution 3:[3]
In more recent versions of @angular/common/http
(5.0 and up, by the looks of it), you can use the fromObject
key of HttpParamsOptions
to pass the object straight in:
let httpParams = new HttpParams({ fromObject: { aaa: 111, bbb: 222 } });
This just runs a forEach
loop under the hood, though:
this.map = new Map<string, string[]>();
Object.keys(options.fromObject).forEach(key => {
const value = (options.fromObject as any)[key];
this.map !.set(key, Array.isArray(value) ? value : [value]);
});
Solution 4:[4]
Couple of Easy Alternatives
Without using HttpParams
Objects
let body = {
params : {
'email' : emailId,
'password' : password
}
}
this.http.post(url, body);
Using HttpParams
Objects
let body = new HttpParams({
fromObject : {
'email' : emailId,
'password' : password
}
})
this.http.post(url, body);
Solution 5:[5]
As for me, chaining set
methods is the cleanest way
const params = new HttpParams()
.set('aaa', '111')
.set('bbb', "222");
Solution 6:[6]
Another way to do it is:
this.httpClient.get('path', {
params: Object.entries(data).reduce((params, [key, value]) => params.set(key, value), new HttpParams());
});
Solution 7:[7]
Since HTTP Params class is immutable therefore you need to chain the set method:
const params = new HttpParams()
.set('aaa', '111')
.set('bbb', "222");
Solution 8:[8]
Using this you can avoid the loop.
// 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());
Furthermore, I suggest making toHttpParams function in your commonly used service. So you can call the function to convert the object to the 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());
}
Update:
Since 5.0.0-beta.6 (2017-09-03) they added new feature (accept object map for HttpClient headers & params)
Going forward the object can be passed directly instead of HttpParams.
This is the other reason if you have used one common function like toHttpParams mentioned above, you can easily remove it or do changes if required.
Solution 9:[9]
As far as I can see from the implementation at https://github.com/angular/angular/blob/master/packages/common/http/src/params.ts
You must provide values separately - You are not able to avoid your loop.
There is also a constructor which takes a string as a parameter, but it is in form param=value¶m2=value2
so there is no deal for You (in both cases you will finish with looping your object).
You can always report an issue/feature request to angular, what I strongly advise: https://github.com/angular/angular/issues
PS: Remember about difference between set
and append
methods ;)
Solution 10:[10]
My helper class (ts) to convert any complex dto object (not only "string dictionary") to HttpParams:
import { HttpParams } from "@angular/common/http";
export class HttpHelper {
static toHttpParams(obj: any): HttpParams {
return this.addToHttpParams(new HttpParams(), obj, null);
}
private static addToHttpParams(params: HttpParams, obj: any, prefix: string): HttpParams {
for (const p in obj) {
if (obj.hasOwnProperty(p)) {
var k = p;
if (prefix) {
if (p.match(/^-{0,1}\d+$/)) {
k = prefix + "[" + p + "]";
} else {
k = prefix + "." + p;
}
}
var v = obj[p];
if (v !== null && typeof v === "object" && !(v instanceof Date)) {
params = this.addToHttpParams(params, v, k);
} else if (v !== undefined) {
if (v instanceof Date) {
params = params.set(k, (v as Date).toISOString()); //serialize date as you want
}
else {
params = params.set(k, v);
}
}
}
}
return params;
}
}
console.info(
HttpHelper.toHttpParams({
id: 10,
date: new Date(),
states: [1, 3],
child: {
code: "111"
}
}).toString()
); // id=10&date=2019-08-02T13:19:09.014Z&states%5B0%5D=1&states%5B1%5D=3&child.code=111
Solution 11:[11]
Just wanted to add that if you want to add several parameters with the same key name for example: www.test.com/home?id=1&id=2
let params = new HttpParams();
params = params.append(key, value);
Use append, if you use set, it will overwrite the previous value with the same key name.
Solution 12:[12]
appendAll function
import { HttpParams } from "@angular/common/http";
export class BuildUrl {
/**
* append all params
* @param args {unknown[]}
* @returns {HttpParams}
*/
static appendAll(...args: unknown[]): HttpParams {
let params = new HttpParams();
args.forEach(param => {
Object.keys(param).forEach((key) => {
params = params.append(key, param[key]);
});
});
return params;
}
}
how we use it in the service.
getData( pag: PaginationRequest, description: string = ''): Observable<any> {
const params = BuildUrl.appendAll(pag,
{ description },
);
return this.http.get(url, { params });
}
Solution 13:[13]
Since @MaciejTreder confirmed that we have to loop, here's a wrapper that will optionally let you add to a set of default params:
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 };
}
You can use it like so:
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
Solution 14:[14]
This solutions working for me,
let params = new HttpParams();
Object.keys(data).forEach(p => {
params = params.append(p.toString(), data[p].toString());
});
Solution 15:[15]
Using set()
From Angular Official Documentation of set()
set(param: string, value: string | number | boolean): HttpParams
Returns HttpParams: A new body with the new value.
Now, lets see how we can add some parameters -
const params = new HttpParams()
.set('aaa', '111')
.set('bbb', "222");
Notice that we are constructing the HTTPParams object by chaining set() methods. The reason is HTTPParams is immutable.
Every time a call to set method will return a new HttpParams object with the new value. We need to first grab the returned HttpParams object and then use that for further modification.
So, If we do the following, it will not work
const params = new HttpParams(); // empty HttpParams object
params.set('aaa', '111'); // lost
params.set('bbb', "222"); // lost
We are only calling set
but not keeping the returned HttpParams
object. So, lastly we would have an empty HttpParams object, and the two calls to set would have add no effect. To make it work, wee need to do the following -
const params = new HttpParams(); // empty HttpParams object
params = params.set('aaa', '111'); // storing the returned HttpParams object, now **it has aaa**
params = params.set('bbb', "222"); // add another parameter and store it. so now **it has both aaa and bbb**
Using fromString
you can also use fromString to create httpParams. It's good when you already have a Query parameters string prepared. you can do it using the following syntax
const params = new HttpParams({
fromString: 'aaa=111&bbb=222'
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow