Skip to content

Commit f44eb98

Browse files
committed
fix(array-repeat): properly handle end of array instanceChanged()
1 parent ece42ff commit f44eb98

File tree

2 files changed

+124
-105
lines changed

2 files changed

+124
-105
lines changed

sample/sample-v-ui-app/src/app.html

Lines changed: 97 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -5,95 +5,106 @@
55
<nav-bar router.bind='router'></nav-bar>
66
<main as-element='router-view'></main>
77
</div>
8+
<button
9+
class="btn btn-sm btn-info"
10+
show.bind="minimizedMonitor"
11+
click.trigger="minimizedMonitor = false"
12+
style="position: absolute; bottom: 20px; right: 20px;">Maximize monitor</button>
813
<div
914
if.bind="window.virtualRepeat"
10-
class="bg-white border shadow-lg"
11-
style="position: fixed; bottom: 0; right: 0; height: 400px; overflow-y: auto;">
15+
show.bind="!minimizedMonitor"
16+
class="bg-white border shadow-lg d-flex flex-column"
17+
style="position: fixed; bottom: 0; right: 0; max-height: 80vh;">
1218
<let virtual-repeat.bind='window.virtualRepeat'></let>
13-
<table class="table table-sm table-striped table-bordered">
14-
<tr>
15-
<th>Name</th>
16-
<th>--- Value ---</th>
17-
</tr>
18-
<tr>
19-
<td>First</td><td>${virtualRepeat._first}</td>
20-
<tr>
21-
<td>Previous First</td><td>${virtualRepeat._previousFirst}</td>
22-
<tr>
23-
<td>Views Length</td><td>${virtualRepeat._viewsLength}</td>
24-
<tr>
25-
<td>Last Rebind</td><td>${virtualRepeat._lastRebind}</td>
26-
<tr>
27-
<td>Elements In view</td>
28-
<td>${virtualRepeat.elementsInView}</td>
29-
<tr>
30-
<td>Item height</td>
31-
<td>${virtualRepeat.itemHeight}</td>
32-
<tr>
33-
<td>Top Buffer height</td>
34-
<td>${virtualRepeat._topBufferHeight}</td>
35-
<tr>
36-
<td>Bottom Buffer height</td>
37-
<td>${virtualRepeat._bottomBufferHeight}</td>
38-
<tr>
39-
<td>Buffer Size</td>
40-
<td>${virtualRepeat._bufferSize}</td>
41-
<tr>
42-
<td>Distance to top</td>
43-
<td>${virtualRepeat.distanceToTop}</td>
44-
<tr>
45-
<td>Top buffer distance</td>
46-
<td>${virtualRepeat.topBufferDistance}</td>
47-
<tr>
48-
<td>Scrolling Down</td>
49-
<td><checkbox checked.bind=virtualRepeat._scrollingDown></checkbox></td>
50-
<tr>
51-
<td>Scrolling Up</td>
52-
<td><checkbox checked.bind=virtualRepeat._scrollingUp></checkbox></td>
53-
<tr>
54-
<td>Is First or last</td>
55-
<td><checkbox checked.bind=virtualRepeat._isAtFirstOrLastIndex></checkbox></td>
56-
<tr>
57-
<td>Switched Direction</td>
58-
<td><checkbox checked.bind=virtualRepeat._switchedDirection></checkbox></td>
59-
</tr>
60-
<tr>
61-
<td>Is Attached</td>
62-
<td><checkbox checked.bind=virtualRepeat._isAttached></checkbox></td>
63-
</tr>
64-
<tr>
65-
<td>Ticking</td>
66-
<td><checkbox checked.bind=virtualRepeat._ticking></checkbox></td>
67-
<tr>
68-
<td>Fixed height Container</td>
69-
<td><checkbox checked.bind=virtualRepeat._fixedHeightContainer></checkbox></td>
70-
<tr>
71-
<td>Has Calculated Size</td><td><checkbox checked.bind=virtualRepeat._hasCalculatedSizes></checkbox></td>
72-
<tr>
73-
<td>Is At top</td>
74-
<td><checkbox checked.bind=virtualRepeat._isAtTop></checkbox></td>
75-
</tr>
76-
<tr>
77-
<td>Is Last Index</td>
78-
<td><checkbox checked.bind=virtualRepeat.isLastIndex></checkbox></td>
79-
</tr>
80-
<tr>
81-
<td>Called Get More</td>
82-
<td><checkbox checked.bind=virtualRepeat._calledGetMore></checkbox></td>
83-
</tr>
84-
<tr>
85-
<td>Skip Next Scroll</td>
86-
<td><checkbox checked.bind=virtualRepeat._skipNextScrollHandle></checkbox></td>
87-
</tr>
88-
<tr>
89-
<td>Handling Mutation</td>
90-
<td><checkbox checked.bind=virtualRepeat._handlingMutations></checkbox></td>
91-
</tr>
92-
<tr>
93-
<td>Is Scrolling</td>
94-
<td><checkbox checked.bind=virtualRepeat._isScrolling></checkbox></td>
95-
</tr>
96-
</table>
19+
<button
20+
class="btn btn-sm btn-block btn-info"
21+
click.trigger="minimizedMonitor = true">Minimize monitor</button>
22+
<div class="flex-fill" style="overflow-y: auto;">
23+
<table class="table table-sm table-striped table-bordered">
24+
<tr>
25+
<th>Name</th>
26+
<th>--- Value ---</th>
27+
</tr>
28+
<tr>
29+
<td>First</td><td>${virtualRepeat._first}</td>
30+
<tr>
31+
<td>Previous First</td><td>${virtualRepeat._previousFirst}</td>
32+
<tr>
33+
<td>Views Length</td><td>${virtualRepeat._viewsLength}</td>
34+
<tr>
35+
<td>Last Rebind</td><td>${virtualRepeat._lastRebind}</td>
36+
<tr>
37+
<td>Elements In view</td>
38+
<td>${virtualRepeat.elementsInView}</td>
39+
<tr>
40+
<td>Item height</td>
41+
<td>${virtualRepeat.itemHeight}</td>
42+
<tr>
43+
<td>Top Buffer height</td>
44+
<td>${virtualRepeat._topBufferHeight}</td>
45+
<tr>
46+
<td>Bottom Buffer height</td>
47+
<td>${virtualRepeat._bottomBufferHeight}</td>
48+
<tr>
49+
<td>Buffer Size</td>
50+
<td>${virtualRepeat._bufferSize}</td>
51+
<tr>
52+
<td>Distance to top</td>
53+
<td>${virtualRepeat.distanceToTop}</td>
54+
<tr>
55+
<td>Top buffer distance</td>
56+
<td>${virtualRepeat.topBufferDistance}</td>
57+
<tr>
58+
<td>Scrolling Down</td>
59+
<td><checkbox checked.bind=virtualRepeat._scrollingDown></checkbox></td>
60+
<tr>
61+
<td>Scrolling Up</td>
62+
<td><checkbox checked.bind=virtualRepeat._scrollingUp></checkbox></td>
63+
<tr>
64+
<td>Is First or last</td>
65+
<td><checkbox checked.bind=virtualRepeat._isAtFirstOrLastIndex></checkbox></td>
66+
<tr>
67+
<td>Switched Direction</td>
68+
<td><checkbox checked.bind=virtualRepeat._switchedDirection></checkbox></td>
69+
</tr>
70+
<tr>
71+
<td>Is Attached</td>
72+
<td><checkbox checked.bind=virtualRepeat._isAttached></checkbox></td>
73+
</tr>
74+
<tr>
75+
<td>Ticking</td>
76+
<td><checkbox checked.bind=virtualRepeat._ticking></checkbox></td>
77+
<tr>
78+
<td>Fixed height Container</td>
79+
<td><checkbox checked.bind=virtualRepeat._fixedHeightContainer></checkbox></td>
80+
<tr>
81+
<td>Has Calculated Size</td><td><checkbox checked.bind=virtualRepeat._hasCalculatedSizes></checkbox></td>
82+
<tr>
83+
<td>Is At top</td>
84+
<td><checkbox checked.bind=virtualRepeat._isAtTop></checkbox></td>
85+
</tr>
86+
<tr>
87+
<td>Is Last Index</td>
88+
<td><checkbox checked.bind=virtualRepeat.isLastIndex></checkbox></td>
89+
</tr>
90+
<tr>
91+
<td>Called Get More</td>
92+
<td><checkbox checked.bind=virtualRepeat._calledGetMore></checkbox></td>
93+
</tr>
94+
<tr>
95+
<td>Skip Next Scroll</td>
96+
<td><checkbox checked.bind=virtualRepeat._skipNextScrollHandle></checkbox></td>
97+
</tr>
98+
<tr>
99+
<td>Handling Mutation</td>
100+
<td><checkbox checked.bind=virtualRepeat._handlingMutations></checkbox></td>
101+
</tr>
102+
<tr>
103+
<td>Is Scrolling</td>
104+
<td><checkbox checked.bind=virtualRepeat._isScrolling></checkbox></td>
105+
</tr>
106+
</table>
107+
</div>
97108
</div>
98109
</template>
99110

src/array-virtual-repeat-strategy.ts

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,14 @@ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy implements I
4747

4848
/**@internal */
4949
_inPlaceProcessItems(repeat: VirtualRepeat, items: any[], first: number): void {
50-
const prevItemCount = repeat._prevItemsCount;
5150
const currItemCount = items.length;
51+
if (currItemCount === 0) {
52+
repeat.removeAllViews(/*return to cache?*/true, /*skip animation?*/false);
53+
repeat._resetCalculation();
54+
delete repeat.__queuedSplices;
55+
delete repeat.__array;
56+
return;
57+
}
5258
/*
5359
Get index of first view is looking at the view which is from the ViewSlot
5460
The view slot has not yet been updated with the new list
@@ -57,46 +63,48 @@ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy implements I
5763
That "first" is calculated and passed into here
5864
*/
5965
// remove unneeded views.
60-
let viewCount = repeat.viewCount();
61-
while (viewCount > currItemCount) {
62-
viewCount--;
63-
repeat.removeView(viewCount, /** Returns to cache? */ true, /** skip animation? */ false);
66+
let realViewsCount = repeat.viewCount();
67+
while (realViewsCount > currItemCount) {
68+
realViewsCount--;
69+
repeat.removeView(realViewsCount, /**return to cache?*/true, /**skip animation?*/false);
6470
}
65-
console.log({ first });
66-
// avoid repeated evaluating the property-getter for the "local" property.
6771
const local = repeat.local;
68-
const viewsCount = Math.min(repeat._viewsLength, currItemCount);
72+
const lastIndex = currItemCount - 1;
73+
if (first + realViewsCount > lastIndex) {
74+
// first = currItemCount - realViewsCount instead of: first = currItemCount - 1 - realViewsCount;
75+
// this is because during view update
76+
// view(i) starts at 0 and ends at less than last
77+
first = Math.max(0, currItemCount - realViewsCount);
78+
}
6979
// re-evaluate bindings on existing views.
70-
for (let i = 0; i < viewCount; i++) {
80+
for (let i = 0; i < realViewsCount; i++) {
81+
const currIndex = i + first;
7182
const view = repeat.view(i);
72-
const last = i === currItemCount - 1;
73-
const middle = i !== 0 && !last;
83+
const last = currIndex === currItemCount - 1;
84+
const middle = currIndex !== 0 && !last;
7485
const bindingContext = view.bindingContext;
7586
const overrideContext = view.overrideContext;
7687
// any changes to the binding context?
77-
if (bindingContext[local] === items[i + first]
88+
if (bindingContext[local] === items[currIndex]
7889
&& overrideContext.$middle === middle
7990
&& overrideContext.$last === last
8091
) {
8192
// no changes. continue...
8293
continue;
8394
}
8495
// update the binding context and refresh the bindings.
85-
bindingContext[local] = items[i + first];
96+
bindingContext[local] = items[currIndex];
8697
overrideContext.$middle = middle;
8798
overrideContext.$last = last;
88-
overrideContext.$index = i + first;
99+
overrideContext.$index = currIndex;
89100
repeat.updateBindings(view);
90101
}
91102
// add new views
92103
const minLength = Math.min(repeat._viewsLength, currItemCount);
93-
for (let i = viewCount; i < minLength; i++) {
104+
for (let i = realViewsCount; i < minLength; i++) {
94105
const overrideContext = createFullOverrideContext(repeat, items[i], i, currItemCount);
95106
repeat.addView(overrideContext.bindingContext, overrideContext);
96-
}
97-
98-
const scrollerInfo = repeat.getScrollerInfo();
99-
107+
}
100108
}
101109

102110
/**@internal */

0 commit comments

Comments
 (0)