Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Infinite Scroll Up #2730

Merged
merged 1 commit into from
Feb 9, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions misc/tutorial/212_infinite_scroll.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,20 @@ Specify percentage when lazy load should trigger:
{ name:'name' },
{ name:'age' }
];
var page = 1;
var page = 0;
var pageUp = 0;
var getData = function(data, page) {
var res = [];
for (var i = 0; i < page * 100 && i < data.length; ++i) {
for (var i = (page * 100); i < (page + 1) * 100 && i < data.length; ++i) {
res.push(data[i]);
}
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;
Expand All @@ -51,14 +61,25 @@ Specify percentage when lazy load should trigger:
gridApi.infiniteScroll.on.needLoadMoreData($scope,function(){
$http.get('/data/10000_complex.json')
.success(function(data) {
$scope.gridOptions.data = getData(data, page);
$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();
});
});
};
}]);
</file>
Expand Down
35 changes: 27 additions & 8 deletions src/features/infinite-scroll/js/infinite-scroll.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*
* @description Service for infinite scroll features
*/
module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', function (gridUtil, $compile, $timeout) {
module.service('uiGridInfiniteScrollService', ['gridUtil', '$compile', '$timeout', 'uiGridConstants', function (gridUtil, $compile, $timeout, uiGridConstants) {

var service = {

Expand Down Expand Up @@ -50,6 +50,17 @@
*/

needLoadMoreData: function ($scope, fn) {
},

/**
* @ngdoc event
* @name needLoadMoreDataTop
* @eventOf ui.grid.infiniteScroll.api:PublicAPI
* @description This event fires when scroll reached top percentage of grid
* and needs to load data
*/

needLoadMoreDataTop: function ($scope, fn) {
}
}
},
Expand Down Expand Up @@ -99,12 +110,16 @@
* @ngdoc function
* @name loadData
* @methodOf ui.grid.infiniteScroll.service:uiGridInfiniteScrollService
* @description This function fires 'needLoadMoreData' event
* @description This function fires 'needLoadMoreData' or 'needLoadMoreDataTop' event based on scrollDirection
*/

loadData: function (grid) {
grid.options.loadTimout = true;
grid.api.infiniteScroll.raise.needLoadMoreData();
grid.options.loadTimout = true;
if (grid.scrollDirection === uiGridConstants.scrollDirection.UP) {
grid.api.infiniteScroll.raise.needLoadMoreDataTop();
return;
}
grid.api.infiniteScroll.raise.needLoadMoreData();
},

/**
Expand Down Expand Up @@ -196,10 +211,14 @@
link: function ($scope, $elm, $attr){
if ($scope.grid.options.enableInfiniteScroll) {
$scope.grid.api.core.on.scrollEvent($scope, function (args) {
if (args.y) {
var percentage = 100 - (args.y.percentage * 100);
uiGridInfiniteScrollService.checkScroll($scope.grid, percentage);
}
//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);
}
});
}
}
Expand Down
24 changes: 19 additions & 5 deletions src/features/infinite-scroll/test/infiniteScroll.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
var uiGridInfiniteScrollService;
var grid;
var gridClassFactory;
var uiGridConstants;

beforeEach(module('ui.grid.infiniteScroll'));

beforeEach(inject(function (_uiGridInfiniteScrollService_, _gridClassFactory_) {
beforeEach(inject(function (_uiGridInfiniteScrollService_, _gridClassFactory_, _uiGridConstants_) {
uiGridInfiniteScrollService = _uiGridInfiniteScrollService_;
gridClassFactory = _gridClassFactory_;
uiGridConstants = _uiGridConstants_;

grid = gridClassFactory.createGrid({});

Expand All @@ -24,11 +26,16 @@
gridApi.infiniteScroll.on.needLoadMoreData(function(){
return [];
});
};
gridApi.infiniteScroll.on.needLoadMoreDataTop(function(){
return [];
});

};

uiGridInfiniteScrollService.initializeGrid(grid);
spyOn(grid.api.infiniteScroll.raise, 'needLoadMoreData');

spyOn(grid.api.infiniteScroll.raise, 'needLoadMoreData');
spyOn(grid.api.infiniteScroll.raise, 'needLoadMoreDataTop');

grid.options.data = [{col1:'a'},{col1:'b'}];

grid.buildColumns();
Expand All @@ -54,7 +61,14 @@
uiGridInfiniteScrollService.loadData(grid);
expect(grid.api.infiniteScroll.raise.needLoadMoreData).toHaveBeenCalled();
});
});

it('should call load data top function on grid event raise', function () {
grid.scrollDirection = uiGridConstants.scrollDirection.UP;
uiGridInfiniteScrollService.loadData(grid);
expect(grid.api.infiniteScroll.raise.needLoadMoreDataTop).toHaveBeenCalled();
});

});

});
})();
11 changes: 10 additions & 1 deletion src/js/core/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,16 @@

// TODO(c0bra): Create full list of these somehow. NOTE: do any allow a space before or after them?
CURRENCY_SYMBOLS: ['ƒ', '$', '£', '$', '¤', '¥', '៛', '₩', '₱', '฿', '₫'],


scrollDirection: {
UP: 'up',
DOWN: 'down',
LEFT: 'left',
RIGHT: 'right',
NONE: 'none'

},

dataChange: {
ALL: 'all',
EDIT: 'edit',
Expand Down
9 changes: 7 additions & 2 deletions src/js/core/directives/ui-grid-viewport.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
(function(){
'use strict';

angular.module('ui.grid').directive('uiGridViewport', ['gridUtil','ScrollEvent',
function(gridUtil, ScrollEvent) {
angular.module('ui.grid').directive('uiGridViewport', ['gridUtil','ScrollEvent','uiGridConstants',
function(gridUtil, ScrollEvent, uiGridConstants) {
return {
replace: true,
scope: {},
Expand Down Expand Up @@ -43,6 +43,9 @@
grid.flagScrollingHorizontally();
var xDiff = newScrollLeft - colContainer.prevScrollLeft;

if (xDiff > 0) { grid.scrollDirection = uiGridConstants.scrollDirection.RIGHT; }
if (xDiff < 0) { grid.scrollDirection = uiGridConstants.scrollDirection.LEFT; }

var horizScrollLength = (colContainer.getCanvasWidth() - colContainer.getViewportWidth());
if (horizScrollLength !== 0) {
horizScrollPercentage = newScrollLeft / horizScrollLength;
Expand All @@ -58,6 +61,8 @@
grid.flagScrollingVertically();
var yDiff = newScrollTop - rowContainer.prevScrollTop;

if (yDiff > 0 ) { grid.scrollDirection = uiGridConstants.scrollDirection.DOWN; }
if (yDiff < 0 ) { grid.scrollDirection = uiGridConstants.scrollDirection.UP; }

var vertScrollLength = rowContainer.getVerticalScrollLength();

Expand Down
35 changes: 33 additions & 2 deletions src/js/core/directives/ui-grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
'use strict';

angular.module('ui.grid').controller('uiGridController', ['$scope', '$element', '$attrs', 'gridUtil', '$q', 'uiGridConstants',
'$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile',
'$templateCache', 'gridClassFactory', '$timeout', '$parse', '$compile', 'ScrollEvent',
function ($scope, $elm, $attrs, gridUtil, $q, uiGridConstants,
$templateCache, gridClassFactory, $timeout, $parse, $compile) {
$templateCache, gridClassFactory, $timeout, $parse, $compile, ScrollEvent) {
// gridUtil.logDebug('ui-grid controller');

var self = this;
Expand Down Expand Up @@ -59,6 +59,23 @@
}
}

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 = [];
Expand Down Expand Up @@ -97,6 +114,20 @@
$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);
});
});
});
Expand Down
21 changes: 16 additions & 5 deletions src/js/core/factories/Grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,25 @@ angular.module('ui.grid')
* @description set to true when Grid is scrolling horizontally. Set to false via debounced method
*/
self.isScrollingHorizontally = false;


/**
* @ngdoc property
* @name scrollDirection
* @propertyOf ui.grid.class:Grid
* @description set one of the uiGridConstants.scrollDirection values (UP, DOWN, LEFT, RIGHT, NONE), which tells
* us which direction we are scrolling. Set to NONE via debounced method
*/
self.scrollDirection = uiGridConstants.scrollDirection.NONE;

var debouncedVertical = gridUtil.debounce(function () {
self.isScrollingVertically = false;
}, 300);
self.scrollDirection = uiGridConstants.scrollDirection.NONE;
}, 1000);

var debouncedHorizontal = gridUtil.debounce(function () {
self.isScrollingHorizontally = false;
}, 300);
self.scrollDirection = uiGridConstants.scrollDirection.NONE;
}, 1000);


/**
Expand Down Expand Up @@ -1853,7 +1864,7 @@ angular.module('ui.grid')
*/
Grid.prototype.refreshCanvas = function(buildStyles) {
var self = this;

if (buildStyles) {
self.buildStyles();
}
Expand Down Expand Up @@ -1969,7 +1980,7 @@ angular.module('ui.grid')

// gridUtil.logDebug('redrawing container', i);

container.adjustRows(null, container.prevScrolltopPercentage);
container.adjustRows(null, container.prevScrolltopPercentage, true);
container.adjustColumns(null, container.prevScrollleftPercentage);
}
};
Expand Down
47 changes: 39 additions & 8 deletions src/js/core/factories/GridRenderContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ angular.module('ui.grid')
scrollTop = (this.getCanvasHeight() - this.getCanvasWidth()) * scrollPercentage;
}

this.adjustRows(scrollTop, scrollPercentage);
this.adjustRows(scrollTop, scrollPercentage, false);

this.prevScrollTop = scrollTop;
this.prevScrolltopPercentage = scrollPercentage;
Expand All @@ -339,7 +339,7 @@ angular.module('ui.grid')
this.grid.queueRefresh();
};

GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage) {
GridRenderContainer.prototype.adjustRows = function adjustRows(scrollTop, scrollPercentage, postDataLoaded) {
var self = this;

var minRows = self.minRowsToRender();
Expand All @@ -359,22 +359,53 @@ angular.module('ui.grid')
if (rowIndex > maxRowIndex) {
rowIndex = maxRowIndex;
}

var newRange = [];
if (rowCache.length > self.grid.options.virtualizationThreshold) {
if (!(typeof(scrollTop) === 'undefined' || scrollTop === null)) {
// Have we hit the threshold going down?
if (self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
if (!self.grid.options.enableInfiniteScroll && self.prevScrollTop < scrollTop && rowIndex < self.prevRowScrollIndex + self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
return;
}
//Have we hit the threshold going up?
if (self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
if (!self.grid.options.enableInfiniteScroll && self.prevScrollTop > scrollTop && rowIndex > self.prevRowScrollIndex - self.grid.options.scrollThreshold && rowIndex < maxRowIndex) {
return;
}
}

var rangeStart = Math.max(0, rowIndex - self.grid.options.excessRows);
var rangeEnd = Math.min(rowCache.length, rowIndex + minRows + self.grid.options.excessRows);
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 (rowCache[i].entity.$$hashKey === self.renderedRows[findIndex].entity.$$hashKey) {
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 (rowCache[i].entity.$$hashKey === self.renderedRows[findIndex].entity.$$hashKey) {
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);
}

newRange = [rangeStart, rangeEnd];
}
Expand Down