Angular State Management without using external libraries

Published by Rienz Otiong on

Angular State Management is important when it comes to web applications or web tools but some external libraries in Angular like ngrx, ngxs and akita are very complicated and complex on how to implement it.

Now I would share something called BehaviorSubject in rxjs which is already included on Angular and can be used as a tool to manage our state. You can also go to this github repo to double check if your doing it correctly and know the structure of this article.

 

 

What is Subject?

We need to know first what is Subject. Basically it is an Observable in which you can store a value and emits the value upon using the next function.

 

 

What is BehaviorSubject?

BehaviorSubject is a type of the Subject but requires an initial value and emits its latest or current value upon subscription. This is important for our Angular State Management since we could get the latest value of our data and update it whenever some changes happens.

 

 

Creating Model and Service

Before we proceed on creating our Store class. I want to share the full potential of this topic so first lets create a Model which represents our state and Service that we can use later from our store which calls an HTTP request from an API.

Checking on the routes that are available in jsonplaceholder. I picked the post endpoint for us to use in our project.

Nothing crazy here just some HTTP functions in our service that we will be using in our store later.

 

 

Creating Store

Now that we know how BehaviorSubject works. Lets proceed on creating our Store class.

Let me explain one by one on what did we do here.

  • First we declare our state$ as BehaviorSubject and assign with an initial value of undefined just to visualize that no value has been stored yet.
  • Next is the getAll function which returns the current value of the store and getAll$ that returns an Observable on which we can subscribe so that our data will be updated when some changes happens in our state.
  • Lastly is the store function where we update the data on our state.

 

 

Extending Store

Here’s the fun part where we’re going to inject the Service and extend the Store. So now we’re going to extend our Store class to our PostsStore.

Then provide an initialization init function to get the data from the service and then use the store function to save the response data.

 

 

Import in Module

Don’t forget to put the store and service inside the providers of the module. also add the HttpClientModule into imports since we use HttpClient in Service.

 

 

Display in Component

You can run the init function wherever you like, for example in route resolver, components, and etc. But in this example I’m just going to run it on the App Component just to show on how it works.

app component image

 

We used an async pipe since our returned value is an observable but you can do it on the other way around where your going to subscribe to the observable then assign the returned value to your variable like the example below.

 

I would still prefer using async pipe as much as possible since it automatically unsubscribe the observable when the component is destroyed or not active but you can also manually unsubscribe the subscription however with extra codes.

 

 

Example Basic CRUD

 

So yeah! This is the end about Angular State Management and how to make yourself a store without using any external libraries. If you have any questions or suggestions feel free to comment here and I will try to reply as soon as I can.


7 Comments

Guilherme · February 7, 2019 at 2:01 am

Really good article! I just didn’t understand the reason of calling “subscribe()” after the pipe in the store. Could you please explain to me?

    Rienz · February 7, 2019 at 8:55 am

    It is called for us to execute the observable to initialize the data and be stored when completed.

Nicolas Forney · April 7, 2019 at 4:27 am

Really interesting article! Thank you for sharing.

Do you think a store should always have only one BehaviorSubject? Imagine in your example you’d like to store the selected posts. Would you create a new store (SelectedPostsStore) or just add a new BehaviorSubject and state to the current PostsStore? Creating a new store for every state you want to manage seems a lot of work and adding multiple states to the same store might make a store become a bit cumbersome. Perhaps a balance between the two is the best solution?
I would be happy to ear your thoughts on this matter.

    Rienz Otiong · April 8, 2019 at 3:49 pm

    Hi Nicolas,

    I think what you can do is from your post’s property have a boolean property named isSelected. then now you can have the same posts but at the same time you can determine what posts are selected. Hope it helps. If you have anymore questions feel free to ask

      Nicolas Forney · April 9, 2019 at 4:07 am

      Hi Rienz, thank you for your answer.

      I see the Post model more like a “pure” model which only represent what I retrieve from the PostService. If I add a isSelected property, I probably don’t want to send it to my back-end when calling the the update or create function. I can of course remove the property when calling my back-end or ignoring it on the back-end part. But it doesn’t seem the right way of doing things. Wouldn’t it better to have a clear distinction between the model you’re using to transfer data from/to your back-end api and an actual PostState which will also contain logic only useful on the browser side and should not be persisted?

        FloppyNotFound · April 11, 2019 at 8:27 pm

        What we are doing is to extend the backend model.
        So you could do something like this:

        export interface BackendPuppet {
        color: string;
        isIntroverted: boolean;
        }

        export interface BackendPuppetState extends BackendPuppet {
        isSelected: boolean;
        }

        and only send back an object of type BackendPuppet.

        Or, as an alternative, box your model:
        export interface BackendPuppetState {
        backendPuppet: BackendPuppet;
        isSelected: boolean;
        }

        This way you make sure, you keep your properties separated.

        Rienz Otiong · May 2, 2019 at 1:38 pm

        In addition to @FloppyNotFound’s comment. On your backend, You could just ignore any other properties that has been passed thru request since You should have a validation and a filter on the backend side. So I think its fine to pass an extra property and just the backend filtering it out

Leave a Reply

%d bloggers like this: