OnsenUI | Working With Pull To Refresh

Written by on April 9, 2015

OnsenUI | Working With Pull To Refresh

Pull To Refresh is another functionality made popular by the advent of mobile devices. Where Infinite Scroller works from the bottom, Pull To Refresh works from the top. The idea is to pull new data from the top of the page on vertical swipe, a loader should appear, and new content should become visible, simple as that.

OnsenUI supports this feature through the ons-pull-hook directive. This article will also use another framework called Faker.js; it will generate fake data required to populate a list view in our example. We will call it again each time we initialize pull-to-refresh functionality.

Note: If this tutorial was helpful, you need further clarification, something is not working or you have a request for another Ionic post? Furthermore, leave me a comment below if you don't like something about this blog, if something is bugging you, don't like how I'm doing stuff here. Feel free to comment below, subscribe to my blog, mail me to dragan.gaic@gmail.com. Thanks and have a nice day!

Table of Contents

[spoiler title=” Click here if you want to see other tutorials, this is the 12th tutorial out of 12 total.”]

[/spoiler]

Intro

<ons-pull-hook ng-action="load($done)" var="loader">
    <span ng-switch="loader.getCurrentState()">
        <span ng-switch-when="initial"><ons-icon size="35px" icon="ion-arrow-down-a"></ons-icon> Pull down to refresh</span>
        <span ng-switch-when="preaction"><ons-icon size="35px" icon="ion-arrow-up-a"></ons-icon> Release to refresh</span>
        <span ng-switch-when="action"><ons-icon size="35px" spin="true" icon="ion-load-d"></ons-icon> Loading data...</span>
    </span>
</ons-pull-hook> 

The ons-pull-hook directive allows you to add pull-to-refresh functionality. Place it as the first child of your ons-page.

The expression you pass in for ng-action is the action associated with pulling down the element. Second expression var=”loader” is used to check to pull-to-refresh status, via ng-switch=”loader.getCurrentState()”.

$scope.load() is the function that implements the pull-to-refresh behavior and takes argument $done, a function that tells the application when the loading is completed.

Warning: Do not forget to wrap list elements into ons-list directive. The component loader will misbehave without it, showing beneath the last list element.

Example

A short walk through, when this example first initializes it will generate ten random list elements; every call to the ons-pull-hook function will produce one additional list item at the list top.

Demo

Embedded working example

OnsenUI Pull To Refresh Example

HTML

<html>

<head>
  <script src="https://code.angularjs.org/1.3.0/angular.js"></script>
  <script src="http://onsenui.io/OnsenUI/build/js/onsenui.js"></script>
  <script src="http://marak.com/faker.js/js/faker.js"></script>
  <script src="script.js"></script>
  <link rel="stylesheet" href="https://cdn.rawgit.com/OnsenUI/OnsenUI/1.2.2/build/css/onsenui.css" />
  <link rel="stylesheet" href="https://cdn.rawgit.com/OnsenUI/OnsenUI/1.2.2/build/css/onsen-css-components.css" />
</head>

<body ng-controller="ListCtrl">

  <ons-navigator animation="slide" var="app.navi">
    
    <ons-page>
      
      <ons-pull-hook ng-action="load($done)" var="loader">
        <span ng-switch="loader.getCurrentState()">
          <span ng-switch-when="initial"><ons-icon size="35px" icon="ion-arrow-down-a"></ons-icon> Pull down to refresh</span>
          <span ng-switch-when="preaction"><ons-icon size="35px" icon="ion-arrow-up-a"></ons-icon> Release to refresh</span>
          <span ng-switch-when="action"><ons-icon size="35px" spin="true" icon="ion-load-d"></ons-icon> Loading data...</span>
        </span>
      </ons-pull-hook>      
      
      <ons-toolbar class="toolbar-black">
        <div class="center">OnsenUI Infinite Scroll Example</div>
      </ons-toolbar>

      <ons-list>
        <ons-list-item class="list-item-container" ng-repeat="list in _list">
          <ons-row style="padding: 10px 10px 5px 0;">
            <ons-col width="145px">
              <img ng-src="{{list.image}}" class="thumbnail">
            </ons-col>
            <ons-col>
              <div style="height: 30px;">
                <h4>{{list.name}}</h4>
              </div>
              <div style="height: 30px; font-size: 13px;">
                <i class="fa fa-map-marker"></i> {{list.address}}
              </div>
              <div style="height: 30px; font-size: 13px;">
                <i class="fa fa-phone"></i> {{list.phone}}
              </div>
            </ons-col>
            <ons-col width="40px"></ons-col>
          </ons-row>
        </ons-list-item>
    </ons-list>

    </ons-page>
    
  </ons-navigator>


</body>

</html>

JavaScript

var module = ons.bootstrap('my-app', ['onsen']);

module.controller('ListCtrl', function($scope, $timeout) {
  
  $scope._list = [];  

  $scope.populateInitialList = function() {
    for (var i = 0; i <= 2; i++) {
      $scope.populateList();
    }    
  }
  
  $scope.load = function($done) {
    $timeout(function() {
      $scope.populateList();
      $done();
    }, 1000);
  };  
  
  $scope.populateList = function() {
      var firstName = faker.name.firstName();
      var lastName = faker.name.lastName();      
      
      $scope._list.unshift({ name: firstName + " " + lastName, 
                          address: faker.address.streetAddress(),
                          phone: faker.phone.phoneNumber(),
                          image: faker.internet.avatar()
      });
  }  

  $scope.populateInitialList();
  
});

Walkthrough

When ListCtrl controller first initializes it will create an empty _list object; we’ll use it to store application list data:

$scope._list = [];  

JavaScript will immediately populate it using a function call:

$scope.populateInitialList();

Application is calling these functions:

  $scope.populateInitialList = function() {
    for (var i = 0; i <= 2; i++) {
      $scope.populateList();
    }    
  }

  $scope.populateList = function() {
      var firstName = faker.name.firstName();
      var lastName = faker.name.lastName();      
      
      $scope._list.unshift({ name: firstName + " " + lastName, 
                          address: faker.address.streetAddress(),
                          phone: faker.phone.phoneNumber(),
                          image: faker.internet.avatar()
      });
  } 

Initially it will generate ten fake list elements using Faker.js.

Above list directive you’ll find pull-to-refresh directive:

<ons-pull-hook ng-action="load($done)" var="loader">
    <span ng-switch="loader.getCurrentState()">
        <span ng-switch-when="initial"><ons-icon size="35px" icon="ion-arrow-down-a"></ons-icon> Pull down to refresh</span>
        <span ng-switch-when="preaction"><ons-icon size="35px" icon="ion-arrow-up-a"></ons-icon> Release to refresh</span>
        <span ng-switch-when="action"><ons-icon size="35px" spin="true" icon="ion-load-d"></ons-icon> Loading data...</span>
    </span>
</ons-pull-hook> 

It’s configured to trigger a function load($done) when user uses pull-to-refresh component.

Timeout is required for successful pull request, any amount of time is good as long as it’s more than 0:

  $scope.load = function($done) {
    $timeout(function() {
      $scope.populateList();
      $done();
    }, 1000);
  }; 

After everything is done application needs to call a function that tells the pull-to-refresh component when the loading is completed:

$done();

Animation loader is placed inside the directive:

<span ng-switch="loader.getCurrentState()">
    <span ng-switch-when="initial"><ons-icon size="35px" icon="ion-arrow-down-a"></ons-icon> Pull down to refresh</span>
    <span ng-switch-when="preaction"><ons-icon size="35px" icon="ion-arrow-up-a"></ons-icon> Release to refresh</span>
    <span ng-switch-when="action"><ons-icon size="35px" spin="true" icon="ion-load-d"></ons-icon> Loading data...</span>
</span>

There are three potential loading states, each one associated with a customizable visual representation (initial, preaction, and action).

Who Am I?

Between working as a senior Java developer in one of the largest insurance companies in the world and traveling, in my free time, I work as a professional mobile development adviser. I'm also a major jQuery Mobile supporter back at StackOverflow and a forum moderator at the official Ionic Framework forum.



Categories

Leave a Reply