【onsenui】無限スクロールを実装する
はじめに
今回やりたかったのはよくある無限スクロール。
リストの1番下までスクロールしたら次のデータを取得しにゆきます。
これをAngular + Onsen UIで実装したのでメモしておく。
データ数の多いリストはパフォーマンス的にons-lazy-repeatを使うとよいらしい。
そちらについてはこちらでも試してみた。
実装
テンプレート
HTMLはこんな感じで実装。ons-lazy-repeatを使った基本的な形。
リストの最下部に読込中アイコンを置いて、状態によって表示・非表示を切り替えるようにする。
<ons-page ng-controller="MainCtrl"> <ons-toolbar> <div class="center">リスト</div> </ons-toolbar> <ons-list> <ons-list-item ons-lazy-repeat="delegate"> {{ item.name }} </ons-list-item> </ons-list> <ons-row ng-if="progress"> <ons-col style="text-align:center;"> <ons-icon size="30px" spin icon="md-spinner"></ons-icon> </ons-col> </ons-row> </ons-page>
メイン処理
必要な処理としては以下
・APIに接続してデータを取得してくる
・1番下までスクロールしたらAPIに接続して次のデータを取得しにいく
1番下までスクロールしたかの判定はこんな感じ
.page__contentを対象にするのがポイントぽい
angular.module('sampleListApp') .controller('MainCtrl', function () { $('.page__content').on('scroll', function(e){ var elm = $(e.currentTarget); if (elm[0].scrollHeight <= elm.height() + elm.scrollTop()) { // ココに1番下までスクロールした時の処理を記述 } });
次はAPI接続部分
適当だけどAPIからはこんな感じのJSONが返ってくる想定
{ contents: [ {id:1, "アイテム1"}, {id:2, "アイテム2"}, {id:3, "アイテム3"}, ・・・ ] }
取得部分をfactoryとして外だし
angular.module('SampleApp') .factory("ApiManager", function($http) { return { callApi: function(offset, callback) { $http({ method: 'GET', url: "http://path/to/api?offset="+offset }).then(function successCallback(response) { callback(respons.contents); }, function errorCallback(response) { }); } }; });
で、完成形はこんな感じに
angular.module('sampleApp') .controller('MainCtrl', function ($scope, $http, ApiManager) { $scope.items = []; $scope.progress = true; ApiManager.callApi(0, function(contents) { $scope.items = contents; $scope.progress = false; }); $('.page__content').on('scroll', function(e){ var elm = $(e.currentTarget); if ($scope.progress == false && elm[0].scrollHeight <= elm.height() + elm.scrollTop()) { $scope.progress = true; ApiManager.callApi($scope.items.length, function(contents) { for (var i = 0; i < contents.length; i++) { $scope.items.push(contents[i]); } $scope.progress = false; }); } }); $scope.delegate = { configureItemScope: function(index, itemScope) { itemScope.item = $scope.items[index]; }, countItems: function() { return $scope.items.length; } }; });
また、ずらずらかいたけど以上です。