Sponsored By Kids In Touch

Trigger Pull To Refresh In Ionic Framework Apps

The Ionic Forum has a few posts about people wanting to programmatically trigger the pull to refresh feature in Ionic Framework apps. Who wouldn't want to do this, right? Since the PTR feature already provides great visual feedback to a user, why not use it to show the content is being loaded for the first time?

Unfortunately, I've never seen a working solution. I had pretty much given up on it because Firebase apps don't really need PTR. However, yesterday I found myself needing Pull To Refresh and went on a mission to solve it.

I didn't have to go far. Chris Pomerantz (cpomer on the forums) posted a solution without much fanfare back in November. I've taken his original solution and made it a little more portable.

tl;dr : Working sample at the bottom of the post.

First, we create a Pull to Refresh Service:

.service('PtrService', ['$timeout', '$ionicScrollDelegate', function($timeout, $ionicScrollDelegate) {

  /**
   * Trigger the pull-to-refresh on a specific scroll view delegate handle.
   * @param {string} delegateHandle - The `delegate-handle` assigned to the `ion-content` in the view.
   */
  this.triggerPtr = function(delegateHandle) {

    $timeout(function() {

      var scrollView = $ionicScrollDelegate.$getByHandle(delegateHandle).getScrollView();

      if (!scrollView) return;

      scrollView.__publish(
        scrollView.__scrollLeft, -scrollView.__refreshHeight,
        scrollView.__zoomLevel, true);

      var d = new Date();

      scrollView.refreshStartTime = d.getTime();

      scrollView.__refreshActive = true;
      scrollView.__refreshHidden = false;
      if (scrollView.__refreshShow) {
        scrollView.__refreshShow();
      }
      if (scrollView.__refreshActivate) {
        scrollView.__refreshActivate();
      }
      if (scrollView.__refreshStart) {
        scrollView.__refreshStart();
      }

    });

  }
}])

The view must have a delegate-handle assigned:

<ion-view view-title="PTR">  
  <ion-content delegate-handle="ptr-content">

    <ion-refresher on-refresh="doRefresh()">
    </ion-refresher>

    <ion-list>
      <ion-item ng-repeat="item in items">{{item}}</ion-item>
    </ion-list>
  </ion-content>
</ion-view>  

Now, we can inject the PtrService into any controller. When the view is loaded for the first time, we can trigger the PTR event with PtrService.triggerPtr('ptr-content');. You must include the delegate-handle from your view's <ion-content> directive.

.controller('PtrCtrl', ['$scope', '$timeout', 'PtrService', function($scope, $timeout, PtrService) {

  // Used to know whether to show ititial items or new items for a manual refresh
  var refreshed = false;

  // Start with an empty items array
  $scope.items = [];

  // When the view is loaded, trigger the PTR event.
  // Use the delegate handle name from the view.
  $scope.$on("$ionicView.loaded", function() {
    console.log("View loaded! Triggering PTR");
    PtrService.triggerPtr('ptr-content');
  })

  $scope.doRefresh = function() {

    console.log('Refreshing!');
    $timeout(function() {
      if (!refreshed) {
        $scope.items = ['Item 1', 'Item 2', 'Item 3'];
        refreshed = true;
      } else {

        //simulate async response
        $scope.items.push('New Item ' + Math.floor(Math.random() * 1000) + 4);

      }

      //Stop the ion-refresher from spinning
      $scope.$broadcast('scroll.refreshComplete');

    }, 1000);

  };

}])

Here's a working example:

See the Pen Trigger Pull To Refresh In Ionic Apps by Justin Noel (@calendee) on CodePen.