'Using an Angular 2 http.post without subscribing? Or am I thinking of it wrong?

Is there a way to just tell the server to update data without subscribing? Skipping a return statement and a subscription seems to render the http call inert.

In my case, my DB guy created a bunch of stored procedures that return nothing and sometimes I want to do something simple like this in my service:

public setItem(item: IRequestItem) {
        this.http.post('api/items', item);
    }

and call it like this in my component:

save() {
        var comp = this;
        this.items.forEach(function(item) {
            comp.service.setItem(item)
        });
    }

Instead I have to do something like this in the service:

public setItem(item: IRequestItem) {
        return this.http.post('api/items', item);
    }

And then call it like this in the conponent:

save() {
        var comp = this;
        this.items.forEach(function(item) {
            comp.service.setItem(item).subscribe(r => console.log(r));
        });
    }

Which would return lots of these:

Response {_body: "", status: 204, ok: true, statusText: "No Content", headers: Headers…}
_body : ""
headers : Headers
ok : true
status : 204
statusText : "No Content"
type : 2
url : "http://localhost:56018/api/items"
__proto__ : Object

I'm just learning so maybe I'm looking at it wrong. Can I interpret something in that Response object that will let me know if the operation failed or succeeded? Or is there another syntax that will just return a success or failure instead of the confusing "No Content" response?



Solution 1:[1]

In order to trigger the request, you need to call subscribe but you do not need to return the request observable from the service and call it from the component, you can call subscribe from within the service.

setItem(item: RequestItem) {
  this.http.post('api/items', item)
    .subscribe({ error: e => console.error(e) });
}

Now in the above, the service will immediately return, before the request completes but the request will be made and any errors logged from within the service.

Solution 2:[2]

The Observable returned by http.post is a "cold" observable: it won't do anything unless someone subscribes to it.

In RXJS 7 you can turn such cold observable into "hot"/connectable observable using ReplaySubject and connectable. If someone subscribes to it, it will get the result. If nobody subscribes to it, it'll still be invoked. Add this utility function into your code:

  private wrapObservable<T>(coldObservable: Observable<T>): Observable<T> {
    const observable = connectable(
      coldObservable,
      {
        connector: () => new ReplaySubject<T>(),
        resetOnDisconnect: false
      }
    );
    observable.connect();
    return observable;
  }

Then wrap http.post with it:

public setItem(item: IRequestItem): Observable<IItemSetResult> {
    return this.wrapObservable(this.http.post('api/items', item));
}

Now you can call setItem without .subscribe() - it'll work:

save() {
    var comp = this;
    this.items.forEach(function(item) {
        comp.service.setItem(item);
    });
}

If you need the results, you can subscribe to the wrapped observable:

save() {
    var comp = this;
    this.items.forEach(function(item) {
        comp.service.setItem(item)
            .subscribe(itemSetResult =>
                console.log(`Server returned result: ${itemSetResult}`)
            );
    });
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 izogfif