Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions src/cdk/scrolling/virtual-scroll-viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ import {ListRange} from '../collections';
import {Platform} from '../platform';
import {
afterNextRender,
ApplicationRef,
booleanAttribute,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef,
effect,
ElementRef,
inject,
Inject,
Expand Down Expand Up @@ -170,8 +173,7 @@ export class CdkVirtualScrollViewport extends CdkVirtualScrollable implements On
*/
private _renderedContentOffsetNeedsRewrite = false;

/** Whether there is a pending change detection cycle. */
private _isChangeDetectionPending = false;
private _changeDetectionNeeded = signal(false);

/** A list of functions to run after the next change detection cycle. */
private _runAfterChangeDetection: Function[] = [];
Expand Down Expand Up @@ -202,6 +204,18 @@ export class CdkVirtualScrollViewport extends CdkVirtualScrollable implements On
this.elementRef.nativeElement.classList.add('cdk-virtual-scrollable');
this.scrollable = this;
}

const ref = effect(
() => {
if (this._changeDetectionNeeded()) {
this._doChangeDetection();
}
},
// Using ApplicationRef injector is important here because we want this to be a root
// effect that runs before change detection of any application views (since we're depending on markForCheck marking parents dirty)
{injector: inject(ApplicationRef).injector},
);
inject(DestroyRef).onDestroy(() => void ref.destroy());
}

override ngOnInit() {
Expand Down Expand Up @@ -488,16 +502,13 @@ export class CdkVirtualScrollViewport extends CdkVirtualScrollable implements On
this._runAfterChangeDetection.push(runAfter);
}

// Use a Promise to batch together calls to `_doChangeDetection`. This way if we set a bunch of
// properties sequentially we only have to run `_doChangeDetection` once at the end.
if (!this._isChangeDetectionPending) {
this._isChangeDetectionPending = true;
this.ngZone.runOutsideAngular(() =>
Promise.resolve().then(() => {
this._doChangeDetection();
}),
);
}
this.ngZone.runOutsideAngular(() => {
Promise.resolve().then(() => {
this.ngZone.run(() => {
this._changeDetectionNeeded.set(true);
});
});
});
}

/** Run change detection. */
Expand All @@ -520,7 +531,7 @@ export class CdkVirtualScrollViewport extends CdkVirtualScrollable implements On

afterNextRender(
() => {
this._isChangeDetectionPending = false;
this._changeDetectionNeeded.set(false);
const runAfterChangeDetection = this._runAfterChangeDetection;
this._runAfterChangeDetection = [];
for (const fn of runAfterChangeDetection) {
Expand Down
Loading