Skip to content

Commit 29418bf

Browse files
committed
feat(virtual-repeat): pass location state to scroll callback
1 parent b4492f8 commit 29418bf

File tree

3 files changed

+51
-6
lines changed

3 files changed

+51
-6
lines changed

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,20 @@ If you are running the plugin in the `skeleton-naviagion` project, make sure to
9898
```javascript
9999
export class MyVirtualList {
100100
items = ['Foo', 'Bar', 'Baz'];
101-
getMore() {
101+
getMore(topIndex, isAtBottom, isAtTop) {
102102
for(let i = 0; i < 100; ++i) {
103103
this.items.push('item' + i);
104104
}
105105
}
106106
}
107107
```
108108
The `virtual-repeat-next` attribute can accept a function, a promise, or a function that returns a promise.
109-
The bound function will be called when the scroll container has reached a point where there are no more items to move into the DOM (i.e. when it reaches the end of a list).
109+
The bound function will be called when the scroll container has reached a point where there are no more items to move into the DOM (i.e. when it reaches the end of a list, either from the top or the bottom).
110+
There are three parameters that are passed to the function (`getMore(topIndex, isAtBottom, isAtTop)`) which helps determine the behavior or amount of items to get during scrolling.
111+
1. `topIndex` - A integer value that represents the current item that exists at the top of the rendered items in the DOM.
112+
2. `isAtBottom` - A boolean value that indicates whether the list has been scrolled to the bottom of the items list.
113+
3. `isAtTop` - A boolean value that indicates whether the list has been scrolled to the top of the items list.
114+
110115

111116
## [Demo](http://aurelia.io/ui-virtualization/)
112117

src/virtual-repeat.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,9 @@ export class VirtualRepeat extends AbstractRepeater {
227227
this._lastRebind = this._first;
228228
let movedViewsCount = this._moveViews(viewsToMove);
229229
let adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
230-
this._getMore();
230+
if (viewsToMove > 0) {
231+
this._getMore();
232+
}
231233
this._switchedDirection = false;
232234
this._topBufferHeight = this._topBufferHeight + adjustHeight;
233235
this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
@@ -248,6 +250,9 @@ export class VirtualRepeat extends AbstractRepeater {
248250
let movedViewsCount = this._moveViews(viewsToMove);
249251
this.movedViewsCount = movedViewsCount;
250252
let adjustHeight = movedViewsCount < viewsToMove ? this._topBufferHeight : itemHeight * movedViewsCount;
253+
if (viewsToMove > 0) {
254+
this._getMore();
255+
}
251256
this._switchedDirection = false;
252257
this._topBufferHeight = this._topBufferHeight - adjustHeight;
253258
this._bottomBufferHeight = this._bottomBufferHeight + adjustHeight;
@@ -261,7 +266,7 @@ export class VirtualRepeat extends AbstractRepeater {
261266
}
262267

263268
_getMore(): void {
264-
if (this.isLastIndex) {
269+
if (this.isLastIndex || this._first === 0) {
265270
if (!this._calledGetMore) {
266271
let getMoreFunc = this.view(0).firstChild.getAttribute('virtual-repeat-next');
267272
if (!getMoreFunc) {
@@ -275,7 +280,7 @@ export class VirtualRepeat extends AbstractRepeater {
275280
this._calledGetMore = false; //Reset for the next time
276281
});
277282
} else if (typeof getMore === 'function') {
278-
let result = getMore.bind(this.scope.overrideContext.bindingContext)();
283+
let result = getMore.bind(this.scope.overrideContext.bindingContext)(this._first, this._bottomBufferHeight === 0, this._isAtTop);
279284
if (!(result instanceof Promise)) {
280285
this._calledGetMore = false; //Reset for the next time
281286
} else {

test/virtual-repeat-integration.spec.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ describe('VirtualRepeat Integration', () => {
107107
});
108108
}
109109

110+
function validateScrollUp(done) {
111+
let elem = document.getElementById('scrollContainer');
112+
let event = new Event('scroll');
113+
elem.scrollTop = elem.scrollHeight/2; //Scroll down but not far enough to reach bottom and call 'getNext'
114+
elem.dispatchEvent(event);
115+
window.setTimeout(()=>{
116+
window.requestAnimationFrame(() => {
117+
let eventUp = new Event('scroll');
118+
elem.scrollTop = 0;
119+
elem.dispatchEvent(eventUp);
120+
window.setTimeout(()=>{
121+
window.requestAnimationFrame(() => {
122+
validateScrolledState();
123+
done();
124+
});
125+
});
126+
});
127+
});
128+
}
129+
110130
function validatePush(done) {
111131
viewModel.items.push('Foo');
112132
nq(() => validateState());
@@ -438,6 +458,14 @@ describe('VirtualRepeat Integration', () => {
438458
})
439459
});
440460
});
461+
it('handles getting next data set scrolling up', done => {
462+
create.then(() => {
463+
validateScrollUp(() => {
464+
expect(vm.getNextPage).toHaveBeenCalledWith(0, false, true);
465+
done();
466+
});
467+
});
468+
});
441469
it('handles getting next data set with promises', done => {
442470
promisedCreate.then(() => {
443471
validateScroll(() => {
@@ -447,6 +475,13 @@ describe('VirtualRepeat Integration', () => {
447475
})
448476
});
449477
});
450-
478+
it('passes the current index and location state', done => {
479+
create.then(() => {
480+
validateScroll(() => {
481+
expect(vm.getNextPage).toHaveBeenCalledWith(989, true, false);
482+
done();
483+
})
484+
});
485+
})
451486
})
452487
});

0 commit comments

Comments
 (0)