diff --git a/projects/igniteui-angular-performance/src/app/app.component.html b/projects/igniteui-angular-performance/src/app/app.component.html index 8ca8b694e34..277913f006f 100644 --- a/projects/igniteui-angular-performance/src/app/app.component.html +++ b/projects/igniteui-angular-performance/src/app/app.component.html @@ -5,6 +5,10 @@ {{ route.title }} } + + diff --git a/projects/igniteui-angular-performance/src/app/app.component.ts b/projects/igniteui-angular-performance/src/app/app.component.ts index 109d49db6d3..d25206dadf1 100644 --- a/projects/igniteui-angular-performance/src/app/app.component.ts +++ b/projects/igniteui-angular-performance/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, ViewChild } from '@angular/core'; import { RouterLink, RouterOutlet, Routes } from '@angular/router'; import { IgxButtonDirective } from 'igniteui-angular'; import { routes } from './app.routes'; @@ -11,4 +11,24 @@ import { routes } from './app.routes'; }) export class AppComponent { protected routes: Routes = routes; + + @ViewChild(RouterOutlet) outlet!: RouterOutlet; + + public async OnPerfTest() { + const longTask = []; + const observer = new PerformanceObserver((list) => { + longTask.push(...list.getEntries()); + }); + observer.observe({ entryTypes: ['longtask'] }); + const grid = (this.outlet.component as any).grid || (this.outlet.component as any).pivotGrid; + for (let i = 0; i < 100; i++) { + grid.navigateTo(i * 50); + await new Promise(r => setTimeout(r, 50)); + } + const sum = longTask.reduce((acc, task) => acc + task.duration, 0); + const avgTime = sum / longTask.length; + console.log('Long Tasks:'+ longTask.length + ", ", 'Average Long Task Time:', avgTime); + observer.disconnect(); + + } } diff --git a/projects/igniteui-angular-performance/src/app/grid/grid.component.html b/projects/igniteui-angular-performance/src/app/grid/grid.component.html index 9cad429ffa8..dbc647f41e7 100644 --- a/projects/igniteui-angular-performance/src/app/grid/grid.component.html +++ b/projects/igniteui-angular-performance/src/app/grid/grid.component.html @@ -1,8 +1,9 @@
diff --git a/projects/igniteui-angular-performance/src/app/pivot-grid/pivot-grid.component.ts b/projects/igniteui-angular-performance/src/app/pivot-grid/pivot-grid.component.ts index e6d9f8593af..9070c7202a8 100644 --- a/projects/igniteui-angular-performance/src/app/pivot-grid/pivot-grid.component.ts +++ b/projects/igniteui-angular-performance/src/app/pivot-grid/pivot-grid.component.ts @@ -182,9 +182,9 @@ export class PivotGridComponent { sortDirection: SortingDirection.None }, { - fullDate: false, + fullDate: true, quarters: true, - months: false, + months: true, }), ], values: [ diff --git a/projects/igniteui-angular-performance/src/styles.scss b/projects/igniteui-angular-performance/src/styles.scss index f6fc0768f45..513b45895b7 100644 --- a/projects/igniteui-angular-performance/src/styles.scss +++ b/projects/igniteui-angular-performance/src/styles.scss @@ -1,4 +1,4 @@ -@use '../../igniteui-angular/src/lib/core/styles/themes' as *; +@use '../../igniteui-angular/core/src/core/styles/themes' as *; @import url('https://fonts.googleapis.com/icon?family=Material+Icons'); @include core(); @include typography( diff --git a/projects/igniteui-angular/directives/src/directives/for-of/base.helper.component.ts b/projects/igniteui-angular/directives/src/directives/for-of/base.helper.component.ts index 7df0cac709d..f3afbf0b949 100644 --- a/projects/igniteui-angular/directives/src/directives/for-of/base.helper.component.ts +++ b/projects/igniteui-angular/directives/src/directives/for-of/base.helper.component.ts @@ -43,11 +43,6 @@ export class VirtualHelperBaseDirective implements OnDestroy, AfterViewInit { this._scrollNativeSize = this.calculateScrollNativeSize(); } - @HostListener('scroll', ['$event']) - public onScroll(event) { - this.scrollAmount = event.target.scrollTop || event.target.scrollLeft; - } - public ngAfterViewInit() { this._afterViewInit = true; diff --git a/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.ts b/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.ts index 7d035ae2888..56c6f77d9f8 100644 --- a/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.ts +++ b/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.ts @@ -1,5 +1,5 @@ import { NgForOfContext } from '@angular/common'; -import { ChangeDetectorRef, ComponentRef, Directive, DoCheck, EmbeddedViewRef, EventEmitter, Input, IterableChanges, IterableDiffer, IterableDiffers, NgZone, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, TemplateRef, TrackByFunction, ViewContainerRef, AfterViewInit, booleanAttribute, DOCUMENT, inject } from '@angular/core'; +import { ChangeDetectorRef, ComponentRef, Directive, EmbeddedViewRef, EventEmitter, Input, IterableChanges, IterableDiffer, IterableDiffers, NgZone, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, TemplateRef, TrackByFunction, ViewContainerRef, AfterViewInit, booleanAttribute, DOCUMENT, inject, afterNextRender, runInInjectionContext, EnvironmentInjector } from '@angular/core'; import { DisplayContainerComponent } from './display.container'; import { HVirtualHelperComponent } from './horizontal.virtual.helper.component'; @@ -84,16 +84,17 @@ export abstract class IgxForOfToken { ], standalone: true }) -export class IgxForOfDirective extends IgxForOfToken implements OnInit, OnChanges, DoCheck, OnDestroy, AfterViewInit { +export class IgxForOfDirective extends IgxForOfToken implements OnInit, OnChanges, OnDestroy, AfterViewInit { private _viewContainer = inject(ViewContainerRef); protected _template = inject>>(TemplateRef); protected _differs = inject(IterableDiffers); + protected _injector = inject(EnvironmentInjector); public cdr = inject(ChangeDetectorRef); protected _zone = inject(NgZone); protected syncScrollService = inject(IgxForOfScrollSyncService); protected platformUtil = inject(PlatformUtil); protected document = inject(DOCUMENT); - + private _igxForOf: U & T[] | null = null; /** * Sets the data to be rendered. @@ -102,7 +103,14 @@ export class IgxForOfDirective extends IgxForOfToken extends IgxForOfToken extends IgxForOfToken extends IgxForOfToken { + afterNextRender({ + write: () => { + this.dc.instance._viewContainer.element.nativeElement.style.transform = `translateY(${-scrollOffset}px)`; + } + }); + }); } const maxRealScrollTop = this.scrollComponent.nativeElement.scrollHeight - containerSize; @@ -894,7 +908,13 @@ export class IgxForOfDirective extends IgxForOfToken { + afterNextRender({ + write: () => { + this.dc.instance._viewContainer.element.nativeElement.style.transform = `translateY(${-scrollOffset}px)`; + } + }); + }); this._zone.onStable.pipe(first()).subscribe(this.recalcUpdateSizes.bind(this)); @@ -1446,8 +1466,10 @@ export class IgxForOfDirective extends IgxForOfToken extends IgxForOfToken extends IgxForOfContext selector: '[igxGridFor][igxGridForOf]', standalone: true }) -export class IgxGridForOfDirective extends IgxForOfDirective implements OnInit, OnChanges, DoCheck { +export class IgxGridForOfDirective extends IgxForOfDirective implements OnInit, OnChanges { protected syncService = inject(IgxForOfSyncService); @Input() @@ -1626,7 +1648,7 @@ export class IgxGridForOfDirective extends IgxForOfDirec this.syncService.setMaster(this, true); } - public override ngDoCheck() { + public override resolveDataDiff() { if (this._differ) { const changes = this._differ.diff(this.igxForOf); if (changes) { @@ -1660,19 +1682,24 @@ export class IgxGridForOfDirective extends IgxForOfDirec } public override onScroll(event) { - if (!parseInt(this.scrollComponent.nativeElement.style.height, 10)) { + this.scrollComponent.scrollAmount = event.target.scrollTop; + if (!this.scrollComponent.size) { return; } if (!this._bScrollInternal) { - this._calcVirtualScrollPosition(event.target.scrollTop); + this._calcVirtualScrollPosition(this.scrollComponent.scrollAmount); } else { this._bScrollInternal = false; } const scrollOffset = this.fixedUpdateAllElements(this._virtScrollPosition); + runInInjectionContext(this._injector, () => { + afterNextRender({ + write: () => { + this.dc.instance._viewContainer.element.nativeElement.style.transform = `translateY(${-scrollOffset}px)`; + } + }); + }); - this.dc.instance._viewContainer.element.nativeElement.style.top = -(scrollOffset) + 'px'; - - this._zone.onStable.pipe(first()).subscribe(this.recalcUpdateSizes.bind(this)); this.cdr.markForCheck(); } diff --git a/projects/igniteui-angular/grids/grid/src/grid-base.directive.ts b/projects/igniteui-angular/grids/grid/src/grid-base.directive.ts index cb01b0beff7..cdf841a1388 100644 --- a/projects/igniteui-angular/grids/grid/src/grid-base.directive.ts +++ b/projects/igniteui-angular/grids/grid/src/grid-base.directive.ts @@ -2998,6 +2998,9 @@ export abstract class IgxGridBaseDirective implements GridType, /** @hidden @internal */ public resizeNotify = new Subject(); + /** @hidden @internal */ + public scrollNotify = new Subject(); + /** @hidden @internal */ public rowAddedNotifier = new Subject(); @@ -3709,6 +3712,15 @@ export abstract class IgxGridBaseDirective implements GridType, this.subscribeToTransactions(); + this.scrollNotify.pipe( + filter(() => !this._init), + throttleTime(40, animationFrameScheduler, { leading: false, trailing: true }), + destructor + ) + .subscribe((event) => { + this.verticalScrollHandler(event); + }); + this.resizeNotify.pipe( filter(() => !this._init), throttleTime(40, animationFrameScheduler, { leading: true, trailing: true }), @@ -4153,7 +4165,7 @@ export abstract class IgxGridBaseDirective implements GridType, this.zone.runOutsideAngular(() => { this.verticalScrollHandler = this.verticalScrollHandler.bind(this); this.horizontalScrollHandler = this.horizontalScrollHandler.bind(this); - this.verticalScrollContainer.getScroll().addEventListener('scroll', this.verticalScrollHandler); + this.verticalScrollContainer.getScroll().addEventListener('scroll', (event) => this.scrollNotify.next(event)); this.headerContainer?.getScroll().addEventListener('scroll', this.horizontalScrollHandler); if (this.hasColumnsToAutosize) { this.headerContainer?.dataChanged.pipe(takeUntil(this.destroy$)).subscribe(() => { @@ -7721,13 +7733,11 @@ export abstract class IgxGridBaseDirective implements GridType, this.verticalScrollContainer.onScroll(event); this.disableTransitions = true; - this.zone.run(() => { - this.zone.onStable.pipe(first()).subscribe(() => { - this.verticalScrollContainer.chunkLoad.emit(this.verticalScrollContainer.state); - if (this.rowEditable) { - this.changeRowEditingOverlayStateOnScroll(this.crudService.rowInEditMode); - } - }); + this.zone.onStable.pipe(first()).subscribe(() => { + this.verticalScrollContainer.chunkLoad.emit(this.verticalScrollContainer.state); + if (this.rowEditable) { + this.changeRowEditingOverlayStateOnScroll(this.crudService.rowInEditMode); + } }); this.disableTransitions = false;