Skip to content

Commit e2fd099

Browse files
crisbetojelbourn
authored andcommitted
refactor: handle stubbed window in SSR checks (#17755)
Uses the `isPlatformBrowser` to check whether we're rendering on the server in the `google-maps` and `youtube-player` packages, similarly to what we're doing in the CDK. This handles people stubbing out the `window`.
1 parent b2ea4c8 commit e2fd099

File tree

6 files changed

+46
-20
lines changed

6 files changed

+46
-20
lines changed

src/google-maps/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ ng_module(
1010
),
1111
module_name = "@angular/google-maps",
1212
deps = [
13+
"@npm//@angular/common",
1314
"@npm//@angular/core",
1415
"@npm//@types/googlemaps",
1516
"@npm//rxjs",

src/google-maps/google-map/google-map.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ import {
2020
OnInit,
2121
Output,
2222
ViewEncapsulation,
23+
Optional,
24+
Inject,
25+
PLATFORM_ID,
2326
} from '@angular/core';
27+
import {isPlatformBrowser} from '@angular/common';
2428
import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs';
2529
import {map, shareReplay, take, takeUntil} from 'rxjs/operators';
2630

@@ -48,12 +52,6 @@ export const DEFAULT_HEIGHT = '500px';
4852
/** Arbitrary default width for the map element */
4953
export const DEFAULT_WIDTH = '500px';
5054

51-
/**
52-
* Whether we're currently rendering inside a browser. Equivalent of `Platform.isBrowser`,
53-
* but copied over here so we don't have to add another dependency.
54-
*/
55-
const isBrowser = typeof window === 'object' && !!window;
56-
5755
/**
5856
* Angular component that renders a Google Map via the Google Maps JavaScript
5957
* API.
@@ -194,6 +192,8 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
194192
private _mapEl: HTMLElement;
195193
_googleMap!: UpdatedGoogleMap;
196194

195+
/** Whether we're currently rendering inside a browser. */
196+
private _isBrowser: boolean;
197197
private _googleMapChanges!: Observable<google.maps.Map>;
198198

199199
private _listeners: google.maps.MapsEventListener[] = [];
@@ -205,8 +205,19 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
205205

206206
private readonly _destroy = new Subject<void>();
207207

208-
constructor(private readonly _elementRef: ElementRef) {
209-
if (isBrowser) {
208+
constructor(
209+
private readonly _elementRef: ElementRef,
210+
/**
211+
* @deprecated `platformId` parameter to become required.
212+
* @breaking-change 10.0.0
213+
*/
214+
@Optional() @Inject(PLATFORM_ID) platformId?: Object) {
215+
216+
// @breaking-change 10.0.0 Remove null check for `platformId`.
217+
this._isBrowser =
218+
platformId ? isPlatformBrowser(platformId) : typeof window === 'object' && !!window;
219+
220+
if (this._isBrowser) {
210221
const googleMapsWindow: GoogleMapsWindow = window;
211222
if (!googleMapsWindow.google) {
212223
throw Error(
@@ -224,7 +235,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
224235

225236
ngOnInit() {
226237
// It should be a noop during server-side rendering.
227-
if (isBrowser) {
238+
if (this._isBrowser) {
228239
this._mapEl = this._elementRef.nativeElement.querySelector('.map-container')!;
229240
this._setSize();
230241

src/youtube-player/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ ng_module(
1919
),
2020
module_name = "@angular/youtube-player",
2121
deps = [
22+
"@npm//@angular/common",
2223
"@npm//@angular/core",
2324
"@npm//@types/youtube",
2425
"@npm//rxjs",

src/youtube-player/youtube-player.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ import {
2222
Output,
2323
ViewChild,
2424
ViewEncapsulation,
25+
Optional,
26+
Inject,
27+
PLATFORM_ID,
2528
} from '@angular/core';
29+
import {isPlatformBrowser} from '@angular/common';
2630

2731
import {
2832
combineLatest,
@@ -72,12 +76,6 @@ interface Player extends YT.Player {
7276
// The only field available is destroy and addEventListener.
7377
type UninitializedPlayer = Pick<Player, 'videoId' | 'destroy' | 'addEventListener'>;
7478

75-
/**
76-
* Whether we're currently rendering inside a browser. Equivalent of `Platform.isBrowser`,
77-
* but copied over here so we don't have to add another dependency.
78-
*/
79-
const isBrowser = typeof window === 'object' && !!window;
80-
8179
/**
8280
* Angular component that renders a YouTube player via the YouTube player
8381
* iframe API.
@@ -158,15 +156,28 @@ export class YouTubePlayer implements AfterViewInit, OnDestroy, OnInit {
158156
@ViewChild('youtubeContainer')
159157
youtubeContainer: ElementRef<HTMLElement>;
160158

159+
/** Whether we're currently rendering inside a browser. */
160+
private _isBrowser: boolean;
161161
private _youtubeContainer = new EventEmitter<HTMLElement>();
162162
private _destroyed = new EventEmitter<undefined>();
163163
private _player: Player | undefined;
164164

165-
constructor(private _ngZone: NgZone) {}
165+
constructor(
166+
private _ngZone: NgZone,
167+
/**
168+
* @deprecated `platformId` parameter to become required.
169+
* @breaking-change 10.0.0
170+
*/
171+
@Optional() @Inject(PLATFORM_ID) platformId?: Object) {
172+
173+
// @breaking-change 10.0.0 Remove null check for `platformId`.
174+
this._isBrowser =
175+
platformId ? isPlatformBrowser(platformId) : typeof window === 'object' && !!window;
176+
}
166177

167178
ngOnInit() {
168179
// Don't do anything if we're not in a browser environment.
169-
if (!isBrowser) {
180+
if (!this._isBrowser) {
170181
return;
171182
}
172183

@@ -340,7 +351,7 @@ export class YouTubePlayer implements AfterViewInit, OnDestroy, OnInit {
340351

341352
/** See https://developers.google.com/youtube/iframe_api_reference#getPlayerState */
342353
getPlayerState(): YT.PlayerState | undefined {
343-
if (!isBrowser || !window.YT) {
354+
if (!this._isBrowser || !window.YT) {
344355
return undefined;
345356
}
346357

tools/public_api_guard/google-maps/google-maps.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export declare class GoogleMap implements OnChanges, OnInit, OnDestroy {
2727
width: string;
2828
zoom: number;
2929
zoomChanged: EventEmitter<void>;
30-
constructor(_elementRef: ElementRef);
30+
constructor(_elementRef: ElementRef,
31+
platformId?: Object);
3132
fitBounds(bounds: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral, padding?: number | google.maps.Padding): void;
3233
getBounds(): google.maps.LatLngBounds | null;
3334
getCenter(): google.maps.LatLng;

tools/public_api_guard/youtube-player/youtube-player.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export declare class YouTubePlayer implements AfterViewInit, OnDestroy, OnInit {
1313
videoId: string | undefined;
1414
width: number | undefined;
1515
youtubeContainer: ElementRef<HTMLElement>;
16-
constructor(_ngZone: NgZone);
16+
constructor(_ngZone: NgZone,
17+
platformId?: Object);
1718
createEventsBoundInZone(): YT.Events;
1819
getAvailablePlaybackRates(): number[];
1920
getAvailableQualityLevels(): YT.SuggestedVideoQuality[];

0 commit comments

Comments
 (0)