Skip to content
Permalink
Browse files

fix(array-repeat): properly handle end of array instanceChanged()

  • Loading branch information...
bigopon committed Feb 22, 2019
1 parent ece42ff commit f44eb987eaa6ec1559286774b8c92a4514b0c6b5
Showing with 124 additions and 105 deletions.
  1. +97 −86 sample/sample-v-ui-app/src/app.html
  2. +27 −19 src/array-virtual-repeat-strategy.ts
@@ -5,95 +5,106 @@
<nav-bar router.bind='router'></nav-bar>
<main as-element='router-view'></main>
</div>
<button
class="btn btn-sm btn-info"
show.bind="minimizedMonitor"
click.trigger="minimizedMonitor = false"
style="position: absolute; bottom: 20px; right: 20px;">Maximize monitor</button>
<div
if.bind="window.virtualRepeat"
class="bg-white border shadow-lg"
style="position: fixed; bottom: 0; right: 0; height: 400px; overflow-y: auto;">
show.bind="!minimizedMonitor"
class="bg-white border shadow-lg d-flex flex-column"
style="position: fixed; bottom: 0; right: 0; max-height: 80vh;">
<let virtual-repeat.bind='window.virtualRepeat'></let>
<table class="table table-sm table-striped table-bordered">
<tr>
<th>Name</th>
<th>--- Value ---</th>
</tr>
<tr>
<td>First</td><td>${virtualRepeat._first}</td>
<tr>
<td>Previous First</td><td>${virtualRepeat._previousFirst}</td>
<tr>
<td>Views Length</td><td>${virtualRepeat._viewsLength}</td>
<tr>
<td>Last Rebind</td><td>${virtualRepeat._lastRebind}</td>
<tr>
<td>Elements In view</td>
<td>${virtualRepeat.elementsInView}</td>
<tr>
<td>Item height</td>
<td>${virtualRepeat.itemHeight}</td>
<tr>
<td>Top Buffer height</td>
<td>${virtualRepeat._topBufferHeight}</td>
<tr>
<td>Bottom Buffer height</td>
<td>${virtualRepeat._bottomBufferHeight}</td>
<tr>
<td>Buffer Size</td>
<td>${virtualRepeat._bufferSize}</td>
<tr>
<td>Distance to top</td>
<td>${virtualRepeat.distanceToTop}</td>
<tr>
<td>Top buffer distance</td>
<td>${virtualRepeat.topBufferDistance}</td>
<tr>
<td>Scrolling Down</td>
<td><checkbox checked.bind=virtualRepeat._scrollingDown></checkbox></td>
<tr>
<td>Scrolling Up</td>
<td><checkbox checked.bind=virtualRepeat._scrollingUp></checkbox></td>
<tr>
<td>Is First or last</td>
<td><checkbox checked.bind=virtualRepeat._isAtFirstOrLastIndex></checkbox></td>
<tr>
<td>Switched Direction</td>
<td><checkbox checked.bind=virtualRepeat._switchedDirection></checkbox></td>
</tr>
<tr>
<td>Is Attached</td>
<td><checkbox checked.bind=virtualRepeat._isAttached></checkbox></td>
</tr>
<tr>
<td>Ticking</td>
<td><checkbox checked.bind=virtualRepeat._ticking></checkbox></td>
<tr>
<td>Fixed height Container</td>
<td><checkbox checked.bind=virtualRepeat._fixedHeightContainer></checkbox></td>
<tr>
<td>Has Calculated Size</td><td><checkbox checked.bind=virtualRepeat._hasCalculatedSizes></checkbox></td>
<tr>
<td>Is At top</td>
<td><checkbox checked.bind=virtualRepeat._isAtTop></checkbox></td>
</tr>
<tr>
<td>Is Last Index</td>
<td><checkbox checked.bind=virtualRepeat.isLastIndex></checkbox></td>
</tr>
<tr>
<td>Called Get More</td>
<td><checkbox checked.bind=virtualRepeat._calledGetMore></checkbox></td>
</tr>
<tr>
<td>Skip Next Scroll</td>
<td><checkbox checked.bind=virtualRepeat._skipNextScrollHandle></checkbox></td>
</tr>
<tr>
<td>Handling Mutation</td>
<td><checkbox checked.bind=virtualRepeat._handlingMutations></checkbox></td>
</tr>
<tr>
<td>Is Scrolling</td>
<td><checkbox checked.bind=virtualRepeat._isScrolling></checkbox></td>
</tr>
</table>
<button
class="btn btn-sm btn-block btn-info"
click.trigger="minimizedMonitor = true">Minimize monitor</button>
<div class="flex-fill" style="overflow-y: auto;">
<table class="table table-sm table-striped table-bordered">
<tr>
<th>Name</th>
<th>--- Value ---</th>
</tr>
<tr>
<td>First</td><td>${virtualRepeat._first}</td>
<tr>
<td>Previous First</td><td>${virtualRepeat._previousFirst}</td>
<tr>
<td>Views Length</td><td>${virtualRepeat._viewsLength}</td>
<tr>
<td>Last Rebind</td><td>${virtualRepeat._lastRebind}</td>
<tr>
<td>Elements In view</td>
<td>${virtualRepeat.elementsInView}</td>
<tr>
<td>Item height</td>
<td>${virtualRepeat.itemHeight}</td>
<tr>
<td>Top Buffer height</td>
<td>${virtualRepeat._topBufferHeight}</td>
<tr>
<td>Bottom Buffer height</td>
<td>${virtualRepeat._bottomBufferHeight}</td>
<tr>
<td>Buffer Size</td>
<td>${virtualRepeat._bufferSize}</td>
<tr>
<td>Distance to top</td>
<td>${virtualRepeat.distanceToTop}</td>
<tr>
<td>Top buffer distance</td>
<td>${virtualRepeat.topBufferDistance}</td>
<tr>
<td>Scrolling Down</td>
<td><checkbox checked.bind=virtualRepeat._scrollingDown></checkbox></td>
<tr>
<td>Scrolling Up</td>
<td><checkbox checked.bind=virtualRepeat._scrollingUp></checkbox></td>
<tr>
<td>Is First or last</td>
<td><checkbox checked.bind=virtualRepeat._isAtFirstOrLastIndex></checkbox></td>
<tr>
<td>Switched Direction</td>
<td><checkbox checked.bind=virtualRepeat._switchedDirection></checkbox></td>
</tr>
<tr>
<td>Is Attached</td>
<td><checkbox checked.bind=virtualRepeat._isAttached></checkbox></td>
</tr>
<tr>
<td>Ticking</td>
<td><checkbox checked.bind=virtualRepeat._ticking></checkbox></td>
<tr>
<td>Fixed height Container</td>
<td><checkbox checked.bind=virtualRepeat._fixedHeightContainer></checkbox></td>
<tr>
<td>Has Calculated Size</td><td><checkbox checked.bind=virtualRepeat._hasCalculatedSizes></checkbox></td>
<tr>
<td>Is At top</td>
<td><checkbox checked.bind=virtualRepeat._isAtTop></checkbox></td>
</tr>
<tr>
<td>Is Last Index</td>
<td><checkbox checked.bind=virtualRepeat.isLastIndex></checkbox></td>
</tr>
<tr>
<td>Called Get More</td>
<td><checkbox checked.bind=virtualRepeat._calledGetMore></checkbox></td>
</tr>
<tr>
<td>Skip Next Scroll</td>
<td><checkbox checked.bind=virtualRepeat._skipNextScrollHandle></checkbox></td>
</tr>
<tr>
<td>Handling Mutation</td>
<td><checkbox checked.bind=virtualRepeat._handlingMutations></checkbox></td>
</tr>
<tr>
<td>Is Scrolling</td>
<td><checkbox checked.bind=virtualRepeat._isScrolling></checkbox></td>
</tr>
</table>
</div>
</div>
</template>

@@ -47,8 +47,14 @@ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy implements I

/**@internal */
_inPlaceProcessItems(repeat: VirtualRepeat, items: any[], first: number): void {
const prevItemCount = repeat._prevItemsCount;
const currItemCount = items.length;
if (currItemCount === 0) {
repeat.removeAllViews(/*return to cache?*/true, /*skip animation?*/false);
repeat._resetCalculation();
delete repeat.__queuedSplices;
delete repeat.__array;
return;
}
/*
Get index of first view is looking at the view which is from the ViewSlot
The view slot has not yet been updated with the new list
@@ -57,46 +63,48 @@ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy implements I
That "first" is calculated and passed into here
*/
// remove unneeded views.
let viewCount = repeat.viewCount();
while (viewCount > currItemCount) {
viewCount--;
repeat.removeView(viewCount, /** Returns to cache? */ true, /** skip animation? */ false);
let realViewsCount = repeat.viewCount();
while (realViewsCount > currItemCount) {
realViewsCount--;
repeat.removeView(realViewsCount, /**return to cache?*/true, /**skip animation?*/false);
}
console.log({ first });
// avoid repeated evaluating the property-getter for the "local" property.
const local = repeat.local;
const viewsCount = Math.min(repeat._viewsLength, currItemCount);
const lastIndex = currItemCount - 1;
if (first + realViewsCount > lastIndex) {
// first = currItemCount - realViewsCount instead of: first = currItemCount - 1 - realViewsCount;
// this is because during view update
// view(i) starts at 0 and ends at less than last
first = Math.max(0, currItemCount - realViewsCount);
}
// re-evaluate bindings on existing views.
for (let i = 0; i < viewCount; i++) {
for (let i = 0; i < realViewsCount; i++) {
const currIndex = i + first;
const view = repeat.view(i);
const last = i === currItemCount - 1;
const middle = i !== 0 && !last;
const last = currIndex === currItemCount - 1;
const middle = currIndex !== 0 && !last;
const bindingContext = view.bindingContext;
const overrideContext = view.overrideContext;
// any changes to the binding context?
if (bindingContext[local] === items[i + first]
if (bindingContext[local] === items[currIndex]
&& overrideContext.$middle === middle
&& overrideContext.$last === last
) {
// no changes. continue...
continue;
}
// update the binding context and refresh the bindings.
bindingContext[local] = items[i + first];
bindingContext[local] = items[currIndex];
overrideContext.$middle = middle;
overrideContext.$last = last;
overrideContext.$index = i + first;
overrideContext.$index = currIndex;
repeat.updateBindings(view);
}
// add new views
const minLength = Math.min(repeat._viewsLength, currItemCount);
for (let i = viewCount; i < minLength; i++) {
for (let i = realViewsCount; i < minLength; i++) {
const overrideContext = createFullOverrideContext(repeat, items[i], i, currItemCount);
repeat.addView(overrideContext.bindingContext, overrideContext);
}

const scrollerInfo = repeat.getScrollerInfo();

}
}

/**@internal */

0 comments on commit f44eb98

Please sign in to comment.
You can’t perform that action at this time.