Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why HttpParams doesn't work in multiple line in angular 4.3

Tags:

angular

From Angular 4.3 they introduced HttpClient instead of Http. in HttpClient I can't use URLSearchParams for url query parameter . instead of URLSearchParams I'm using HttpParams

This work

 var params = new HttpParams().append('a', '1').append('b', '2');

But why this doesn't work

var params = new HttpParams();
params.append('a', '1');
params.append('b', '2');
like image 789
Imran Avatar asked Aug 02 '17 11:08

Imran


5 Answers

The new HTTP client works with immutable request object and all its consistuent parts like HttpParams and HttpHeaders. To understand why see Why is http request and all its constituent parts like HttpHeaders and HttpParams are immutable or read the article Insider’s guide into interceptors and HttpClient mechanics in Angular.

That is why append method merges the parameters and returns the new instance of the merged HttpParams object on each call to append:

  /**
   * Construct a new body with an appended value for the given parameter name.
   */
  append(param: string, value: string): HttpParams { 
        return this.clone({param, value, op: 'a'}); 
  }

  private clone(update: Update): HttpParams {
    const clone = new HttpParams({encoder: this.encoder}); <-------
    clone.cloneFrom = this.cloneFrom || this;
    clone.updates = (this.updates || []).concat([update]);
    return clone;                                          <--------
  }

So here:

var params = new HttpParams().append('a', '1').append('b', '2');

the append with b parameter updates the object returned by the append with a parameter.

While with this approach

var params = new HttpParams();
params.append('a', '1');
params.append('b', '2');

the append always updates initial state of the HttpParams and all intermediary append operations effectively ignored.

So you have to use the previous returned value:

var params = new HttpParams();
params = params.append('a', '1');
params = params.append('b', '2');

Or use the shortcut with fromObject:

let searchParams = new HttpParams({
    fromObject: {
        query: query,
        sort: sort,
        order: order
    }
});

const modified = req.clone({params: searchParams});

Or use setParams method on a request directly:

const modified = req.clone({setParams: {'query': query, 'sort': sort, 'order': order}});

Also, since 5.1.x you can pass object directly instead of an instance of HttpParams:

const params = {
  'a': '1',
  'b': '2'
};

this.http.get('...', { params })
like image 130
Max Koretskyi Avatar answered Nov 18 '22 21:11

Max Koretskyi


For this to work

var params = new HttpParams();
params.append('a', '1');
params.append('b', '2');

This has to be changed to

var params = new HttpParams();
params = params.append('a', '1');
params = params.append('b', '2');

It can be looped and added dynamically

like image 41
Anthony Avatar answered Nov 18 '22 21:11

Anthony


Since 5.0.0-beta.6 (2017-09-03) new feature(accept object map for HttpClient headers & params) is available.

Now we can pass object directly instead of HttpParams:

const params = {
  'a': '1',
  'b': '2'
};

this.http.get('...', { params })

or instead of HttpHeaders:

http.get('/url', {
   headers: {'My-Header': 'header value'}
})
like image 13
yurzui Avatar answered Nov 18 '22 22:11

yurzui


Actually @Maximus made a pretty good explanation about the immutability of the HttpParams object, and all you need is to simply replace the params with its clone inside the loop.

Assuming that you have zero-to-many params available, stored in an array similar to the structure below:

"params": [
  {
    "key": "p1",
    "value": "v1"
  },
  {
    "key": "p2",
    "value": "v2"
  }
]

And according to the information above, the following helper function should help:

export const getHttpParams = (params: Array<any>): HttpParams => {
  let res = new HttpParams();

  for (const item of params)
    res = res.append(item.key, item.value);

  return res;
};

Usage

const backend = 'http://httpstat.us/200';
const params = getHttpParams(backend.params);

return this.http.get(`${backend}`, { params });

Hope it helps!

like image 2
Burak Tasci Avatar answered Nov 18 '22 21:11

Burak Tasci


I have tried all the other ways on this post, but had little success. So I'm chaining params onto an HttpParams singleton and calling toString() to return a string type. I can then pass that to http.get() and everything seems to be working fine for building up the url parameters. Here is my ng -v:

$ ng -v
    _                      _                 ____ _     ___
   / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
  / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
 / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
/_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
           |___/
@angular/cli: 1.4.2
node: 8.5.0
os: linux x64
@angular/animations: 4.4.3
@angular/cdk: 2.0.0-beta.10
@angular/common: 4.4.3
@angular/compiler: 4.4.3
@angular/core: 4.4.3
@angular/forms: 4.4.3
@angular/http: 4.4.3
@angular/material: 2.0.0-beta.10
@angular/platform-browser: 4.4.3
@angular/platform-browser-dynamic: 4.4.3
@angular/router: 4.4.3
@angular/cli: 1.4.2
@angular/compiler-cli: 4.4.3
@angular/language-service: 4.4.3
typescript: 2.3.4

Here is an example that is working well for me:

// Simplified for example (I'm using Redux and won't go into all that)
private downloadState = { requestType: 'Auction', fileType: 'CSV' };

getStuffFromApi(): Observable<any> {
    const { requestType, fileType } = this.downloadState;
    const apiRoot = 'http://www.example.com';

    const params: string = new HttpParams()
        .set('RequestType', requestType)
        .set('FileType', fileType)
        .set('AuctionType', auctionType)
        .set('BackorderDay', backorderDay)
        .toString();

    return this.http.get(apiRoot, { params })
        .map(res => res.json())
        .catch(err => Observable.of(err.json()));

}
like image 2
Joshua Michael Calafell Avatar answered Nov 18 '22 22:11

Joshua Michael Calafell