diff --git a/misc/tutorial/212_infinite_scroll.ngdoc b/misc/tutorial/212_infinite_scroll.ngdoc
index d8f184d9f4..44d26ed239 100644
--- a/misc/tutorial/212_infinite_scroll.ngdoc
+++ b/misc/tutorial/212_infinite_scroll.ngdoc
@@ -2,85 +2,104 @@
@name Tutorial: 212 Infinite scroll
@description
-The infinite scroll feature allows the user to lazy load their data to gridOptions.data
+The infinite scroll feature allows the user to lazy load their data to gridOptions.data.
-Specify percentage when lazy load should trigger:
-
- $scope.gridOptions.infiniteScroll = 20;
-
+Once you reach the top (or bottom) of your real data set, you can notify that no more pages exist
+up (or down), and infinite scroll will stop triggering events in that direction. You can also
+optionally tell us up-front that there are no more pages up through `infiniteScrollUp = true` or down through
+`infiniteScrollDown = true`, and we will never trigger
+pages in that direction. By default we assume you have pages down but not up.
+
+You can specify the percentage of the grid at which the infinite scroll will trigger a request for
+more data `infiniteScrollPercentage = 20`. By default we trigger when you are 20% away from the end of
+the grid (in either direction).
+
+We will raise a `needMoreData` or `needMoreDataTop` event, which you must listen to and respond to if
+you have told us that you have more data available. Once you have retrieved the data and added it to your
+data array (at the top if the event was `needMoreDataTop`), you need to call `dataLoaded` to tell us
+that you have loaded your data. Optionally, you can tell us that there is no more data, and we won't trigger
+further requests for more data in that direction.
+
+When you have loaded your data we will attempt to adjust the grid scroll to give the appearance of continuous
+scrolling. This is a little jumpy at present, largely because we work of percentages instead of a number of
+rows from the end. We basically assume that your user will have reached the end of the scroll (upwards or downwards)
+by the time the data comes back, and scroll the user to the beginning of the newly added data to reflect that. If
+your user has already scrolled a lot of pages, then they may not be at the end of the data (20% can be a long way).
+Ideally the API would change to a number of rows.
+
+Finally, we suppress the normal grid behaviour of propagating the scroll to the parent container when you reach the end
+if infinite scroll is enabled and there is still data in that direction.
@example
+In this example we have a data set that starts at page 2 of a 5 page data set. Each page is 100 records, so we start at
+record 200, and we can scroll up 2 pages, and scroll down 2 pages. You should see smooth scrolling as you move up, when
+you hit record zero a touchpad scroll should propagate to the parent page. You should also see smooth scrolling as you
+move down, and when you hit record 499 a touchpad scroll should propagate to the parent page.
+
var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.infiniteScroll']);
- app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
- $scope.gridOptions = {};
-
- /**
- * @ngdoc property
- * @name infiniteScrollPercentage
- * @propertyOf ui.grid.class:GridOptions
- * @description This setting controls at what percentage of the scroll more data
- * is requested by the infinite scroll
- */
- $scope.gridOptions.infiniteScrollPercentage = 15;
-
- $scope.gridOptions.columnDefs = [
- { name:'id'},
- { name:'name' },
- { name:'age' }
- ];
- var page = 0;
- var pageUp = 0;
- var getData = function(data, page) {
- var res = [];
- for (var i = (page * 100); i < (page + 1) * 100 && i < data.length; ++i) {
- res.push(data[i]);
+ app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
+ $scope.gridOptions = {
+ infiniteScrollPercentage: 15,
+ infiniteScrollUp: true,
+ infiniteScrollDown: true,
+ columnDefs: [
+ { name:'id'},
+ { name:'name' },
+ { name:'age' }
+ ],
+ data: 'data',
+ onRegisterApi: function(gridApi){
+ gridApi.infiniteScroll.on.needLoadMoreData($scope, $scope.getDataDown);
+ gridApi.infiniteScroll.on.needLoadMoreDataTop($scope, $scope.getDataUp);
+ $scope.gridApi = gridApi;
}
- return res;
};
- var getDataUp = function(data, page) {
- var res = [];
- for (var i = data.length - (page * 100) - 1; (data.length - i) < ((page + 1) * 100) && (data.length - i) > 0; --i) {
- data[i].id = -(data.length - data[i].id)
- res.push(data[i]);
- }
- return res;
+ $scope.data = [];
+
+ var firstPage = 2;
+ var lastPage = 1;
+
+ $scope.getDataDown = function() {
+ $http.get('/data/10000_complex.json')
+ .success(function(data) {
+ lastPage++;
+ var newData = $scope.getPage(data, lastPage);
+ $scope.data = $scope.data.concat(newData);
+ $scope.gridApi.infiniteScroll.dataLoaded(null, lastPage === 4);
+ })
+ .error(function(error) {
+ $scope.gridApi.infiniteScroll.dataLoaded();
+ });
};
- $http.get('/data/10000_complex.json')
+ $scope.getDataUp = function() {
+ $http.get('/data/10000_complex.json')
.success(function(data) {
- $scope.gridOptions.data = getData(data, page);
- ++page;
+ firstPage--;
+ var newData = $scope.getPage(data, firstPage);
+ $scope.data = newData.concat($scope.data);
+ $scope.gridApi.infiniteScroll.dataLoaded(firstPage === 0, null);
+ })
+ .error(function(error) {
+ $scope.gridApi.infiniteScroll.dataLoaded();
});
+ };
- $scope.gridOptions.onRegisterApi = function(gridApi){
- gridApi.infiniteScroll.on.needLoadMoreData($scope,function(){
- $http.get('/data/10000_complex.json')
- .success(function(data) {
- $scope.gridOptions.data = $scope.gridOptions.data.concat(getData(data, page));
- ++page;
- gridApi.infiniteScroll.dataLoaded();
- })
- .error(function() {
- gridApi.infiniteScroll.dataLoaded();
- });
- });
- gridApi.infiniteScroll.on.needLoadMoreDataTop($scope,function(){
- $http.get('/data/10000_complex.json')
- .success(function(data) {
- $scope.gridOptions.data = getDataUp(data, pageUp).reverse().concat($scope.gridOptions.data);
- ++pageUp;
- gridApi.infiniteScroll.dataLoaded();
- })
- .error(function() {
- gridApi.infiniteScroll.dataLoaded();
- });
- });
+
+ $scope.getPage = function(data, page) {
+ var res = [];
+ for (var i = (page * 100); i < (page + 1) * 100 && i < data.length; ++i) {
+ res.push(data[i]);
+ }
+ return res;
};
+
+ $scope.getDataDown();
}]);
diff --git a/src/features/infinite-scroll/js/infinite-scroll.js b/src/features/infinite-scroll/js/infinite-scroll.js
index bd90ae8747..06ba5b6e3a 100644
--- a/src/features/infinite-scroll/js/infinite-scroll.js
+++ b/src/features/infinite-scroll/js/infinite-scroll.js
@@ -17,7 +17,7 @@
*
* @description Service for infinite scroll features
*/
- module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', 'uiGridConstants', function (gridUtil, $compile, $timeout, uiGridConstants) {
+ module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', 'uiGridConstants', 'ScrollEvent', function (gridUtil, $compile, $timeout, uiGridConstants, ScrollEvent) {
var service = {
@@ -28,8 +28,24 @@
* @description This method register events and methods into grid public API
*/
- initializeGrid: function(grid) {
+ initializeGrid: function(grid, $scope) {
service.defaultGridOptions(grid.options);
+ grid.infiniteScroll = { dataLoading: false, scrollUp: grid.options.infiniteScrollUp, scrollDown: grid.options.infiniteScrollDown };
+
+ if ( grid.options.infiniteScrollUp){
+ grid.suppressParentScrollUp = true;
+ }
+
+ if ( grid.options.infiniteScrollDown){
+ grid.suppressParentScrollDown = true;
+ }
+
+ if (grid.options.enableInfiniteScroll) {
+ grid.api.core.on.scrollEvent($scope, service.handleScroll);
+ }
+
+ // tweak the scroll for infinite scroll up (if enabled)
+ service.adjustScroll(grid);
/**
* @ngdoc object
@@ -45,7 +61,7 @@
* @ngdoc event
* @name needLoadMoreData
* @eventOf ui.grid.infiniteScroll.api:PublicAPI
- * @description This event fires when scroll reached bottom percentage of grid
+ * @description This event fires when scroll reaches bottom percentage of grid
* and needs to load data
*/
@@ -56,7 +72,7 @@
* @ngdoc event
* @name needLoadMoreDataTop
* @eventOf ui.grid.infiniteScroll.api:PublicAPI
- * @description This event fires when scroll reached top percentage of grid
+ * @description This event fires when scroll reaches top percentage of grid
* and needs to load data
*/
@@ -71,20 +87,40 @@
* @ngdoc function
* @name dataLoaded
* @methodOf ui.grid.infiniteScroll.api:PublicAPI
- * @description This function is used as a promise when data finished loading.
- * See infinite_scroll ngdoc for example of usage
+ * @description Call this function when you have loaded the additional data
+ * requested. You can set noMoreDataTop or noMoreDataBottom to indicate
+ * that we've reached the end of your data set, we won't fire any more events
+ * for scroll in that direction.
+ * See infinite_scroll tutorial for example of usage
+ * @param {boolean} noMoreDataTop flag that there are no more pages upwards, so don't fire
+ * any more infinite scroll events upward
+ * @param {boolean} noMoreDataBottom flag that there are no more pages downwards, so don't
+ * fire any more infinite scroll events downward
*/
- dataLoaded: function() {
- grid.options.loadTimout = false;
+ dataLoaded: function( noMoreDataTop, noMoreDataBottom ) {
+ grid.infiniteScroll.dataLoading = false;
+
+ if ( noMoreDataTop === true ){
+ grid.infiniteScroll.scrollUp = false;
+ grid.suppressParentScrollUp = false;
+ }
+
+ if ( noMoreDataBottom === true ){
+ grid.infiniteScroll.scrollDown = false;
+ grid.suppressParentScrollDown = false;
+ }
+
+ service.adjustScroll(grid);
}
}
}
};
- grid.options.loadTimout = false;
grid.api.registerEventsFromObject(publicApi.events);
grid.api.registerMethodsFromObject(publicApi.methods);
},
+
+
defaultGridOptions: function (gridOptions) {
//default option to true unless it was explicitly set to false
/**
@@ -103,6 +139,73 @@
*
Defaults to true
*/
gridOptions.enableInfiniteScroll = gridOptions.enableInfiniteScroll !== false;
+
+ /**
+ * @ngdoc property
+ * @name infiniteScrollPercentage
+ * @propertyOf ui.grid.class:GridOptions
+ * @description This setting controls at what percentage remaining more data
+ * is requested by the infinite scroll, whether scrolling up or down.
+ *
+ * TODO: it would be nice if this were percentage of a page, not percentage of the
+ * total scroll - as you get more and more data, the needMoreData event is triggered
+ * further and further away from the end (in terms of number of rows)
+ *
Defaults to 20
+ */
+ gridOptions.infiniteScrollPercentage = gridOptions.infiniteScrollPercentage || 20;
+
+ /**
+ * @ngdoc property
+ * @name infiniteScrollUp
+ * @propertyOf ui.grid.class:GridOptions
+ * @description Whether you allow infinite scroll up, implying that the first page of data
+ * you have displayed is in the middle of your data set. If set to true then we trigger the
+ * needMoreDataTop event when the user hits the top of the scrollbar.
+ *
Defaults to false
+ */
+ gridOptions.infiniteScrollUp = gridOptions.infiniteScrollUp === true;
+
+ /**
+ * @ngdoc property
+ * @name infiniteScrollDown
+ * @propertyOf ui.grid.class:GridOptions
+ * @description Whether you allow infinite scroll down, implying that the first page of data
+ * you have displayed is in the middle of your data set. If set to true then we trigger the
+ * needMoreData event when the user hits the bottom of the scrollbar.
+ *
Defaults to true
+ */
+ gridOptions.infiniteScrollDown = gridOptions.infiniteScrollDown !== false;
+ },
+
+
+ /**
+ * @ngdoc function
+ * @name handleScroll
+ * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
+ * @description Called whenever the grid scrolls, determines whether the scroll should
+ * trigger an infinite scroll request for more data
+ * @param {object} args the args from the event
+ */
+ handleScroll: function (args) {
+ // don't request data if already waiting for data, or if source is coming from ui.grid.adjustInfiniteScrollPosition() function
+ if ( args.grid.infiniteScroll && args.grid.infiniteScroll.dataLoading || args.source === 'ui.grid.adjustInfiniteScrollPosition' ){
+ return;
+ }
+
+ if (args.y) {
+ var percentage;
+ if (args.grid.scrollDirection === uiGridConstants.scrollDirection.UP ) {
+ percentage = args.y.percentage;
+ if (percentage <= args.grid.options.infiniteScrollPercentage / 100){
+ service.loadData(args.grid);
+ }
+ } else if (args.grid.scrollDirection === uiGridConstants.scrollDirection.DOWN) {
+ percentage = 1 - args.y.percentage;
+ if (percentage <= args.grid.options.infiniteScrollPercentage / 100){
+ service.loadData(args.grid);
+ }
+ }
+ }
},
@@ -111,43 +214,92 @@
* @name loadData
* @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
* @description This function fires 'needLoadMoreData' or 'needLoadMoreDataTop' event based on scrollDirection
+ * and whether there are more pages upwards or downwards
+ * @param {Grid} grid the grid we're working on
*/
-
loadData: function (grid) {
- grid.options.loadTimout = true;
- if (grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
+ // save number of currently visible rows to calculate new scroll position later - we know that we want
+ // to be at approximately the row we're currently at
+ grid.infiniteScroll.previousVisibleRows = grid.renderContainers.body.visibleRowCache.length;
+ grid.infiniteScroll.direction = grid.scrollDirection;
+
+ if (grid.scrollDirection === uiGridConstants.scrollDirection.UP && grid.infiniteScroll.scrollUp ) {
+ grid.infiniteScroll.dataLoading = true;
grid.api.infiniteScroll.raise.needLoadMoreDataTop();
- return;
+ } else if (grid.scrollDirection === uiGridConstants.scrollDirection.DOWN && grid.infiniteScroll.scrollDown ) {
+ grid.infiniteScroll.dataLoading = true;
+ grid.api.infiniteScroll.raise.needLoadMoreData();
}
- grid.api.infiniteScroll.raise.needLoadMoreData();
},
-
+
+
/**
* @ngdoc function
- * @name checkScroll
+ * @name adjustScroll
* @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
- * @description This function checks scroll position inside grid and
- * calls 'loadData' function when scroll reaches 'infiniteScrollPercentage'
+ * @description Once we are informed that data has been loaded, adjust the scroll position to account for that
+ * addition and to make things look clean.
+ *
+ * If we're scrolling up we scroll to the first row of the old data set -
+ * so we're assuming that you would have gotten to the top of the grid (from the 20% need more data trigger) by
+ * the time the data comes back. If we're scrolling down we scoll to the last row of the old data set - so we're
+ * assuming that you would have gotten to the bottom of the grid (from the 80% need more data trigger) by the time
+ * the data comes back.
+ *
+ * Neither of these are good assumptions, but making this a smoother experience really requires
+ * that trigger to not be a percentage, and to be much closer to the end of the data (say, 5 rows off the end). Even then
+ * it'd be better still to actually run into the end. But if the data takes a while to come back, they may have scrolled
+ * somewhere else in the mean-time, in which case they'll get a jump back to the new data. Anyway, this will do for
+ * now, until someone wants to do better.
+ * @param {Grid} grid the grid we're working on
*/
+ adjustScroll: function(grid){
+ $timeout(function () {
+ var percentage;
+
+ if ( grid.infiniteScroll.direction === undefined ){
+ // called from initialize, tweak our scroll up a little
+ service.adjustInfiniteScrollPosition(grid, 0);
+ }
- checkScroll: function(grid, scrollTop) {
+ var newVisibleRows = grid.renderContainers.body.visibleRowCache.length;
+ if ( grid.infiniteScroll.direction === uiGridConstants.scrollDirection.UP ){
+ percentage = ( newVisibleRows - grid.infiniteScroll.previousVisibleRows ) / newVisibleRows;
+ service.adjustInfiniteScrollPosition(grid, percentage);
+ }
- /* Take infiniteScrollPercentage value or use 20% as default */
- var infiniteScrollPercentage = grid.options.infiniteScrollPercentage ? grid.options.infiniteScrollPercentage : 20;
+ if ( grid.infiniteScroll.direction === uiGridConstants.scrollDirection.DOWN ){
+ percentage = grid.infiniteScroll.previousVisibleRows / newVisibleRows;
+ service.adjustInfiniteScrollPosition(grid, percentage);
+ }
+ }, 0);
+ },
+
+
+ /**
+ * @ngdoc function
+ * @name adjustInfiniteScrollPosition
+ * @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
+ * @description This function fires 'needLoadMoreData' or 'needLoadMoreDataTop' event based on scrollDirection
+ * @param {Grid} grid the grid we're working on
+ * @param {number} percentage the percentage through the grid that we want to scroll to
+ */
+ adjustInfiniteScrollPosition: function (grid, percentage) {
+ var scrollEvent = new ScrollEvent(grid, null, null, 'ui.grid.adjustInfiniteScrollPosition');
- if (!grid.options.loadTimout && scrollTop <= infiniteScrollPercentage) {
- this.loadData(grid);
- return true;
+ //for infinite scroll, if there are pages upwards then never allow it to be at the zero position so the up button can be active
+ if ( percentage === 0 && grid.infiniteScroll.scrollUp ) {
+ scrollEvent.y = {pixels: 1};
}
- return false;
+ else {
+ scrollEvent.y = {percentage: percentage};
+ }
+ scrollEvent.fireScrollingEvent();
}
- /**
- * @ngdoc property
- * @name infiniteScrollPercentage
- * @propertyOf ui.grid.class:GridOptions
- * @description This setting controls at what percentage of the scroll more data
- * is requested by the infinite scroll
- */
+
+
+
+
};
return service;
}]);
@@ -193,7 +345,7 @@
compile: function($scope, $elm, $attr){
return {
pre: function($scope, $elm, $attr, uiGridCtrl) {
- uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid);
+ uiGridInfiniteScrollService.initializeGrid(uiGridCtrl.grid, $scope);
},
post: function($scope, $elm, $attr) {
}
@@ -202,26 +354,4 @@
};
}]);
- module.directive('uiGridViewport',
- ['$compile', 'gridUtil', 'uiGridInfiniteScrollService', 'uiGridConstants',
- function ($compile, gridUtil, uiGridInfiniteScrollService, uiGridConstants) {
- return {
- priority: -200,
- scope: false,
- link: function ($scope, $elm, $attr){
- if ($scope.grid.options.enableInfiniteScroll) {
- $scope.grid.api.core.on.scrollEvent($scope, function (args) {
- //Prevent circular scroll references, if source is coming from ui.grid.adjustInfiniteScrollPosition() function
- if (args.y && (args.source !== 'ui.grid.adjustInfiniteScrollPosition')) {
- var percentage = 100 - (args.y.percentage * 100);
- if ($scope.grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
- percentage = (args.y.percentage * 100);
- }
- uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
- }
- });
- }
- }
- };
- }]);
})();
\ No newline at end of file
diff --git a/src/features/infinite-scroll/test/infiniteScroll.spec.js b/src/features/infinite-scroll/test/infiniteScroll.spec.js
index dd9af5c09e..b978ad5f99 100644
--- a/src/features/infinite-scroll/test/infiniteScroll.spec.js
+++ b/src/features/infinite-scroll/test/infiniteScroll.spec.js
@@ -1,74 +1,112 @@
/* global _ */
(function () {
- 'use strict';
- describe('ui.grid.infiniteScroll uiGridInfiniteScrollService', function () {
+ 'use strict';
+ describe('ui.grid.infiniteScroll uiGridInfiniteScrollService', function () {
- var uiGridInfiniteScrollService;
- var grid;
- var gridClassFactory;
+ var uiGridInfiniteScrollService;
+ var grid;
+ var gridClassFactory;
var uiGridConstants;
+ var $rootScope;
+ var $scope;
- beforeEach(module('ui.grid.infiniteScroll'));
+ beforeEach(module('ui.grid.infiniteScroll'));
- beforeEach(inject(function (_uiGridInfiniteScrollService_, _gridClassFactory_, _uiGridConstants_) {
- uiGridInfiniteScrollService = _uiGridInfiniteScrollService_;
- gridClassFactory = _gridClassFactory_;
+ beforeEach(inject(function (_uiGridInfiniteScrollService_, _gridClassFactory_, _uiGridConstants_, _$rootScope_) {
+ uiGridInfiniteScrollService = _uiGridInfiniteScrollService_;
+ gridClassFactory = _gridClassFactory_;
uiGridConstants = _uiGridConstants_;
-
- grid = gridClassFactory.createGrid({});
-
- grid.options.columnDefs = [
- {field: 'col1'}
- ];
- grid.options.infiniteScroll = 20;
-
- grid.options.onRegisterApi = function (gridApi) {
- gridApi.infiniteScroll.on.needLoadMoreData(function(){
- return [];
- });
- gridApi.infiniteScroll.on.needLoadMoreDataTop(function(){
- return [];
- });
-
- };
-
- uiGridInfiniteScrollService.initializeGrid(grid);
+ $rootScope = _$rootScope_;
+ $scope = $rootScope.$new();
+
+ grid = gridClassFactory.createGrid({});
+
+ grid.options.columnDefs = [
+ {field: 'col1'}
+ ];
+ grid.options.infiniteScrollPercentage = 20;
+
+ uiGridInfiniteScrollService.initializeGrid(grid, $scope);
spyOn(grid.api.infiniteScroll.raise, 'needLoadMoreData');
spyOn(grid.api.infiniteScroll.raise, 'needLoadMoreDataTop');
- grid.options.data = [{col1:'a'},{col1:'b'}];
+ grid.options.data = [{col1:'a'},{col1:'b'}];
- grid.buildColumns();
+ grid.buildColumns();
- }));
+ }));
- describe('event handling', function () {
- it('should return false if scrollTop is positioned more than 20% of scrollHeight', function() {
- var scrollHeight = 100;
- var scrollTop = 80;
- var callResult = uiGridInfiniteScrollService.checkScroll(grid, scrollTop);
- expect(callResult).toBe(false);
- });
+ describe('event handling', function () {
+ beforeEach(function() {
+ spyOn(uiGridInfiniteScrollService, 'loadData').andCallFake(function() {});
+ });
+
+ it('should not request more data if scroll up to 21%', function() {
+ grid.scrollDirection = uiGridConstants.scrollDirection.UP;
+ uiGridInfiniteScrollService.handleScroll( { grid: grid, y: { percentage: 0.21 }});
+ expect(uiGridInfiniteScrollService.loadData).not.toHaveBeenCalled();
+ });
- it('should return false if scrollTop is positioned less than 20% of scrollHeight', function() {
- var scrollHeight = 100;
- var scrollTop = 19;
- var callResult = uiGridInfiniteScrollService.checkScroll(grid, scrollTop);
- expect(callResult).toBe(true);
- });
+ it('should request more data if scroll up to 20%', function() {
+ grid.scrollDirection = uiGridConstants.scrollDirection.UP;
+ uiGridInfiniteScrollService.handleScroll( { grid: grid, y: { percentage: 0.20 }});
+ expect(uiGridInfiniteScrollService.loadData).toHaveBeenCalled();
+ });
- it('should call load data function on grid event raise', function () {
- uiGridInfiniteScrollService.loadData(grid);
- expect(grid.api.infiniteScroll.raise.needLoadMoreData).toHaveBeenCalled();
- });
+ it('should not request more data if scroll down to 79%', function() {
+ grid.scrollDirection = uiGridConstants.scrollDirection.DOWN;
+ uiGridInfiniteScrollService.handleScroll( {grid: grid, y: { percentage: 0.79 }});
+ expect(uiGridInfiniteScrollService.loadData).not.toHaveBeenCalled();
+ });
- it('should call load data top function on grid event raise', function () {
+ it('should request more data if scroll down to 80%', function() {
+ grid.scrollDirection = uiGridConstants.scrollDirection.DOWN;
+ uiGridInfiniteScrollService.handleScroll( { grid: grid, y: { percentage: 0.80 }});
+ expect(uiGridInfiniteScrollService.loadData).toHaveBeenCalled();
+ });
+ });
+
+ describe('loadData', function() {
+ it('scroll up and there is data up', function() {
grid.scrollDirection = uiGridConstants.scrollDirection.UP;
+ grid.infiniteScroll.scrollUp = true;
+
uiGridInfiniteScrollService.loadData(grid);
+
expect(grid.api.infiniteScroll.raise.needLoadMoreDataTop).toHaveBeenCalled();
+ expect(grid.infiniteScroll.previousVisibleRows).toEqual(0);
+ expect(grid.infiniteScroll.direction).toEqual(uiGridConstants.scrollDirection.UP);
});
+ it('scroll up and there isn\'t data up', function() {
+ grid.scrollDirection = uiGridConstants.scrollDirection.UP;
+ grid.infiniteScroll.scrollUp = false;
+
+ uiGridInfiniteScrollService.loadData(grid);
+
+ expect(grid.api.infiniteScroll.raise.needLoadMoreDataTop).not.toHaveBeenCalled();
+ });
+
+ it('scroll down and there is data down', function() {
+ grid.scrollDirection = uiGridConstants.scrollDirection.DOWN;
+ grid.infiniteScroll.scrollDown = true;
+
+ uiGridInfiniteScrollService.loadData(grid);
+
+ expect(grid.api.infiniteScroll.raise.needLoadMoreData).toHaveBeenCalled();
+ expect(grid.infiniteScroll.previousVisibleRows).toEqual(0);
+ expect(grid.infiniteScroll.direction).toEqual(uiGridConstants.scrollDirection.DOWN);
+ });
+
+ it('scroll down and there isn\'t data down', function() {
+ grid.scrollDirection = uiGridConstants.scrollDirection.DOWN;
+ grid.infiniteScroll.scrollDown = false;
+
+ uiGridInfiniteScrollService.loadData(grid);
+
+ expect(grid.api.infiniteScroll.raise.needLoadMoreData).not.toHaveBeenCalled();
+ });
});
- });
+ });
})();
\ No newline at end of file
diff --git a/src/js/core/directives/ui-grid.js b/src/js/core/directives/ui-grid.js
index 4608370b2c..a6cf821597 100644
--- a/src/js/core/directives/ui-grid.js
+++ b/src/js/core/directives/ui-grid.js
@@ -2,9 +2,9 @@
'use strict';
angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
- '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile', 'ScrollEvent',
+ '$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
- $templateCache, gridClassFactory, $timeout, $parse, $compile, ScrollEvent) {
+ $templateCache, gridClassFactory, $timeout, $parse, $compile) {
// gridUtil.logDebug('ui-grid controller');
var self = this;
@@ -59,23 +59,6 @@
}
}
- function adjustInfiniteScrollPosition (scrollToRow) {
-
- var scrollEvent = new ScrollEvent(self.grid, null, null, 'ui.grid.adjustInfiniteScrollPosition');
- var totalRows = self.grid.renderContainers.body.visibleRowCache.length;
- var percentage = ( scrollToRow + ( scrollToRow / ( totalRows - 1 ) ) ) / totalRows;
-
- //for infinite scroll, never allow it to be at the zero position so the up button can be active
- if ( percentage === 0 ) {
- scrollEvent.y = {pixels: 1};
- }
- else {
- scrollEvent.y = {percentage: percentage};
- }
- scrollEvent.fireScrollingEvent();
-
- }
-
function dataWatchFunction(newData) {
// gridUtil.logDebug('dataWatch fired');
var promises = [];
@@ -114,20 +97,6 @@
$scope.$evalAsync(function() {
self.grid.refreshCanvas(true);
self.grid.callDataChangeCallbacks(uiGridConstants.dataChange.ROW);
-
- $timeout(function () {
- //Process post load scroll events if using infinite scroll
- if ( self.grid.options.enableInfiniteScroll ) {
- //If first load, seed the scrollbar down a little to activate the button
- if ( self.grid.renderContainers.body.prevRowScrollIndex === 0 ) {
- adjustInfiniteScrollPosition(0);
- }
- //If we are scrolling up, we need to reseed the grid.
- if (self.grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
- adjustInfiniteScrollPosition(self.grid.renderContainers.body.prevRowScrollIndex + 1 + self.grid.options.excessRows);
- }
- }
- }, 0);
});
});
});
diff --git a/src/js/core/factories/GridRenderContainer.js b/src/js/core/factories/GridRenderContainer.js
index 495b3eeaa4..7c39c73545 100644
--- a/src/js/core/factories/GridRenderContainer.js
+++ b/src/js/core/factories/GridRenderContainer.js
@@ -364,48 +364,19 @@ angular.module('ui.grid')
if (rowCache.length > self.grid.options.virtualizationThreshold) {
if (!(typeof(scrollTop) === 'undefined' || scrollTop === null)) {
// Have we hit the threshold going down?
- if (!self.grid.options.enableInfiniteScroll && self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
+ if ( !self.grid.suppressParentScrollDown && self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
return;
}
//Have we hit the threshold going up?
- if (!self.grid.options.enableInfiniteScroll && self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
+ if ( !self.grid.suppressParentScrollUp && self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
return;
}
}
var rangeStart = {};
var rangeEnd = {};
- //If infinite scroll is enabled, and we loaded more data coming from redrawInPlace, then recalculate the range and set rowIndex to proper place to scroll to
- if ( self.grid.options.enableInfiniteScroll && self.grid.scrollDirection !== uiGridConstants.scrollDirection.NONE && postDataLoaded ) {
- var findIndex = null;
- var i = null;
- if ( self.grid.scrollDirection === uiGridConstants.scrollDirection.UP ) {
- findIndex = rowIndex > 0 ? self.grid.options.excessRows : 0;
- for ( i = 0; i < rowCache.length; i++) {
- if (self.grid.options.rowIdentity(rowCache[i].entity) === self.grid.options.rowIdentity(self.renderedRows[findIndex].entity)) {
- rowIndex = i;
- break;
- }
- }
- rangeStart = Math.max(0, rowIndex);
- rangeEnd = Math.min(rowCache.length, rangeStart + self.grid.options.excessRows + minRows);
- }
- else if ( self.grid.scrollDirection === uiGridConstants.scrollDirection.DOWN ) {
- findIndex = minRows;
- for ( i = 0; i < rowCache.length; i++) {
- if (self.grid.options.rowIdentity(rowCache[i].entity) === self.grid.options.rowIdentity(self.renderedRows[findIndex].entity)) {
- rowIndex = i;
- break;
- }
- }
- rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows - minRows);
- rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
- }
- }
- else {
- rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
- rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
- }
+ rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
+ rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
newRange = [rangeStart, rangeEnd];
}