Project Overview0:00
In this episode, we're building an infinite scroll feed with real-time filters and search. This is what it looks like. We have a posts feed with a limited set of posts loaded. But as I start scrolling towards the end, more and more posts load. That's how infinite scroll works. But now if I change the category, it scrolls back to the top stats again and it only continues to load the technology posts. If I search for something like design, it will obviously combine the two and if I've reached the end of the feed, it says you've reached the end. This is very useful for blog posts, news articles, even products, especially products display
reached the end of the feed, it says you've reached the end. This is very useful for blog posts, news articles, even products, especially products display with filters. So let's see how this is built. This is what we will be starting with. The same UI, everything looks the same, but there is no infinite scroll right now. Even the search doesn't work and none of this works as of now. So let's start from this one. Let's look at the LiveWire component. It might look like a lot, but it's all the simple stuff.
Let's look at the LiveWire component. It might look like a lot, but it's all the simple stuff. We have these public properties, the page number, how many posts per page you want to load, the categories and then this is important. We have posts as a computed property. We're just simply getting the posts per page here and we have a load more method. We're going to change this soon. Here's the entire UI. This is the header with the filters, search, category, dropdown and everything and this is where the posts list is simply looping through all the posts.
Adding Load More1:38
This is the header with the filters, search, category, dropdown and everything and this is where the posts list is simply looping through all the posts. All right. So let's start with a simple load more button that will load more posts when you click on it. So right after the for each loop, let me add the load more button. Okay. Just clicking on it will trigger load more. Now the load more method, what it does is currently this is just increasing the page number.
Now the load more method, what it does is currently this is just increasing the page number. Let's see what happens. So we have the posts, we have the load more posts. Now if I click on that, it replaces the existing page with the next page. So this is almost as good as next, right? But what we want is we want to append the number of posts with the ones that already existed in Livewire 3, there was no efficient way of doing this. So what people would do was they would just increase the per page number. So we could do this per page plus equals five.
So what people would do was they would just increase the per page number. So we could do this per page plus equals five. So now if I refresh and load more posts, note that it is loading more posts and these are new ones. So it's loading the next page. It does look like it's working great, but with every request you are querying more and more posts. So if you look at the network request here, let me open the network tab, just refresh once again and click on load more. Just notice it's 3.8 KB, load more again, it's 4.2 KB, it's 4.7.
Using Livewire Islands3:14
once again and click on load more. Just notice it's 3.8 KB, load more again, it's 4.2 KB, it's 4.7. Of course, it doesn't look like it's too much, but if you have images and a lot of other assets, this completely fails the point of infinite scrolling. So let me go back. With Livewire 4, there's this new islands feature, which makes this completely efficient. So let's go back and wrap this entire for each loop within an island. If you want to learn more about islands, you should watch the course by Caleb Posio, everything new in Livewire 4, right here on Laddercasts, so you could understand.
If you want to learn more about islands, you should watch the course by Caleb Posio, everything new in Livewire 4, right here on Laddercasts, so you could understand. So we just have an island here. You could give this a name, let's call it posts and let's end the island here. Now, when you click on this load more button, you can instruct Livewire to append the island using wireisland.append and you can specify the name of that island. That's it. It magically works. So let's go back up and also change the per page. Instead, this time we're going to just increase the page number because we're
So let's go back up and also change the per page. Instead, this time we're going to just increase the page number because we're getting the next set of posts and so on. We're not loading everything. Let's see. Refresh, load more posts. We have five more, load more. We have five more. Yes, it doesn't look like it has changed, but let's look at the network tab. Go to network, refresh, load more posts, look at the size.
Yes, it doesn't look like it has changed, but let's look at the network tab. Go to network, refresh, load more posts, look at the size. It's 2.5 KB, 2.5 KB again, 2.5 KB and it remains the same, which clearly shows it's only fetching five posts per request. So problem is solved. Now that it's working, let's replace this load more posts. We don't have to manually click it. Let's use intersection observer and load more automatically. Here, I will replace this button with a div. Let me remove this.
Auto-Loading on Scroll5:24
Here, I will replace this button with a div. Let me remove this. And instead of wire click, I will use wire intercite. So when the browser scrolls to that position, it will automatically trigger load more. Let me remove all these classes and simply add some padding so that there is a little space in the div. Let's see if this works. Refresh, let me scroll down and you can see. As in when we reach the bottom, just when we reach here, it will start loading more. Great.
As in when we reach the bottom, just when we reach here, it will start loading more. Great. But if this, this takes a little bit of time, we would like to see a loading spinner. So let's go back. So let me add a loading spinner here, which shows only while it is loading. And let me center this using flex, item center, justify center. And also these two could be inline flex. Yeah, this is just, you know, not so important stuff, but let me show you, and since the network request is too small right now, we won't be able to see this. Let's simulate it by adding a sleep so that we can verify it appears.
network request is too small right now, we won't be able to see this. Let's simulate it by adding a sleep so that we can verify it appears. Sleep for two seconds. Right. So yeah, now you can see loading more posts. It takes two seconds and this is great. So we have an infinite scroll working already. Now we just need to make it work along with the categories and the search. I already have added the query scopes in the model. Let me just show that to you.
Wiring Search Filters7:00
I already have added the query scopes in the model. Let me just show that to you. Post model. We have these category and search query scopes. Let's go back. Now let me add a public property search, public string search, and also for the public string search and also for the category, public string category. And when any of this is updated, let's add the public function updated. Yes. So if one of them is updated, then we would like to reset the page.
Yes. So if one of them is updated, then we would like to reset the page. We would like to use this render island method and re-render the entire island. And we would like to scroll back to the top because the user might have scrolled down 50 posts and then they get lost. So the moment we search or change the filters, we would like to smoothly scroll back to the top. And now let's also update, I'll remove sleep. I'll also update this with this. Yes, exactly.
I'll also update this with this. Yes, exactly. And the category. Okay. Now let's go to the search input and add wire model right here. Wire model live debounce. Perfect. Let's try the search first. Refresh. Let me search for, let's say technology.
Refresh. Let me search for, let's say technology. And yes, you can see that it is already working. Let's search for something else life or something more common D and yes, you can see that it's also triggering the intersection observer and we are still seeing only those posts that have the here. Okay. So that's great. It's working. Let's make the categories one work.
It's working. Let's make the categories one work. So right now clicking on it does nothing. So go back. Okay. Let's scroll down to the categories buttons. Yes. So when any of the button is clicked, we would like to update the category public property with this one. But if we click on the all categories button, we need to update it with blank.
public property with this one. But if we click on the all categories button, we need to update it with blank. So why your click set category is blank. Great. So let's also show the category here. So instead of directly showing all categories show the category, if it's not blank, otherwise we show all categories. All right, this should work. Let's see. Refresh and let me click on technology.
Let's see. Refresh and let me click on technology. Yes, we have technology. We have lifestyle. This is great. And along with that, we can also search by D so you'll see it's more smoothly scroll back up and now it's showing me only the lifestyle posts with the search query. The last and final thing we need to do is add a button here, a scroll to top button, which is really quick.
Finishing UI States10:03
The last and final thing we need to do is add a button here, a scroll to top button, which is really quick. Let me go back. Scroll down to the complete bottom. And just before closing the div, add this button. On click, it will just scroll to the top with a smooth behavior. And these are the styles. Let's see, let's refresh. And yes, we do see the scroll to top button. It works, but it's too annoying to see it as soon as you load the page, right?
And yes, we do see the scroll to top button. It works, but it's too annoying to see it as soon as you load the page, right? It's not required here to show this button only after the user scrolls a bit. We can, we can use Alpine. So let's first turn the parent div into an Alpine component. The very top one with X data. Yeah. Show scroll top, like show that button. It is false to start with. And while the user is scrolling, let's check that.
It is false to start with. And while the user is scrolling, let's check that. And if, if the scroll Y is greater than, let's say 500 pixels, then set this to true. Now we can use X show right here. X show is show scroll top. Perfect. Let's check now. Refresh. And you're able to see it after the user scrolls 500 pixels. Great.
And you're able to see it after the user scrolls 500 pixels. Great. One last thing. Now let's say I select a design category and I search for something like UI. I am not able to see that there is an end of feed. The intersection observer probably is still triggered and the user might expect that there are more posts if the network request is slow, especially. So it would be great to tell the user that they've reached the end. So wherever there is this load more method, let's check if there are more posts. If the number of posts returned is less than the per page, that is, if we want five
So wherever there is this load more method, let's check if there are more posts. If the number of posts returned is less than the per page, that is, if we want five per page, but it returned just two or even zero, then it dispatches an event end of feed. And once this is done, we can check this check for this event and show end of feed. So let me just scroll down to the bottom, wherever there's this intersection observer. I will, okay. This is not the load more button anymore. This is the intersection observer. Anyway, I will wrap this with an Alpine component, close the div where I say I start
This is the intersection observer. Anyway, I will wrap this with an Alpine component, close the div where I say I start with ended false. And once this event end of feed is fired, I set ended to true. And so I show this intersection observer only if it hasn't ended. Otherwise I show this paragraph which says you've reached the end. Okay. Let's test this. So once again, let me search for design and let's say UI. I'll scroll down and yeah, it says you've reached the end.
So once again, let me search for design and let's say UI. I'll scroll down and yeah, it says you've reached the end. This is great. We probably forgot to add one more thing. That is the empty field. Let's go back and yes, even before the island, let's add this empty state. So if posts is empty, we show an empty state else we show the island and the intersection observer. Once all of this ends, let's end the if. Yeah, this should work.
Once all of this ends, let's end the if. Yeah, this should work. Refresh, search for something. And yes, we do see the empty state and that's our complete infinite scroll with empty state, filters, search and so many other small details, including Livewire 4 islands feature. I hope you enjoyed this one.
