Composing with Higher-Order Operators
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.
Get unlimited access to Mastering RxJS: A Compact Journey from Beginner to Pro, plus 80+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 01:29] Hello guys, now that we've seen all the higher order observables, we've seen all the regular operators as well. It's time to incorporate this knowledge and finally implement the search and infinite scroll functionality. The goal is simple. We can search the list, we can get the next results that are already filtered. Let's dive into the code first. Let me remove that here. Also, let me delete all unused imports and let's start here. So let's think for a minute what happens. We start from the filter term observable and we want every time we get a new value, that we need the filter with, we want to cancel the previous request so that we can start a new request. For this we are going to use the switch map operator. The filter term will return a string, let's call it filter term and we want to use the string to call the product service. As you can see it in here, we also need to give a page number. How do we get this page number? It's pretty simple. As you remember from our previous lessons, out here we have the infinite scroll directive and also a scrolled method, where on scroll, we are going to increment the current page observable. What is the current page observable? It's a behavior subject and because it's a behavior subject, it already has a start value. So we can directly use this current page observable, pipe and now in here we can use another higher order observable. So let's think again for a minute. What do we need here? When we get a new filter term, we want to cancel the previous request and start a new one. But when we scroll down, we want to append or concatenate the next result sets to the one that we currently have.
[01:30 - 01:50] So in this case, I'm going to use the concat map operator and in here we get the page number and with this page number, we can now finally call our product service. Of course, we need to return all of that. Why? Because at the end, we want to assign this observable to the products observable. And I need to return that here as well, let me format and this is what we get.
[01:51 - 02:23] This is what is called a nested higher order observable. This then becomes the inner observable and this is the outer observable. There's one more thing that we need to do and that is the result from this fetch products method. We need to store it somewhere and this all product will be our in memory variable that will store all the result that we get from this service. To do that, I'm going to the map operator, let me import it. And in the map operator, we get the products, from the concat map, from out here. And we want to append these products to all products. So let me just do that.
[02:24 - 02:34] We will append the current products list and the new products that we got from the concat map. Let me format and for a little bit of consistency, I will use the curly braces out here.
[02:35 - 03:41] With a return statement. Format again. So this is how our observable looks like. Now let's see it in action. First, I want to turn off throttling so we can get results faster. Then when I scroll down, immediately or almost immediately, we get the new results appending to the current ones. Now if I scroll down, nothing happens, which means that we got infinite scroll working or pagination, but we somehow broke filtering. Before we dig deeper into what we need to do to fix this, I want to refactor this part. This is a preference. Personally, I don't like the nested style of higher order observables. So I will flatten this out. First, I'm going to combine the filter term and the current page number together into a result. For this, I'm going to the map operator and the current page observable is going to return the current page. And we are going to map it to an object that we are going to construct. And this object will allow two values, which is filter term and current page. I think I'm missing a bracket here, and another one, curly bracket and another bracket. Okay, now the next operator that we're going to use is the concat map. And the concat map is going to get this object as parameter.
[03:42 - 03:57] And let's change current page to page number. Still have some syntax errors. We have a little too many brace out here. Let me remove those and I removed one too many. Let's format. So this is our end result. Now that I have flattened what we had before, we get a single pipeline structure.
[03:58 - 04:34] And this is my preferred way of writing pipelines. For me, this is more readable and easier to maintain. Also, we can see how the data flows from top to bottom. It goes into the switch map, then into concat map, and eventually into the map operator. And to achieve even better readability, I will move the search component back into the app component. The reason for this is this filter term is a behavior subject. And I have no idea where it's being set. I need to go into handle search, search for where it's actually used, it's used in here, then I need to go here. So it's quite spread out. And I'd rather have it into one single observable.
[04:35 - 04:52] This is a mistake I've done in the past where I would split different observables in different services or components. And this made readability of the code so much harder. Now let me just copy that into our app component. And then what we have here, let's copy it in our app component.ts.
[04:53 - 05:04] Let's swap it. Okay, we got one pipe already. We don't need a second. I can remove that. Let's format. Import all the missing imports. We are still lacking the search control. Let's add it import again.
[05:05 - 05:24] And we can remove the search component from here. We need to import the reactive forms module. Let's go ahead and do it. Let's format. Save. And we should be good to go. This is so much more readable. And we have more control and it's easier to maintain. For example, I want this take until destroyed to be first in the chain, because let's say the component gets destroyed.
[05:25 - 05:34] I'm not interested in everything out here. I want the observable to complete as soon as possible. Let's go back to our application. And looks like we forgot to do one more thing.
[05:35 - 05:49] When we had the search component, we would emit an event with the search term. Now we don't do that anymore. So we don't need this behavior subject and this handle search method. What's happening is before there is any change on the search control, nothing actually happens.
[05:50 - 06:33] That's why we only get the loading spinner. If I were to search for 36 MP, for example, we see immediately that we get the search result. There is an operator called startWith where we can force this event. So it triggers for the first time without actually typing something in the search control. So, let's start with an empty string. Let's see if it works. Now if I refresh the page, we can see that we get results. Now let's go back to our filtering issue. Before I move any further, I want to encourage you to stop this video, set a breakpoint and try debugging it and see what the issue is. The issue that we're currently having is we are starting with the first page. We are starting with an empty list. After we get some data, we are going to increment the page. We are going to add data to this list.
[06:34 - 06:43] But once we reset the search term, we don't reset the state. So the state stays unchanged. We want to reset the state when we get a new filter term. Let's do it inside the switch map.
[06:44 - 07:03] This all products will be an empty array. And then for the current page number, we want to emit one as the next page, because later on, when we get the current page, we want for it to be one. Let's go back to our page and see what we have now. So now when I'm scrolling, I get next results. And when I filter, now we get filtered results. Let's see if pagination works.
[07:04 - 07:26] Unfortunately, there is still something with the pagination. Let's go back to code and see what we're still missing. Unfortunately, I don't have enough data to show you that the next page is being loaded. So let's add more data. Inside our product JSON. Let me copy this array. Let me just copy past it a few times. Format. Save. Now let's try again. If I'm going to type 36 MP, I get the filtered list.
[07:27 - 07:53] Now when I scroll down, I get the next filtered list. And if I scroll down again, I get the next batch again. And if we are going to clear it, the state is reset, and we get the initial ten items again, let's try it again. So we see that we get new results. Then we reset it with scroll down. But somehow we get very strange results, which is not what we expected. For some reason, we still get cameras and other stuff than camera. Sometimes this happens when we miss something.
[07:54 - 08:50] And I'm going to show you how I prefer to solve this kind of issues. We can use debugging or just print statements. For this, I think it's easier to use print statements. I'm going to print out the filter term and current page and see what we get there. So we see we started with an empty string and current pages one, we go back to camera, we get the filter term camera, we scroll down, we get current page two, scroll down again, we get current page three. Now let's go clear the state. We start again, let's print 36, scroll down. And there we have it. We can clearly see that there's something wrong with the current page, the way it's being set. Let me try one more time. So I'm scrolling down. And now for some reason, I get six. So there's definitely something wrong with the current page. Let's go back into the code. We know that there's something wrong with the current page, And we get the current page from the current page observable. And in here, we're going to set the current page observable to one. But when we scroll down, we have this on scroll method.
[08:51 - 09:27] And this on scroll method, it will get the current page value, which is something that we hold in memory. And it will increment it with one. The issue is actually that we never reset this value. Let's go ahead and reset this value as well. Now we should be good to go. If I do the same steps as before, I filter on camera, I scroll down, I scroll down again, let's reset the filter. Let's go for 36. And when I scroll down, I expect to see the second page, which is exactly what we get here, we see that we get the second page, the third page, and so forth. If you reset the page again, we get the list in the order that is in our database, or our JSON file.
[09:28 - 09:47] To summarize what we have done in this lesson, we have composed a single pipeline that consists of multiple operators and a higher order observables. We have learned how to chain multiple higher order observables together. And we have finally implemented the infinite scroll and the search functionality. Thank you for watching and see you in the next video.