From 9263cf89c6babf04bd3d84bb7210d071bb7442a7 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. --- .../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 | 19 +++++++++++-------- 6 files changed, 34 insertions(+), 22 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/utils.ts b/projects/igniteui-angular/src/lib/core/utils.ts index b3c3994c7af..c12a4046a4d 100644 --- a/projects/igniteui-angular/src/lib/core/utils.ts +++ b/projects/igniteui-angular/src/lib/core/utils.ts @@ -450,12 +450,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 dcdb118ae8d..5b35548bb8c 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 47e10fb326e..8fd928e9042 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 @@ -99,10 +99,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 62dc87ebf0c..95f8fb8108e 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'; @@ -138,10 +138,11 @@ 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); + super(animationService, cdr, platform, dir); } @@ -150,12 +151,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 1a2695237ccbfd13b9cbb55ddcbd29e8578dd65c 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 c12a4046a4d..0bda0fc6ec6 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, InjectionToken, PLATFORM_ID, inject } 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'; @@ -449,16 +449,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 783886af82f961cb3a2eb248e02a35490ffff61b 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 0bda0fc6ec6..79c0e1ecb42 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, InjectionToken, PLATFORM_ID, inject } 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'; @@ -461,7 +461,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 79c0e1ecb42..a98cc78a034 100644 --- a/projects/igniteui-angular/src/lib/core/utils.ts +++ b/projects/igniteui-angular/src/lib/core/utils.ts @@ -452,6 +452,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); @@ -461,6 +462,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 | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/utils.ts b/projects/igniteui-angular/src/lib/core/utils.ts index a98cc78a034..509f4a26eda 100644 --- a/projects/igniteui-angular/src/lib/core/utils.ts +++ b/projects/igniteui-angular/src/lib/core/utils.ts @@ -451,8 +451,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 95f8fb8108e..b337fcf80d5 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts @@ -138,11 +138,11 @@ export class IgxTabsComponent extends IgxTabsDirective implements AfterViewInit, constructor( @Inject(IgxAngularAnimationService) animationService: AnimationService, cdr: ChangeDetectorRef, - platform: PlatformUtil, private ngZone: NgZone, dir: IgxDirectionality, + private platform: PlatformUtil ) { - super(animationService, cdr, platform, dir); + super(animationService, cdr, dir); }