Filtering Data Part 2

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

Previous LessonFiltering Data Part 1Next LessonInfinite Scrolling

This lesson preview is part of the Mastering RxJS: A Compact Journey from Beginner to Pro course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Mastering RxJS: A Compact Journey from Beginner to Pro, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Mastering RxJS: A Compact Journey from Beginner to Pro

Hey guys, in this lesson we are going to look into what a Subject is, what kind of Subjects there are and how to use the Subject. As you remember from the last lesson we wanted to create an Observable in here, so whenever we get new data, we call our fetchProducts method with a search term in it, which comes from our Observable, and then the UI gets updated. As you've probably guessed it by now, this Observable that we want to create is actually a Subject, A Subject, is just a special type of Observable. One of the key differences of a Subject is that in a Subject you can actually manually emit the next value, while as opposed to a simple Observable you can only subscribe to it. The second key difference is that an Observable gets executed upon subscription, while a Subject gets executed whenever there is a new value emitted. Let's go back to our code and see how it works. First things first, we want to convert this filter term into a Subject. Now that we have a Subject, the Subject has a method next, which will emit a new value to the subscriber of our Subject. Now in our ngOnInit, let's subscribe to our filter term and let's just console log the value that we are emitting. Great, now let's start the application, let's type something in. As you can see whenever we type something in here, the next value gets emitted and we can see it being console logged in here. It's as simple as that. To summerize this, the Subject is just like an Observable, with the only difference is that we are responsible for emitting new values and it does not execute upon subscription. There are different types of Subjects and we will go through each one of them. The first one is a BehaviorSubject. A BehaviorSubject is a variant of a Subject that requires an initial value and emits its current value to the new subscribers upon subscription. Let's go back to the code and see how it works. To create a BehaviorSubject, we need to rename this Subject to BehaviorSubject. Now it is complaining because as you remember a BehaviorSubject requires an initial value. Let's give it one. Now, if we go back to our browser, whenever we refresh our page, we see the initial value being emitted, then after we type something, the following values are being emitted as well. The behavior is pretty similar to a Subject with the difference that it will always have an initial value. A BehaviorSubject is useful when you need to start with an initial value or a default value in cases like when you have a reactive form or you want to start with a default state and update its values from there. The next type of Subject is a ReplaySubject. A ReplaySubject does not have an initial value. Instead it will emit its latest value or latest values, plural. Let's see it in action. Let's replace BehaviorSubject with ReplaySubject. A ReplaySubject does not have an initial value. So, let's remove that. Instead, what the ReplaySubject does, as the name suggests, it will replay the latest values that are being stored in memory. The default is an infinite amount of values. But we can also specify a number of values that should be retained in memory. For example, at any given time, it should have at most the two most recent values stored in the Subject. It is also possible to configure for how long a ReplaySubject will store its values, which is a second parameter, which is a number in milliseconds, of course. So in this case, it will store two most recent values for five seconds. A ReplaySubject will work with a FIFO principle, so first in first out. For demo purposes, I will remove the timer and I'll just keep it at two values. If we leave it like that and go to our application and we type anything in here, the behavior is the same as if it was a regular Subject. How do we see that it's different than a regular Subject? In our application, let's emit two values, this filter term, next, let's called value one, and then value two and after that, we will subscribe to it. Now if we go back to our application, we refresh the page. Now you can see that the last two values have been emitted. If we add a third value, the expectation is that only these two values will be emitted. And you can see it here in the console that only the last two values have been emitted. One of the key differences between a BehaviorSubject and a ReplaySubject is how they behave when they observe an error. The ReplaySubject will replay values even after observing an error where a BehaviorSubject will not. Let me demonstrate. A Subject also has a method called error. So now the second value will error with a value two message, or actually let me rename it to error message. And then we will try to emit a new value after it observed an error. With the ReplaySubject, let's see what happens. So, when I refresh the page, I get the first value, I get the error message, and the third value is not emitted anymore. The reason why value three is not emitted anymore is after an error is emitted, the Subject will no longer emit any more next values. And the subsequent calls on that Subject will be ignored. Now let's observe the behavior of the BehaviorSubject. Let me write initial value in here. Let's see what happens. Now when I refresh the page, I only see the error message. And the reason for this is because BehaviorSubject emits only the current value. Another difference is how they behave when a Subject completes. Let me demonstrate that as well. So, let me remove that error here and go back to value two. In the last part, let's complete. When you call the complete function on a Subject or Observable, what it does under the hood is, it notifies all the subscribers that the Observable has finsihed emitting all its values and will not emit any further values. In our case, we have completed the BehaviorSubject, and afterwards we will try to subscribe to it. Let's see what happens. Let me refresh the page and nothing happens. This is expected. Contrary to how the BehaviorSubject works. The ReplaySubject has a different behavior. Let's see it in action. Now if I refresh the page, I see the last two values being emitted. Even though the Observable has been completed, I can still fetch the last two values from the ReplaySubject. This is intentional and by design. Most often when an observable completes is when a component gets destroyed. A few use cases for ReplaySubject could be a multi-step checkout process where each step component can access the previous step's data or, for example, when you have a chatbot where the user refreshes the page or navigates back to the chat or a user submitted the feedback form and then navigated away from the page. We can still use the data that the user submitted in other parts of the application by using a ReplaySubject. The next type of subject is the AsyncSubject. The AsyncSubject will only emit the last value and only one the execution completes. Let me show you. In here, let's change this to AsyncSubject. In here, we are going to emit one value, then value two. And after we are going to complete it. Now let's go into the browser and see what happens. If I refresh the page, as you can see, only value 2 has been emitted because in our code we completed the Observable after we emitted two values and only the last one is being emitted. A use case for an AsyncSubject would be when you are interested in only the last value and you want to cache it. And the difference with ReplaySubject is the ReplaySubject will emit when it gets a new value while the AsyncSubject will emit after it is completed. So for example, HTTP calls that you want to cache. Those three are different types of Subject and of course if we don't need any of those special behaviors we can just use the Subject itself. So, in here, if we just name that Subject that will return a type of string, let me remove that complete from here. Let's move the Subscription here up top and now if we look at the browser we see that value 1 and value 2 have been emitted. There's one interesting thing about the Subject is let's say that you are not so interested in the value that has been emitted but instead you are interested in the fact that a value has been emitted. In this case let's change the type to void. Let's remove those in here, and let's comment this out for now and in here let's type in emitted. Let's go to our browser and see what happens. If I refresh the page I see emitted in here two times. This is actually called a void Subject although it doesn't have a special type on its own. It can be quite handy if we want to be notified about the fact that something happened and we are not so interested in the value itself. For example all the browser events like a mouse click or the scroll of the mouse, those can be the type of actions that can be used with the void Subject. Now let's go back to our application and finish implementing the filtering part. Let's go back, set this to string, let's remove those in here and let's comment this out. The next thing that we actually want to do is call this fetchProducts method inside our search term Subscription. Let me do that. We get our next value, our search term as a parameter and then we want to pass it down to the fetchProducts. And to make it work let's assign this Observable to our products Observable like this. Now, If you go back to the browser and now I refresh the page I get the whole product list in here and if I want to filter it out for let's say DSLR we get the list filtered out. So our solution works but there are a few problems. The first, one because we subscribe we forgot to create a Subscription and unsubscribe from it. Luckily for us, there is a special operator which is called takeUntilDestroyed. Let's call pipe, let me import that. Unfortunately it does not get suggested to auto import it. So let me import it manually and we import it from Angular RxJS interop. So basically this is just syntactic sugar for all the subscribe and unsubscribe boiler plate. Unfortunately as of the recording of this video this is still in developer preview. So for those of you who do not want to use developer preview functionality or who are stuck on an older Angular version, we will go into implement our own take until destroyed functionality. So let's remove that for now. Let's leave it like this and actually create a Subject, call it take until destroyed, new Subject and do you remember guys when I told you about the void Subject? This is actually the use case for it. As for the operator that we want to use there is actually an operator called takeUntil let's put our Subject in here let's fix the naming. There we have it. And because I don't like take until this take until, let's change the name to just destroyed. So this is how the newest operator actually came to be and where the name stems from. We are not done yet. We want to implement the onDestroy method in here ng on destroy and there are two things that we want to do is, first of all, this destroyed we want to emit that there's something has happened, and that's something is the component has been destroyed. That's why it is inside the on destroy method and the next thing is we want to complete this Observable. So, what this does is it will automatically unsubscribe whenever this component gets destroyed. Now that we fixed our subscription problem with the help of the void Subject there's one more problem that we have in here and that is that we are re assigning this products Observable in here, which I said earlier, this is thinking imperatively. So the next question is: How can we avoid this and think reactively? How can we not reassign this products Observable but instead work on what we have? First, let's get rid of the first assignment of the products Observable. Now, the problem that we have is this function will only get assigned when we actually have a value in here. So, in our browser, if we refresh the page and see it here I refreshed nothing happens. Now, what I want to do is force trigger the call to our product service. There are two ways that we can use to do this. One is using an operator and the second one is using one of the Subjects that we have seen earlier. So, pause the video and try to find a solution. Now I'm going to show you how I would solve this. There is an operator that is called startWith and we can pass to it and empty string. Now if we go back to our application, I refresh the page. You can see that the first empty value got added, and then if we filter the list it gets filtered. The second solution is to use the right type of Subject. So looking at all the types of subjects that we have we see immediately that a BehaviorSubject always must have an initial value. Let's go to our code and change it. Let me type in here BehaviorSubject. And it is complaining because an initial value is required. The initial value will also be an empty string. Let's save. And if we refresh the page we get the same behavior just like with the startWith operator. That's it. In this lesson we've seen what a Subject is, the different types of Subject and a few practical use cases for the Subject.