RVP RVP - 4 months ago 38
AngularJS Question

Angular2 http.post gets executed twice

I came across a weird issue where the Angular2's (RC1) Http service executes the http.post call twice. I've debugged my app and I know for a fact this is not a click event issue. All the calls that lead up to the core service call

public create(json: Object, params?: Object): Observable<T> {
let body = JSON.stringify([json]);
let headers = this.getHeaders();
let options = new RequestOptions({ headers: headers });

return this._http.post(this.createURL(this.getCreateURL(), [], params), body, options)
.map(res => this.handleObjectResponse(res));
}


are run once. Then when I started tracing the issue I found out that my handler
this.handleObjectResponse
gets executed twice. So I delved further and reached
@angular/http/src/backends/xhr_backend.ts
where they do this

constructor(req: Request, browserXHR: BrowserXhr, baseResponseOptions?: ResponseOptions) {
this.request = req;
this.response = new Observable<Response>((responseObserver: Observer<Response>) => {
let _xhr: XMLHttpRequest = browserXHR.build();
_xhr.open(RequestMethod[req.method].toUpperCase(), req.url);
// load event handler
...
..


So I put a breakpoint on
this.request = req;
and then another breakpoint on
let _xhr: XMLHttpRequest = browserXHR.build();
and I found out I hit the first breakpoint once but then I hit the second breakpoint from the callback twice.

This has been driving me nuts so I wanted to check whether anyone familiar with the angular2 internals could shed some light whether this looks like a bug or something that I've done wrong.

In my code I've created some abstract generic service classes: GenericService and FullService which extends GenericService. Both of these are abstract and use generics and the real service classes that get injected in the different components all extend either GenericService or FullService. Do you guys think this setup could possibly be responsible for the double post executions?

All ideas are appreciated!

Thanks in advance!

P.S.

This doesn't happen with gets but it also happens with puts.

Answer

The http service returns a cold observable that get executed on every subscribe, you want to convert it to a hot observable that get only executed on the first subscribe and share the same value for subsequent subscribes.

To convert it all you have to do is share it:

return this._http.post(this.createURL(this.getCreateURL(), [], params), body, options)
.map(res => this.handleObjectResponse(res))
.share();