From 1c892f53ee85b5bb3a08e6df61c658d3c59f7f8e Mon Sep 17 00:00:00 2001 From: Martin Dragnev Date: Wed, 20 Nov 2024 17:43:35 +0200 Subject: [PATCH 1/5] fix(*): Fix resize observe and animation player errors when using Angular SSR. --- projects/igniteui-angular/src/lib/core/utils.ts | 14 ++++++++------ .../lib/directives/for-of/for_of.directive.ts | 6 ++++-- .../animation/angular-animation-player.ts | 4 +++- .../src/lib/tabs/tabs.directive.ts | 3 ++- .../src/lib/tabs/tabs/tab-header.component.ts | 10 ++++++---- .../src/lib/tabs/tabs/tabs.component.ts | 17 ++++++++++------- 6 files changed, 33 insertions(+), 21 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/utils.ts b/projects/igniteui-angular/src/lib/core/utils.ts index 8d30de4b84a..3f3fa4181e2 100644 --- a/projects/igniteui-angular/src/lib/core/utils.ts +++ b/projects/igniteui-angular/src/lib/core/utils.ts @@ -440,12 +440,14 @@ export const HEADER_KEYS = new Set([...Array.from(NAVIGATION_KEYS), 'escape', 'e * Related issue: https://github.com/angular/angular/issues/31712 */ export const resizeObservable = (target: HTMLElement): Observable => new Observable((observer) => { - const instance = new (getResizeObserver())((entries: ResizeObserverEntry[]) => { - observer.next(entries); - }); - instance.observe(target); - const unsubscribe = () => instance.disconnect(); - return unsubscribe; + if (isPlatformBrowser(PLATFORM_ID)) { + const instance = new (getResizeObserver())((entries: ResizeObserverEntry[]) => { + observer.next(entries); + }); + instance.observe(target); + const unsubscribe = () => instance.disconnect(); + return unsubscribe; + } }); /** diff --git a/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts b/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts index 814362aa687..a51dfed5d0b 100644 --- a/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts @@ -491,8 +491,10 @@ export class IgxForOfDirective extends IgxForOfToken { - this.contentObserver = new (getResizeObserver())(() => this.contentResizeNotify.next()); - this.contentObserver.observe(this.dc.instance._viewContainer.element.nativeElement); + if (this.platformUtil.isBrowser) { + this.contentObserver = new (getResizeObserver())(() => this.contentResizeNotify.next()); + this.contentObserver.observe(this.dc.instance._viewContainer.element.nativeElement); + } }); } } diff --git a/projects/igniteui-angular/src/lib/services/animation/angular-animation-player.ts b/projects/igniteui-angular/src/lib/services/animation/angular-animation-player.ts index 8602d9d7614..6a568814688 100644 --- a/projects/igniteui-angular/src/lib/services/animation/angular-animation-player.ts +++ b/projects/igniteui-angular/src/lib/services/animation/angular-animation-player.ts @@ -23,7 +23,9 @@ export class IgxAngularAnimationPlayer implements AnimationPlayer { // To workaround this we are getting the positions from the inner player. // This is logged in Angular here - https://github.com/angular/angular/issues/18891 // As soon as this is resolved we can remove this hack - this._innerPlayer = innerRenderer.engine.players[innerRenderer.engine.players.length - 1]; + const rendererEngine = innerRenderer.engine || innerRenderer.delegate.engine; + // A workaround because of Angular SSR is using some delegation. + this._innerPlayer = rendererEngine.players[rendererEngine.players.length - 1]; } public init(): void { diff --git a/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts b/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts index 3e554a22ad4..6240a2a223d 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts @@ -5,7 +5,7 @@ import { } from '@angular/core'; import { Subscription } from 'rxjs'; import { Direction, IgxCarouselComponentBase } from '../carousel/carousel-base'; -import { IBaseEventArgs } from '../core/utils'; +import { IBaseEventArgs, PlatformUtil } from '../core/utils'; import { IgxAngularAnimationService } from '../services/animation/angular-animation-service'; import { AnimationService } from '../services/animation/animation'; import { IgxDirectionality } from '../services/direction/directionality'; @@ -117,6 +117,7 @@ export abstract class IgxTabsDirective extends IgxCarouselComponentBase implemen constructor( @Inject(IgxAngularAnimationService) animationService: AnimationService, cdr: ChangeDetectorRef, + protected platform: PlatformUtil, public dir: IgxDirectionality) { super(animationService, cdr); } diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.ts b/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.ts index 77692aee39b..8f51ec280d5 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.ts @@ -103,10 +103,12 @@ export class IgxTabHeaderComponent extends IgxTabHeaderDirective implements Afte /** @hidden @internal */ public ngAfterViewInit(): void { this.ngZone.runOutsideAngular(() => { - this._resizeObserver = new (getResizeObserver())(() => { - this.tabs.realignSelectedIndicator(); - }); - this._resizeObserver.observe(this.nativeElement); + if (this.platform.isBrowser) { + this._resizeObserver = new (getResizeObserver())(() => { + this.tabs.realignSelectedIndicator(); + }); + this._resizeObserver.observe(this.nativeElement); + } }); } diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts index 438693a90f5..9d8c069f839 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts @@ -1,5 +1,5 @@ import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, HostBinding, Inject, Input, NgZone, OnDestroy, ViewChild } from '@angular/core'; -import { getResizeObserver, mkenum } from '../../core/utils'; +import { getResizeObserver, mkenum, PlatformUtil } from '../../core/utils'; import { IgxAngularAnimationService } from '../../services/animation/angular-animation-service'; import { AnimationService } from '../../services/animation/animation'; import { IgxDirectionality } from '../../services/direction/directionality'; @@ -128,6 +128,7 @@ export class IgxTabsComponent extends IgxTabsDirective implements AfterViewInit, constructor( @Inject(IgxAngularAnimationService) animationService: AnimationService, cdr: ChangeDetectorRef, + platform: PlatformUtil, private ngZone: NgZone, dir: IgxDirectionality) { super(animationService, cdr, dir); @@ -139,12 +140,14 @@ export class IgxTabsComponent extends IgxTabsDirective implements AfterViewInit, super.ngAfterViewInit(); this.ngZone.runOutsideAngular(() => { - this._resizeObserver = new (getResizeObserver())(() => { - this.updateScrollButtons(); - this.realignSelectedIndicator(); - }); - this._resizeObserver.observe(this.headerContainer.nativeElement); - this._resizeObserver.observe(this.viewPort.nativeElement); + if (this.platform.isBrowser) { + this._resizeObserver = new (getResizeObserver())(() => { + this.updateScrollButtons(); + this.realignSelectedIndicator(); + }); + this._resizeObserver.observe(this.headerContainer.nativeElement); + this._resizeObserver.observe(this.viewPort.nativeElement); + } }); } From 394c849f25d26415eb9f991a8b00c97832d28965 Mon Sep 17 00:00:00 2001 From: Martin Dragnev Date: Thu, 21 Nov 2024 17:00:22 +0200 Subject: [PATCH 2/5] chore(*): fix build. Change a check in resize observer creation --- .../igniteui-angular/src/lib/core/utils.ts | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/utils.ts b/projects/igniteui-angular/src/lib/core/utils.ts index 3f3fa4181e2..a8622aca59d 100644 --- a/projects/igniteui-angular/src/lib/core/utils.ts +++ b/projects/igniteui-angular/src/lib/core/utils.ts @@ -1,7 +1,7 @@ import { CurrencyPipe, formatDate as _formatDate, isPlatformBrowser } from '@angular/common'; import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; import { mergeWith } from 'lodash-es'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { setImmediate } from './setImmediate'; import { isDevMode } from '@angular/core'; @@ -439,16 +439,21 @@ export const HEADER_KEYS = new Set([...Array.from(NAVIGATION_KEYS), 'escape', 'e * Run the resizeObservable outside angular zone, because it patches the MutationObserver which causes an infinite loop. * Related issue: https://github.com/angular/angular/issues/31712 */ -export const resizeObservable = (target: HTMLElement): Observable => new Observable((observer) => { - if (isPlatformBrowser(PLATFORM_ID)) { - const instance = new (getResizeObserver())((entries: ResizeObserverEntry[]) => { - observer.next(entries); +export const resizeObservable = (target: HTMLElement): Observable => { + const resizeObserver = getResizeObserver(); + if (resizeObserver) { + return new Observable((observer) => { + const instance = new resizeObserver((entries: ResizeObserverEntry[]) => { + observer.next(entries); + }); + instance.observe(target); + const unsubscribe = () => instance.disconnect(); + return unsubscribe; }); - instance.observe(target); - const unsubscribe = () => instance.disconnect(); - return unsubscribe; + } else { + return of(); } -}); +} /** * @hidden From 11a4eef4dffb1767202865d0515921aecce33a25 Mon Sep 17 00:00:00 2001 From: Martin Dragnev Date: Thu, 21 Nov 2024 17:31:30 +0200 Subject: [PATCH 3/5] chore(*): Use never observable when on server --- projects/igniteui-angular/src/lib/core/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/utils.ts b/projects/igniteui-angular/src/lib/core/utils.ts index a8622aca59d..88b576c7063 100644 --- a/projects/igniteui-angular/src/lib/core/utils.ts +++ b/projects/igniteui-angular/src/lib/core/utils.ts @@ -1,7 +1,7 @@ import { CurrencyPipe, formatDate as _formatDate, isPlatformBrowser } from '@angular/common'; import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; import { mergeWith } from 'lodash-es'; -import { Observable, of } from 'rxjs'; +import { NEVER, Observable } from 'rxjs'; import { setImmediate } from './setImmediate'; import { isDevMode } from '@angular/core'; @@ -451,7 +451,7 @@ export const resizeObservable = (target: HTMLElement): Observable Date: Thu, 21 Nov 2024 17:35:54 +0200 Subject: [PATCH 4/5] chore(*): add comments --- projects/igniteui-angular/src/lib/core/utils.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/projects/igniteui-angular/src/lib/core/utils.ts b/projects/igniteui-angular/src/lib/core/utils.ts index 88b576c7063..bf69ce2562a 100644 --- a/projects/igniteui-angular/src/lib/core/utils.ts +++ b/projects/igniteui-angular/src/lib/core/utils.ts @@ -442,6 +442,7 @@ export const HEADER_KEYS = new Set([...Array.from(NAVIGATION_KEYS), 'escape', 'e export const resizeObservable = (target: HTMLElement): Observable => { const resizeObserver = getResizeObserver(); if (resizeObserver) { + // check whether we are on server env or client env return new Observable((observer) => { const instance = new resizeObserver((entries: ResizeObserverEntry[]) => { observer.next(entries); @@ -451,6 +452,7 @@ export const resizeObservable = (target: HTMLElement): Observable Date: Fri, 22 Nov 2024 11:19:53 +0200 Subject: [PATCH 5/5] chore(*): apply review comments --- projects/igniteui-angular/src/lib/core/utils.ts | 2 +- projects/igniteui-angular/src/lib/tabs/tabs.directive.ts | 3 +-- projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/utils.ts b/projects/igniteui-angular/src/lib/core/utils.ts index bf69ce2562a..d1180ec1d84 100644 --- a/projects/igniteui-angular/src/lib/core/utils.ts +++ b/projects/igniteui-angular/src/lib/core/utils.ts @@ -441,8 +441,8 @@ export const HEADER_KEYS = new Set([...Array.from(NAVIGATION_KEYS), 'escape', 'e */ export const resizeObservable = (target: HTMLElement): Observable => { const resizeObserver = getResizeObserver(); + // check whether we are on server env or client env if (resizeObserver) { - // check whether we are on server env or client env return new Observable((observer) => { const instance = new resizeObserver((entries: ResizeObserverEntry[]) => { observer.next(entries); diff --git a/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts b/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts index 6240a2a223d..3e554a22ad4 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts @@ -5,7 +5,7 @@ import { } from '@angular/core'; import { Subscription } from 'rxjs'; import { Direction, IgxCarouselComponentBase } from '../carousel/carousel-base'; -import { IBaseEventArgs, PlatformUtil } from '../core/utils'; +import { IBaseEventArgs } from '../core/utils'; import { IgxAngularAnimationService } from '../services/animation/angular-animation-service'; import { AnimationService } from '../services/animation/animation'; import { IgxDirectionality } from '../services/direction/directionality'; @@ -117,7 +117,6 @@ export abstract class IgxTabsDirective extends IgxCarouselComponentBase implemen constructor( @Inject(IgxAngularAnimationService) animationService: AnimationService, cdr: ChangeDetectorRef, - protected platform: PlatformUtil, public dir: IgxDirectionality) { super(animationService, cdr); } diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts index 9d8c069f839..be577ed456b 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts @@ -128,8 +128,8 @@ export class IgxTabsComponent extends IgxTabsDirective implements AfterViewInit, constructor( @Inject(IgxAngularAnimationService) animationService: AnimationService, cdr: ChangeDetectorRef, - platform: PlatformUtil, private ngZone: NgZone, + private platform: PlatformUtil, dir: IgxDirectionality) { super(animationService, cdr, dir); }