@@ -112,8 +112,8 @@ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy {
112112 * @param repeat The repeater instance.
113113 * @param items The new array instance.
114114 */
115- instanceChanged ( repeat : VirtualRepeat , items : Array < any > ) : void {
116- this. _inPlaceProcessItems ( repeat , items ) ;
115+ instanceChanged ( repeat : VirtualRepeat , items : Array < any > , ... rest ) : void {
116+ this . _inPlaceProcessItems ( repeat , items , rest [ 0 ] ) ;
117117 }
118118
119119 _standardProcessInstanceChanged ( repeat : VirtualRepeat , items : Array < any > ) : void {
@@ -123,10 +123,16 @@ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy {
123123 }
124124 }
125125
126- _inPlaceProcessItems ( repeat : VirtualRepeat , items : Array < any > ) : void {
126+ _inPlaceProcessItems ( repeat : VirtualRepeat , items : Array < any > , first : number ) : void {
127127 let itemsLength = items . length ;
128128 let viewsLength = repeat . viewCount ( ) ;
129- let first = repeat . _getIndexOfFirstView ( ) ;
129+ /*
130+ Get index of first view is looking at the view which is from the ViewSlot
131+ The view slot has not yet been updated with the new list
132+ New first has to be the calculated "first" in our view slot, so the first one that's going to be rendered
133+ To figure out that one, we're going to have to know where we are in our scrolling so we can know how far down we've gone to show the first view
134+ That "first" is calculated and passed into here
135+ */
130136 // remove unneeded views.
131137 while ( viewsLength > itemsLength ) {
132138 viewsLength -- ;
@@ -148,6 +154,7 @@ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy {
148154 view . bindingContext [ local ] = items [ i + first ] ;
149155 view . overrideContext . $middle = middle ;
150156 view . overrideContext . $last = last ;
157+ view . overrideContext . $index = i + first ;
151158 repeat . updateBindings ( view ) ;
152159 }
153160 // add new views
@@ -457,7 +464,7 @@ export class TableStrategy {
457464 getFirstElement ( topBuffer : Element ) : Element {
458465 const tbody = this . _getTbodyElement ( DOM . nextElementSibling ( topBuffer ) ) ;
459466 const tr = tbody . firstChild ;
460- return DOM . nextElementSibling ( tr ) ;
467+ return tr ; //since the buffer is outside table, first element _is_ first element.
461468 }
462469
463470 getLastElement ( bottomBuffer : Element ) : Element {
@@ -613,6 +620,7 @@ export class VirtualRepeat extends AbstractRepeater {
613620 } , 500 ) ;
614621
615622 this . distanceToTop = this . domHelper . getElementDistanceToTopOfDocument ( this . templateStrategy . getFirstElement ( this . topBuffer ) ) ;
623+ // When dealing with tables, there can be gaps between elements, causing distances to be messed up. Might need to handle this case here.
616624 this . topBufferDistance = this . templateStrategy . getTopBufferDistance ( this . topBuffer ) ;
617625
618626 if ( this . domHelper . hasOverflowScroll ( this . scrollContainer ) ) {
@@ -667,17 +675,53 @@ export class VirtualRepeat extends AbstractRepeater {
667675 if ( ! this . scope ) {
668676 return ;
669677 }
678+ let reducingItems = false ;
679+ let previousLastViewIndex = this . _getIndexOfLastView ( ) ;
680+
670681 let items = this . items ;
671682 this . strategy = this . strategyLocator . getStrategy ( items ) ;
672683 if ( items . length > 0 && this . viewCount ( ) === 0 ) {
673684 this . strategy . createFirstItem ( this ) ;
674685 }
686+ // Skip scroll handling if we are decreasing item list
687+ // Otherwise if expanding list, call the handle scroll below
688+ if ( this . _itemsLength >= items . length ) {
689+ //Scroll handle is redundant in this case since the instanceChanged will re-evaluate orderings
690+ // Also, when items are reduced, we're not having to move any bindings, just a straight rebind of the items in the list
691+ this . _skipNextScrollHandle = true ;
692+ reducingItems = true ;
693+ }
694+ this . _checkFixedHeightContainer ( ) ;
675695 this . _calcInitialHeights ( items . length ) ;
676696 if ( ! this . isOneTime && ! this . _observeInnerCollection ( ) ) {
677697 this . _observeCollection ( ) ;
678698 }
699+ this . strategy . instanceChanged ( this , items , this . _first ) ;
700+ this . _lastRebind = this . _first ; //Reset rebinding
701+
702+ if ( reducingItems && previousLastViewIndex > this . items . length - 1 ) {
703+ //Do we need to set scrolltop so that we appear at the bottom of the list to match scrolling as far as we could?
704+ //We only want to execute this line if we're reducing such that it brings us to the bottom of the new list
705+ //Make sure we handle the special case of tables
706+ if ( this . scrollContainer . tagName === 'TBODY' ) {
707+ let realScrollContainer = this . scrollContainer . parentNode . parentNode ; //tbody > table > container
708+ realScrollContainer . scrollTop = realScrollContainer . scrollTop + ( this . viewCount ( ) * this . itemHeight ) ;
709+ } else {
710+ this . scrollContainer . scrollTop = this . scrollContainer . scrollTop + ( this . viewCount ( ) * this . itemHeight ) ;
711+ }
712+ }
713+ if ( ! reducingItems ) {
714+ // If we're expanding our items, then we need to reset our previous first for the next go around of scroll handling
715+ this . _previousFirst = this . _first ;
716+ this . _scrollingDown = true ; //Simulating the down scroll event to load up data appropriately
717+ this . _scrollingUp = false ;
718+
719+ //Make sure we fix any state (we could have been at the last index before, but this doesn't get set until too late for scrolling)
720+ this . isLastIndex = this . _getIndexOfLastView ( ) >= this . items . length - 1 ;
721+ }
679722
680- this . strategy . instanceChanged ( this , items , this . _viewsLength ) ;
723+ //Need to readjust the scroll position to "move" us back to the appropriate position, since moving the views will shift our view port's percieved location
724+ this . _handleScroll ( ) ;
681725 }
682726
683727 unbind ( ) : void {
@@ -728,6 +772,10 @@ export class VirtualRepeat extends AbstractRepeater {
728772 if ( ! this . _isAttached ) {
729773 return ;
730774 }
775+ if ( this . _skipNextScrollHandle ) {
776+ this . _skipNextScrollHandle = false ;
777+ return ;
778+ }
731779 let itemHeight = this . itemHeight ;
732780 let scrollTop = this . _fixedHeightContainer ? this . scrollContainer . scrollTop : pageYOffset - this . distanceToTop ;
733781 this . _first = Math . floor ( scrollTop / itemHeight ) ;
@@ -859,6 +907,12 @@ export class VirtualRepeat extends AbstractRepeater {
859907 }
860908 }
861909
910+ _checkFixedHeightContainer ( ) : void {
911+ if ( this . domHelper . hasOverflowScroll ( this . scrollContainer ) ) {
912+ this . _fixedHeightContainer = true ;
913+ }
914+ }
915+
862916 _adjustBufferHeights ( ) : void {
863917 this . topBuffer . style . height = `${ this . _topBufferHeight } px` ;
864918 this . bottomBuffer . style . height = `${ this . _bottomBufferHeight } px` ;
@@ -935,20 +989,38 @@ export class VirtualRepeat extends AbstractRepeater {
935989 } , 500 ) ;
936990 return ;
937991 }
992+
938993 this . _itemsLength = itemsLength ;
939994 this . scrollContainerHeight = this . _fixedHeightContainer ? this . _calcScrollHeight ( this . scrollContainer ) : document . documentElement . clientHeight ;
940995 this . elementsInView = Math . ceil ( this . scrollContainerHeight / this . itemHeight ) + 1 ;
941996 this . _viewsLength = ( this . elementsInView * 2 ) + this . _bufferSize ;
942- this . _bottomBufferHeight = this . itemHeight * itemsLength - this . itemHeight * this . _viewsLength ;
943- if ( this . _bottomBufferHeight < 0 ) {
997+
998+ //Look at top buffer height (how far we've scrolled down)
999+ //If top buffer height is greater than the new bottom buffer height (how far we *can* scroll down)
1000+ // Then set top buffer height to max it can be (bottom buffer height - views in length?) and bottom buffer height to 0
1001+ let newBottomBufferHeight = this . itemHeight * itemsLength - this . itemHeight * this . _viewsLength ; //How much buffer room to the bottom if you were at the top
1002+ if ( newBottomBufferHeight < 0 ) { // In case of small lists, ensure that we never set the buffer heights to impossible values
1003+ newBottomBufferHeight = 0 ;
1004+ }
1005+ if ( this . _topBufferHeight >= newBottomBufferHeight ) { //Use case when items are removed (we've scrolled past where we can)
1006+ this . _topBufferHeight = newBottomBufferHeight ;
9441007 this . _bottomBufferHeight = 0 ;
1008+ this . _first = this . _itemsLength - this . _viewsLength ;
1009+ if ( this . _first < 0 ) { // In case of small lists, ensure that we never set first to less than possible
1010+ this . _first = 0 ;
1011+ }
1012+ } else { //Use case when items are added (we are adding scrollable space to the bottom)
1013+ // We need to re-evaluate which is the true "first". If we've added items, then the previous "first" is actually too far down the list
1014+ this . _first = this . _getIndexOfFirstView ( ) ;
1015+ let adjustedTopBufferHeight = this . _first * this . itemHeight ; //appropriate buffer height for top, might be 1 too long...
1016+ this . _topBufferHeight = adjustedTopBufferHeight ;
1017+ //But what about when we've only scrolled slightly down the list? We need to readjust the top buffer height then
1018+ this . _bottomBufferHeight = newBottomBufferHeight - adjustedTopBufferHeight ;
1019+ if ( this . _bottomBufferHeight < 0 ) {
1020+ this . _bottomBufferHeight = 0 ;
1021+ }
9451022 }
946- this . bottomBuffer . style . height = `${ this . _bottomBufferHeight } px` ;
947- this . _topBufferHeight = 0 ;
948- this . topBuffer . style . height = `${ this . _topBufferHeight } px` ;
949- // TODO This will cause scrolling back to top when swapping collection instances that have different lengths - instead should keep the scroll position
950- this . scrollContainer . scrollTop = 0 ;
951- this . _first = 0 ;
1023+ this . _adjustBufferHeights ( ) ;
9521024 return ;
9531025 }
9541026
@@ -993,6 +1065,7 @@ export class VirtualRepeat extends AbstractRepeater {
9931065 }
9941066
9951067 // @override AbstractRepeater
1068+ // How will these behaviors need to change since we are in a virtual list instead?
9961069 viewCount ( ) { return this . viewSlot . children . length ; }
9971070 views ( ) { return this . viewSlot . children ; }
9981071 view ( index ) { return this . viewSlot . children [ index ] ; }
0 commit comments