On using cdk-virtual-scroll-viewport in Angular SSR app and adding scrollWindow attribute, I am getting the following error:-
document is not defined
at _CdkVirtualScrollableWindow (...\test_cdk_scroll_ssr\node_modules\@angular\cdk\fesm2022\scrolling.mjs:1659:26)
at NodeInjectorFactory.CdkVirtualScrollableWindow_Factory (...\test_cdk_scroll_ssr\node_modules\@angular\cdk\fesm2022\scrolling.mjs:1667:14)
at getNodeInjectable (...\test_cdk_scroll_ssr\node_modules\@angular\core\fesm2022\core.mjs:5984:44)
at searchTokensOnInjector (...\test_cdk_scroll_ssr\node_modules\@angular\core\fesm2022\core.mjs:5911:16)
at lookupTokenUsingNodeInjector (...\test_cdk_scroll_ssr\node_modules\@angular\core\fesm2022\core.mjs:5860:34)
at getOrCreateInjectable (...\test_cdk_scroll_ssr\node_modules\@angular\core\fesm2022\core.mjs:5772:23)
at ɵɵdirectiveInject (...\test_cdk_scroll_ssr\node_modules\@angular\core\fesm2022\core.mjs:11050:19)
at ɵɵinject (...\test_cdk_scroll_ssr\node_modules\@angular\core\fesm2022\core.mjs:1106:42)
at NodeInjectorFactory.factory (...\test_cdk_scroll_ssr\node_modules\@angular\core\fesm2022\core.mjs:3325:29)
at getNodeInjectable (...\test_cdk_scroll_ssr\node_modules\@angular\core\fesm2022\core.mjs:5984:44
I followed the official example of scrollWindow attribute in an SSR app and it gave me the above error. This example works fine on non SSR angular apps.
My Code (exactly same as in the example)
app.component.ts:-
import { ChangeDetectionStrategy, Component } from '@angular/core';
import {ScrollingModule} from '@angular/cdk/scrolling';
@Component({
selector: 'app-root',
styleUrl: './app.component.scss',
templateUrl: './app.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [ScrollingModule]
})
export class AppComponent {
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
}
app.component.html
<div class="example-header">Content before</div>
<cdk-virtual-scroll-viewport scrollWindow itemSize="50">
<div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
</cdk-virtual-scroll-viewport>
<div class="example-footer">Content after</div>
app.component.scss:-
.example-item {
height: 50px;
}
.example-header,
.example-footer {
height: 100px;
background: lightgray;
}
Maybe it does not work because window is not available on server side?
Is there any way to make the scrollWindow attribute work in Angular SSR apps? thanks!
Yes. Make the virtual scroll render only when it's the browser, we can use isPlatformBrowser
and solve it:
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
import { NgIf } from '@angular/common';
import {ScrollingModule} from '@angular/cdk/scrolling';
@Component({
selector: 'app-root',
styleUrl: './app.component.scss',
templateUrl: './app.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [ScrollingModule, NgIf]
})
export class AppComponent {
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
isBrowser: boolean;
constructor( @Inject(PLATFORM_ID) platformId: Object) {
this.isBrowser = isPlatformBrowser(platformId);
}
}
HTML
<ng-container *ngIf="isBrowser">
<div class="example-header">Content before</div>
<cdk-virtual-scroll-viewport scrollWindow itemSize="50">
<div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
</cdk-virtual-scroll-viewport>
<div class="example-footer">Content after</div>
</ng-container>
By the way, the component works using the window
or document
object, so it is pointless to render on the server. It's a browser only functionality, due to use of window
or document
.