2

I am using the BehaviorSubject following the article here:

https://coryrylan.com/blog/angular-observable-data-services

In this article the author is using loadAll() to load all items and load() for a single entry. load() will then push the retrieved item into the dataStore which then gets sent into the next(...) function, so that all subscribers get notified. I am not sure 100% sure if this is the right approach. I am not sure why, but it just seems strange to me that this is how we should design our services. I could be wrong, since I am new to BehaviorSubject. So my question is, is this the correct way to retrieve all items and a single item or is there a better way?

user8408326
  • 83
  • 1
  • 2
  • 7

2 Answers2

4

From what I am seeing ... way too many devs are using BehaviorSubject when a simpler solution would suffice.

BehaviorSubject is really only needed if you have complex requirements to watch for data changes when the data is not bound. Otherwise, simple data binding handles watching for changes for you.

This is the code I have in my service for getting all and getting one:

getProducts(): Observable<IProduct[]> {
    return this._http.get<IProduct[]>(this._productUrl)
        .do(data => console.log('All: ' + JSON.stringify(data)))
        .catch(this.handleError);
}

getProduct(id: number): Observable<IProduct> {
    return this.getProducts()
        .map((products: IProduct[]) => products.find(p => p.productId === id));
}

I modified the plunker from the link provided by the OP and my results are here: https://plnkr.co/edit/r5PMFprgoWbzmFPTK3xN?p=preview

Note that it provides the same basic functionality with NO BehaviorSubject and much more simplified code.

DeborahK
  • 57,520
  • 12
  • 104
  • 129
  • 1
    I do need to watch for data changes. – user8408326 Aug 02 '17 at 23:32
  • I am asking the question based off the article posted. Imagine that this article is returning a lot of data over time. – user8408326 Aug 02 '17 at 23:36
  • @deborak I am not doing anything special with the data. Retrieving it through HTTP, then mapping it to some entity and finally using an `ngFor` to bind it. The data will change quite often. – user8408326 Aug 02 '17 at 23:43
  • Then your binding will take care of it for you ... you don't need BehaviorSubject. I was just consider rewriting Cory's example without BehaviorSubject to show what I mean ... but it can't seem to connect to the mockapi service that it is using. Were you able to run the plunker? I'm getting: `Failed to load resource: the server responded with a status of 503 (Service Unavailable)` – DeborahK Aug 02 '17 at 23:47
  • If you are interested, you could look at my example here: https://github.com/DeborahK/Angular-Routing. – DeborahK Aug 02 '17 at 23:51
  • I wish I could find an article that would explain when to use the `BehaviorSubject`. The plnkr was working yesterday. Not sure why its down. – user8408326 Aug 02 '17 at 23:56
  • Thanks for sharing the link. I will review it. There are a ton of articles out there using `BehaviorSubject`. It seems very popular. – user8408326 Aug 02 '17 at 23:57
2

Observable, Subject & BehaviorSubject

Difference Between Observable and Subject

If all you are concerned about is data retrieval then DeborahK's answer is pretty much right on. Typically, and I say "typically" lightly, an HTTP request is a standard observable, meaning the request goes out, comes back, returns some data, and doesn't get fired again until a new subscription is made to it. For most observable patterns, the standard Observable type is perfect for the job.

The easiest way to think about it is to just look at the name; Observable. If all you are doing is 'getting' data, then an Observable is what you want. However, if you find that you have a requirement to manipulate the stream of data after instantiation, then a Subject or BehaviorSubject may be the right fit. The difference between Subject and BehaviorSubject is that a Subject does have to have an initial value, where a BehaviorSubject is given an initial value on instantiation.

A good example of a use case for a Subject or BehaviorSubject is a boolean value that is used across a site to tell the application when a Modal should be visible or not. Since multiple components can alter the state of the visibility of the Modal, you would need a BehaviorSubject that can be altered, triggering the parent component to display the modal.

Another good example for Subject would be a search bar that advertises it's contents to other components throughout the application. The key here is that you are emitting new values to the stream to be observed by other components/services within the application.

The last thing I will say about is that all of the above fall under the category of an Observable, technically speaking. I think that's where a lot of the confusion takes place.

Pushing Data

Another thing I am noticing about your question is that seems like you are actually trying to solve a problem that isn't necessarily solvable within Angular itself. If you have very dynamic data within your "backend" that you want to be pushed out to your front end, then you may need to look into a websocket socket server. It sounds way more complicated than it is, but essentially it allows your server to "push" data to your application. If it's secure data, I recommend using your server to push an "updates available" message, and then have the application securely make an HTTP request for the updated data. DO NOT send secure information over web sockets. Here is a great resource for websockets using Socket IO within a node server and making pushes to an Angular App. There's a lot out there.

joshrathke
  • 7,564
  • 7
  • 23
  • 38
  • 1
    Thanks. That makes sense. I am however not looking to push data. – user8408326 Aug 03 '17 at 13:26
  • And I would say that your two examples could be done leveraging Angular's change detection and binding with no need for BehaviorSubject. – DeborahK Aug 03 '17 at 14:59
  • They could be, but it would depend on the app structure. For example trying to communicate between components that are not a direct parent/child or even communicating between a parent module and a lazy loaded module becomes very difficult using standard data binding. – joshrathke Aug 03 '17 at 15:05