Skip to content

Commit 636e5c3

Browse files
fix(for-of): correct content area recalculation
1 parent c6d9a0a commit 636e5c3

File tree

4 files changed

+1984
-44
lines changed

4 files changed

+1984
-44
lines changed

projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -798,75 +798,57 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U
798798
|| containerSize && endTopOffset - containerSize > 5;
799799
}
800800

801-
802801
/**
803802
* @hidden
804803
* Function that recalculates and updates cache sizes.
805804
*/
806805
public recalcUpdateSizes() {
807-
const dimension = this.igxForScrollOrientation === 'horizontal' ?
808-
this.igxForSizePropName : 'height';
806+
const dimension = this.igxForScrollOrientation === 'horizontal' ? this.igxForSizePropName : 'height';
809807
const diffs = [];
810808
let totalDiff = 0;
811809
const l = this._embeddedViews.length;
810+
812811
const rNodes = this._embeddedViews.map(view =>
813812
view.rootNodes.find(node => node.nodeType === Node.ELEMENT_NODE) || view.rootNodes[0].nextElementSibling);
813+
814814
for (let i = 0; i < l; i++) {
815815
const rNode = rNodes[i];
816816
if (rNode) {
817817
const height = window.getComputedStyle(rNode).getPropertyValue('height');
818-
const h = parseFloat(height) || parseInt(this.igxForItemSize, 10);
818+
const h = parseFloat(height);
819819
const index = this.state.startIndex + i;
820+
820821
if (!this.isRemote && !this.igxForOf[index]) {
821822
continue;
822823
}
823-
const margin = this.getMargin(rNode, dimension);
824-
const oldVal = this.individualSizeCache[index];
825-
const newVal = (dimension === 'height' ? h : rNode.clientWidth) + margin;
824+
825+
const oldVal = this.individualSizeCache[index] || 0;
826+
const newVal = h + this.getMargin(rNode, dimension);
826827
this.individualSizeCache[index] = newVal;
827828
const currDiff = newVal - oldVal;
828829
diffs.push(currDiff);
829830
totalDiff += currDiff;
830-
this.sizesCache[index + 1] += totalDiff;
831+
832+
this.sizesCache[index + 1] = this.sizesCache[index] + newVal;
831833
}
832834
}
833-
// update cache
834-
if (Math.abs(totalDiff) > 0) {
835-
for (let j = this.state.startIndex + this.state.chunkSize + 1; j < this.sizesCache.length; j++) {
836-
this.sizesCache[j] += totalDiff;
837-
}
838835

839-
// update scrBar heights/widths
840-
const reducer = (acc, val) => acc + val;
836+
for (let j = this.state.startIndex + this.state.chunkSize + 1; j < this.sizesCache.length; j++) {
837+
this.sizesCache[j] += totalDiff;
838+
}
841839

842-
const hSum = this.individualSizeCache.reduce(reducer);
843-
if (hSum > this._maxSize) {
844-
this._virtRatio = hSum / this._maxSize;
845-
}
846-
this.scrollComponent.size = Math.min(this.scrollComponent.size + totalDiff, this._maxSize);
847-
this._virtSize = hSum;
848-
if (!this.scrollComponent.destroyed) {
849-
this.scrollComponent.cdr.detectChanges();
850-
}
851-
const scrToBottom = this._isScrolledToBottom && !this.dc.instance.notVirtual;
852-
if (scrToBottom && !this._isAtBottomIndex) {
853-
const containerSize = parseInt(this.igxForContainerSize, 10);
854-
const maxVirtScrollTop = this._virtSize - containerSize;
855-
this._bScrollInternal = true;
856-
this._virtScrollPosition = maxVirtScrollTop;
857-
this.scrollPosition = maxVirtScrollTop;
858-
return;
859-
}
860-
if (this._adjustToIndex) {
861-
// in case scrolled to specific index where after scroll heights are changed
862-
// need to adjust the offsets so that item is last in view.
863-
const updatesToIndex = this._adjustToIndex - this.state.startIndex + 1;
864-
const sumDiffs = diffs.slice(0, updatesToIndex).reduce(reducer);
865-
if (sumDiffs !== 0) {
866-
this.addScroll(sumDiffs);
867-
}
868-
this._adjustToIndex = null;
869-
}
840+
const oldScrollSize = this.scrollComponent.size;
841+
this.scrollComponent.size = this._calcSize();
842+
843+
if (this.scrollComponent.size !== oldScrollSize) {
844+
this._zone.run(() => {
845+
this.scrollbarVisibilityChanged.emit();
846+
this.contentSizeChange.emit();
847+
});
848+
}
849+
850+
if (Math.abs(totalDiff) > 0) {
851+
this._adjustScrollPositionAfterSizeChange(totalDiff);
870852
}
871853
}
872854

projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.navigation.spec.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { clearGridSubs, setupHierarchicalGridScrollDetection } from '../../test-
1111
import { GridFunctions } from '../../test-utils/grid-functions.spec';
1212
import { IgxGridCellComponent } from '../cell.component';
1313
import { IGridCellEventArgs, IgxColumnComponent } from '../public_api';
14+
import { IgxHierarchicalGridDefaultComponent } from '../../test-utils/hierarchical-grid-components.spec';
15+
import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition';
1416

1517
const DEBOUNCE_TIME = 50;
1618
const GRID_CONTENT_CLASS = '.igx-grid__tbody-content';
@@ -30,7 +32,8 @@ describe('IgxHierarchicalGrid Navigation', () => {
3032
IgxHierarchicalGridTestBaseComponent,
3133
IgxHierarchicalGridTestComplexComponent,
3234
IgxHierarchicalGridMultiLayoutComponent,
33-
IgxHierarchicalGridSmallerChildComponent
35+
IgxHierarchicalGridSmallerChildComponent,
36+
IgxHierarchicalGridDefaultComponent
3437
]
3538
}).compileComponents();
3639
jasmine.DEFAULT_TIMEOUT_INTERVAL = defaultTimeout * 2;
@@ -634,6 +637,43 @@ describe('IgxHierarchicalGrid Navigation', () => {
634637

635638
expect(document.activeElement.tagName.toLowerCase()).toBe('input');
636639
});
640+
641+
it('should recalculate and update content correctly after filter is cleared, ensuring no empty areas post-filtering and scrolling', async () => {
642+
// eslint-disable-next-line @typescript-eslint/no-shadow
643+
const fixture = TestBed.createComponent(IgxHierarchicalGridDefaultComponent);
644+
fixture.detectChanges();
645+
// eslint-disable-next-line @typescript-eslint/no-shadow
646+
const hierarchicalGrid = fixture.componentInstance.hierarchicalGrid;
647+
fixture.detectChanges();
648+
await wait();
649+
650+
hierarchicalGrid.filter('Artist', 'd', IgxStringFilteringOperand.instance().condition('contains'));
651+
fixture.detectChanges();
652+
await wait();
653+
654+
hierarchicalGrid.expandRow(6);
655+
fixture.detectChanges();
656+
await wait();
657+
658+
hierarchicalGrid.verticalScrollContainer.getScroll().scrollTop = 2000;
659+
fixture.detectChanges();
660+
await wait(DEBOUNCE_TIME);
661+
662+
hierarchicalGrid.clearFilter();
663+
fixture.detectChanges();
664+
await wait();
665+
666+
hierarchicalGrid.verticalScrollContainer.getScroll().scrollTop = 2000;
667+
fixture.detectChanges();
668+
await wait(DEBOUNCE_TIME);
669+
670+
const hierarchicalGridRect = hierarchicalGrid.tbody.nativeElement.getBoundingClientRect();
671+
const lastRowRect = hierarchicalGrid.dataRowList.last.nativeElement.getBoundingClientRect();
672+
673+
const emptySpace = hierarchicalGridRect.bottom - lastRowRect.bottom;
674+
675+
expect(emptySpace).toBeLessThan(5);
676+
});
637677
});
638678

639679

projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-components.spec.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,3 +687,47 @@ class MyChildSummary {
687687
return result;
688688
}
689689
}
690+
691+
@Component({
692+
template: `
693+
<igx-hierarchical-grid [data]="data" [autoGenerate]="false" [allowFiltering]='true'
694+
[height]="'600px'" [width]="'100%'" [rowHeight]="'65px'" [primaryKey]="'ID'" #hierarchicalGrid>
695+
<igx-column field="ID" [hidden]="true"></igx-column>
696+
<igx-column field="Artist"></igx-column>
697+
<igx-column field="Debut" dataType="number"></igx-column>
698+
<igx-column field="GrammyNominations" header="Grammy Nominations" dataType="number"></igx-column>
699+
<igx-column field="GrammyAwards" header="Grammy Awards" dataType="number"></igx-column>
700+
701+
<igx-row-island [height]="null" [key]="'Albums'" [autoGenerate]="false" [allowFiltering]='true'>
702+
<igx-column field="Album"></igx-column>
703+
<igx-column field="LaunchDate" header="Launch Date" [dataType]="'date'"></igx-column>
704+
<igx-column field="BillboardReview" header="Billboard Review" dataType="number"></igx-column>
705+
<igx-column field="USBillboard200" header="US Billboard 200" dataType="number"></igx-column>
706+
<igx-row-island [height]="null" [key]="'Songs'" [autoGenerate]="false" >
707+
<igx-column field="Number" header="No."></igx-column>
708+
<igx-column field="Title"></igx-column>
709+
<igx-column field="Released" dataType="date"></igx-column>
710+
<igx-column field="Genre"></igx-column>
711+
</igx-row-island>
712+
</igx-row-island>
713+
714+
<igx-row-island [height]="null" [key]="'Tours'" [autoGenerate]="false" [allowFiltering]='true'>
715+
<igx-column field="Tour"></igx-column>
716+
<igx-column field="StartedOn" header="Started on"></igx-column>
717+
<igx-column field="Location"></igx-column>
718+
<igx-column field="Headliner"></igx-column>
719+
</igx-row-island>
720+
</igx-hierarchical-grid>`,
721+
standalone: true,
722+
imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent]
723+
})
724+
export class IgxHierarchicalGridDefaultComponent {
725+
@ViewChild('hierarchicalGrid', { read: IgxHierarchicalGridComponent, static: true })
726+
public hierarchicalGrid: IgxHierarchicalGridComponent;
727+
728+
public data;
729+
730+
constructor() {
731+
this.data = SampleTestData.hierarchicalGridSingersFullData();
732+
}
733+
}

0 commit comments

Comments
 (0)