Skip to content

Commit 2d1789b

Browse files
committed
feat(virtual-repeat): allow use of .call on virtual-repeat-next
Allow ‘virtual-repeat-next' to evaluate expressions via `.call` so that the `getMore` function can be called from a scope different from the `virtual-repeat` it’s contained in. Access context parameters via `$scrollContext`, e.g. `virtual-repeat-next.call='getMore($scrollContext)'`.
1 parent 66d7418 commit 2d1789b

File tree

3 files changed

+278
-173
lines changed

3 files changed

+278
-173
lines changed

README.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ If you are running the plugin in the `skeleton-naviagion` project, make sure to
9494
</div>
9595
</template>
9696
```
97-
9897
```javascript
9998
export class MyVirtualList {
10099
items = ['Foo', 'Bar', 'Baz'];
@@ -105,6 +104,26 @@ export class MyVirtualList {
105104
}
106105
}
107106
```
107+
108+
Or to use an expression, use `.call` as shown below.
109+
```html
110+
<template>
111+
<div virtual-repeat.for="item of items" virtual-repeat-next.call="getMore($scrollContext)">
112+
${$index} ${item}
113+
</div>
114+
</template>
115+
```
116+
```javascript
117+
export class MyVirtualList {
118+
items = ['Foo', 'Bar', 'Baz'];
119+
getMore(scrollContext) {
120+
for(let i = 0; i < 100; ++i) {
121+
this.items.push('item' + i);
122+
}
123+
}
124+
}
125+
```
126+
108127
The `virtual-repeat-next` attribute can accept a function, a promise, or a function that returns a promise.
109128
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).
110129
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.

src/virtual-repeat.js

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -271,26 +271,43 @@ export class VirtualRepeat extends AbstractRepeater {
271271
_getMore(): void {
272272
if (this.isLastIndex || this._first === 0) {
273273
if (!this._calledGetMore) {
274-
let getMoreFunc = this.view(0).firstChild.getAttribute('virtual-repeat-next');
275-
if (!getMoreFunc) {
276-
return;
277-
}
278-
let getMore = this.scope.overrideContext.bindingContext[getMoreFunc];
279274
let executeGetMore = () => {
280275
this._calledGetMore = true;
281-
if (getMore instanceof Promise) {
282-
return getMore.then(() => {
283-
this._calledGetMore = false; //Reset for the next time
284-
});
285-
} else if (typeof getMore === 'function') {
286-
let result = getMore.bind(this.scope.overrideContext.bindingContext)(this._first, this._bottomBufferHeight === 0, this._isAtTop);
287-
if (!(result instanceof Promise)) {
288-
this._calledGetMore = false; //Reset for the next time
289-
} else {
290-
return result.then(() => {
276+
let func = (this.view(0) && this.view(0).firstChild.au) ? this.view(0).firstChild.au['virtual-repeat-next'].instruction.attributes['virtual-repeat-next'] : undefined;
277+
let topIndex = this._first;
278+
let isAtBottom = this._bottomBufferHeight === 0;
279+
let isAtTop = this._isAtTop;
280+
let scrollContext = {
281+
topIndex: topIndex,
282+
isAtBottom: isAtBottom,
283+
isAtTop: isAtTop
284+
};
285+
286+
this.scope.overrideContext.$scrollContext = scrollContext;
287+
288+
if (func === undefined) {
289+
return null;
290+
} else if (typeof func === 'string') {
291+
let getMoreFuncName = this.view(0).firstChild.getAttribute('virtual-repeat-next');
292+
let funcCall = this.scope.overrideContext.bindingContext[getMoreFuncName];
293+
294+
if (typeof funcCall === 'function') {
295+
let result = funcCall.call(this.scope.overrideContext.bindingContext, topIndex, isAtBottom, isAtTop);
296+
if (!(result instanceof Promise)) {
291297
this._calledGetMore = false; //Reset for the next time
292-
});
298+
} else {
299+
return result.then(() => {
300+
this._calledGetMore = false; //Reset for the next time
301+
});
302+
}
303+
} else {
304+
throw new Error("'virtual-repeat-next' must be a function or evaluate to one");
293305
}
306+
} else if (func.sourceExpression) {
307+
this._calledGetMore = false; //Reset for the next time
308+
return func.sourceExpression.evaluate(this.scope);
309+
} else {
310+
throw new Error("'virtual-repeat-next' must be a function or evaluate to one");
294311
}
295312
return null;
296313
};

0 commit comments

Comments
 (0)