window is not defined in Angular 17 command line but component works

216 Views Asked by At

I am building a custom video player as a practice project. This is the component that creates a container for the video player based on browser window size:

import { OnInit, Component, HostListener } from '@angular/core';

import { AppConstants } from '../../common/constants';

@Component({
  selector: 'app-video-player',
  standalone: true,
  imports: [],
  templateUrl: './video-player.component.html',
  styleUrl: './video-player.component.scss',
})
export class VideoPlayerComponent implements OnInit {
  videoStyle: any;

  constructor() {}

  ngOnInit(): void {
    this.generateVideoStyle(window.innerWidth, window.innerHeight);
  }

  generateVideoStyle(inpWidth: number, inpHeight: number): void {
    let playerWidth, playerHeight, playerMarginTop: number;
    playerWidth = 0.9 * inpWidth;
    if (playerWidth > AppConstants.MAX_VIDEO_WIDTH) {
      playerWidth = AppConstants.MAX_VIDEO_WIDTH;
    }
    playerHeight = playerWidth * AppConstants.VIDEO_ASPECT_RATIO;
    if (playerHeight > inpHeight) {
      playerHeight = 0.9 * inpHeight;
      playerWidth = playerHeight / AppConstants.VIDEO_ASPECT_RATIO;
    }
    playerMarginTop = (inpHeight - playerHeight) / 2.0;

    this.videoStyle = {
      height: `${playerHeight}px`,
      width: `${playerWidth}px`,
      marginTop: `${playerMarginTop}px`
    };
  }

  @HostListener('window:resize', ['$event'])
  onResize(event: any) {
    this.generateVideoStyle(event.target.innerWidth, event.target.innerHeight);
  }
}

The code works perfectly - container is sized correctly when app loads, resizes when browser window is expanded or shrunk. But I get this error in the command line:

ERROR ReferenceError: window is not defined
    at _VideoPlayerComponent.ngOnInit (/home/app/accordion-angular/src/app/video-player/components/video-player/video-player.component.ts:18:29)
    at callHookInternal (/home/app/accordion-angular/node_modules/@angular/core/fesm2022/core.mjs:3607:14)
    at callHook (/home/app/accordion-angular/node_modules/@angular/core/fesm2022/core.mjs:3634:13)
    at callHooks (/home/app/accordion-angular/node_modules/@angular/core/fesm2022/core.mjs:3589:17)
    at executeInitAndCheckHooks (/home/app/accordion-angular/node_modules/@angular/core/fesm2022/core.mjs:3539:9)
    at refreshView (/home/app/accordion-angular/node_modules/@angular/core/fesm2022/core.mjs:13556:21)
    at detectChangesInView (/home/app/accordion-angular/node_modules/@angular/core/fesm2022/core.mjs:13765:9)
    at detectChangesInViewIfAttached (/home/app/accordion-angular/node_modules/@angular/core/fesm2022/core.mjs:13728:5)
    at detectChangesInComponent (/home/app/accordion-angular/node_modules/@angular/core/fesm2022/core.mjs:13717:5)
    at detectChangesInChildComponents (/home/app/accordion-angular/node_modules/@angular/core/fesm2022/core.mjs:13778:9)

I read in another SO post, that with Angular 17 SSR, the dev server does not create the window object. So how am I able to access it in ngOnInit? Am I doing something wrong?

1

There are 1 best solutions below

4
Matthieu Riegler On

Your app has either prerendering or server-side rendering enable which means your app is also run in a node environment.

window is a browser only global that doesn't exist on node.

  injector = inject(Injector);

  ngOnInit(): void {
    afterNextRender(() => this.generateVideoStyle(window.innerWidth, window.innerHeight), {injector: this.injector});
  }

Your best alternative is to run your method on the client only by wrapping it with afterNextRender which run only in the client (and not the server/node).