Angular Data Services, helped by the beauty of BehaviourSubjects (they are not BS)

Technical Mar 30, 2018

The rule of thumb in all of Angular (2+), alongside the complete rewriting of the HTTP Client in 4.3, is that the data flow should be handled using Observables. All of the Client’s calls are themselves Observables, to which you can subscribe and receive the required data on completion.

This should be a good way to handle your data, but what happens when you want to create a Service that manages your data, as models, or maybe just as JS primitives, store them, and modify/delete them when needed.

Personally, I’ve dealt with this problem for a long time, but recently I came up with a rather simple solution to it, that I would like to share it to all of those who are also struggling with it. It might not be much, it might not be perfect, but for now, it is a good solution to the problem at hand.

Hello there, BehaviourSubject!

Yes, please say hello to the Behaviour Subject, or how I like to call him, BS for short. BS will allow you to read the current value of the Observable, submit a new value (that becomes current) and allow others to listen to the stream by subscribing. BS is somehow similar to the Replay Subject, but the key difference is that he will re-emit only the last emitted value. This is actually what we want, only one state of the entire data (the current one).

There is only one problem with BS, he needs an initial value. But, being an optimist (of course, only in the morning) I took this as an opportunity, rather than a setback. Thus, I will always initialize my BS with the null value and have a getter method that returns the Observable of the Subject. The trick is to filter the returned observer values and allow only those that are different from null.

By this, my Service will always return a coherent value, in the form of an Observable with data. You can either subscribe to it or even use it in the template with the async pipe.

Inside the Service, I will be able to get the current state of the Observable data, by calling the getValue method of the BS. Make any needed modifications to that data, and updating the data inside the BS’s Observable with the next method. All of my subscribers will get the update, and even if there is a late subscriber to the party, he will always get the current value of the data. Simple. I leave you now with an example of how this can be used. Cheerios!

/** A random, totally not real, aNGular Users Service */

private users$: BehaviourSubject<User[]> = new BehaviourSubject(null);

get users() {
  return this.users.asObservable().filter(item => item !== null);
}

private get usersValue() {
  return this.users.getValue();
}

public updateUserName(id, name) {
  const usersInstance = this.usersValue();
  const index = usersInstance.findIndex(item => item.id === +id);
  usersInstance[index]['name'] = name;
  this.users$.next(usersInstance);
}

Tags

Florin Tomozei

Software Engineer and Storyteller