Understanding Ionic’s Infinite Scroll

posted in: Uncategorized | 12

With the rise of social networks, the “feed” has become a popular design pattern, especially in mobile apps. In a previous article, I showed how to use the pull to refresh to create a feed. Another staple of the feed is the idea of infinite scrolling which is loading in new items (typically older items) to the bottom of a list as the user scrolls.

The Ionic Framework has a directive to accomplish exactly this. In this post, we’ll break down a basic example of using this directive, a list, and the Random User API to see how to use the directive with example data (feel free to follow along on CodePen).

ion-infinite-scroll (Infinite Scroll Directive)

The Ionic directive we are going to use is the ion-infinite-scroll (Official Documentation). The most basic usage is as follows:

<ion-infinite-scroll on-infinite="loadMore()" distance="1%"></ion-infinite-scroll>

on-infinite should point to a $scope function that gets the new data, updates a list, and then lets the ion-infinite-scroll know it is done. This ion-infinite-scroll should be below some kind of list.

View

For our example, we’ll be using the following view markup:

<ion-list>
	<ion-item class="item-avatar" ng-repeat="item in items">
		<img src="{{item.user.picture.thumbnail}} " />
		<h2>{{item.user.name.first}} {{item.user.name.last}}</h2>
		<p>{{item.user.location.city}} {{item.user.password}}</p>
	</ion-item>
</ion-list>

<ion-infinite-scroll on-infinite="loadMore()" distance="5%"></ion-infinite-scroll>

Which looks something like this once rendered:

rendered list

Remember that this list iterates over the $scope.items array.

ng-repeat="item in items"

(Read more about views in Ionic Creating Views with Ionic)

Factory

In our example, we’re going to be making a call to the Random User API to get some data to play with. To do this, we’ll create a factory that makes these API calls. This factory will have two methods: GetFeed and GetNewUsers. GetFeed will be called when our app loads to get the initial data and the GetNewUsers will be called each time we need to load in new items for the infinite scroll.

.factory('PersonService', function($http){
	var BASE_URL = "http://api.randomuser.me/";
	var items = [];
	
	return {
		GetFeed: function(){
			return $http.get(BASE_URL+'?results=10').then(function(response){
				items = response.data.results;
				return items;
			});
		},
		GetNewUsers: function(){
			return $http.get(BASE_URL+'?results=10').then(function(response){
				items = response.data.results;
				return items;
			});
		}
	}
})

Both methods return 10 results.

(Read more about using factories: Ionic: Using Factories and Web Services for Dynamic Data)

Controller

Our controller needs to do 2 things:

  1. Fill the feed with the initial items
  2. Handle the infinite scroll

First, to fill our feed, we’ll want to make a call to the PersonService and assign the result to the $scope.items array:

.controller('MyCtrl', function($scope, $timeout, PersonService) {
	$scope.items = [];

	PersonService.GetFeed().then(function(items){
		$scope.items = items;
	});
});

Next, we need to handle the infinite scroll. Recall we configured our directive to call a loadMore function. We’ll need to define this function:

$scope.loadMore = function() {

}

In this function, we should call the GetNewUsers function and add these items to the end of the array.

$scope.loadMore = function() {
	PersonService.GetNewUsers().then(function(items){
		$scope.items = $scope.items.concat(items);
	});
};

You’ll notice we are using the array.concat function to add the items in. This is because items is an array, so we need to add the two arrays together.

We still need to do one final thing. We need to let the ion-infinite-scroll know that we’re done loading in the new items. To do this, we need to broadcast the scroll.infiniteScrollComplete event.

$scope.loadMore = function() {
	PersonService.GetNewUsers().then(function(items){
		$scope.items = $scope.items.concat(items);

		$scope.$broadcast('scroll.infiniteScrollComplete');
	});
};

In its entirety, our controller looks like this:

.controller('MyCtrl', function($scope, $timeout, PersonService) {
	$scope.items = [];

	PersonService.GetFeed().then(function(items){
		$scope.items = items;
	});

	$scope.loadMore = function() {
		PersonService.GetNewUsers().then(function(items){
			$scope.items = $scope.items.concat(items);

			$scope.$broadcast('scroll.infiniteScrollComplete');
		});
	};

});

(Read more about using controllers: Controllers in Ionic/Angular)

Conclusion

Using the code above (full code on CodePen), you can accomplish this common infinite scroll pattern in your Ionic Apps. Questions? Feel free to comment below!

My name is Andrew McGivery. I currently work full time as an application developer at Manulife Financial in Canada.

12 Responses

  1. Hi Andrew, i have followed the tutorial, and it show me the json feed, but when i scroll down it start from the beginning again and doesn’t stop loading feeds.

    Here you can see my json file, http://yanupla.com/apps/ligajaguares/json/gallery.json this is the only difference between your tutorial and my project.

    • This tutorial shows an example of setting up the frontend, not the backend. In practice, you would have an endpoint that you would send the ID of the last item you have in your list and the backend would send you the entries that come after that Id.

      • How can I make : endpoint that you would send the ID of the last item you have in your list and the backend would send you the entries that come after that Id.

        Please give the CodePen demo.

        • I’m not really sure what you’re looking for from me.

          What you’re asking is a fairly common and simple pattern… when you get the first set of results from your backend, save the ID of the last item to a private variable in your factory and then pass that id when you go to grab more results.

          Something like below… you’ll have to fill in the gaps.

          factory('factoryName',function($http){
          	var lastId;
          	
          	getSome: function(){
          		$http.get(...).then(function(response){
          			// etc
          			lastId = response.data[response.data.length-1].id;
          			
          			return response.data;
          		});
          	},
          	
          	getMore: function(){
          		$http.get("...lastId="+lastId).then(function(response){
          			// etc
          			lastId = response.data[response.data.length-1].id;
          			
          			return response.data;
          		});
          	}
          });
          

          Depending on your backend logic, you may also be able to combine these into one method.

  2. this help me a lot !! Thanks!!!!!!

  3. Soumen Naskar

    Hi Andrew, I have followed the tutorial, and use it in my app. But in my case the loadMore() method is called repeatedly on app load. my loadMore is like the following.

    $scope.loadMore = function() {
    var studentId = $scope.Student.Id;
    $scope.getArtifactCollection(studentId);
    $scope.$broadcast(‘scroll.infiniteScrollComplete’);
    }

    I have seen this issue in Ionic serve. Any help will be appreciated.

  4. I see in this exemple, the same problem i have, the first json call is alway called twice.
    If you look at the Chrome inspector in “Network”
    my problem is it call the json twice too on my infinite scroll.

  5. Hi. Nice Post. I have been across an issue where when I scroll to the bottom, the “loadMore()” method is called, and it is continuously called for as long as I do not change the scroll position. I tried logging the loadMore() method to console, and the console is filled with loadMore calls, tens and hundreds of it. And since my API returns the data, the list becomes infinitely long just after the first scroll (or first reaching to the bottom). I actually worked around the issue by returning all the calls to loadMore() but it is not great.
    What do you think? Is this an issue or am I doing something terribly wrong?

  6. Great post, thanks for your help !

  7. Great post! We are using infinite scroll as well with data from an API. What happens is that after the first 10 are loaded, the infinite scroll kicks in immediately. The same thing happens on your CodePen, initially you will have 20 items. Do you have any idea if this can be fixed?

    • Good catch!

      It appears when the page it loaded, it is triggering the infinite scroll right away since there haven’t been any items loaded in yet. One possible fix is to remove the part of code that is doing the initial loading and let the infinite scroll also handle the initial load.

Leave a Reply