From 87d2407557bf5b51844adfb91e67da2ba0159122 Mon Sep 17 00:00:00 2001 From: wnvko Date: Fri, 7 Nov 2025 10:32:36 +0200 Subject: [PATCH 1/4] fix(toggle): in toggle call overlay show method after target element is visible --- .../lib/directives/toggle/toggle.directive.ts | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/projects/igniteui-angular/src/lib/directives/toggle/toggle.directive.ts b/projects/igniteui-angular/src/lib/directives/toggle/toggle.directive.ts index 72b44260461..0c0bd8405c0 100644 --- a/projects/igniteui-angular/src/lib/directives/toggle/toggle.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/toggle/toggle.directive.ts @@ -1,16 +1,19 @@ import { + afterNextRender, ChangeDetectorRef, Directive, ElementRef, EventEmitter, - HostBinding, HostListener, + inject, Inject, + Injector, Input, OnDestroy, OnInit, Optional, - Output + Output, + runInInjectionContext } from '@angular/core'; import { AbsoluteScrollStrategy } from '../../services/overlay/scroll/absolute-scroll-strategy'; import { CancelableBrowserEventArgs, IBaseEventArgs, PlatformUtil } from '../../core/utils'; @@ -34,7 +37,13 @@ export interface ToggleViewCancelableEventArgs extends ToggleViewEventArgs, Canc @Directive({ exportAs: 'toggle', selector: '[igxToggle]', - standalone: true + standalone: true, + host: { + '[class.igx-toggle--hidden]': 'hiddenClass', + '[attr.aria-hidden]': 'hiddenClass', + '[class.igx-toggle--hidden-webkit]': 'hiddenWebkitClass', + '[class.igx-toggle]': 'defaultClass' + } }) export class IgxToggleDirective implements IToggleView, OnInit, OnDestroy { /** @@ -159,13 +168,13 @@ export class IgxToggleDirective implements IToggleView, OnInit, OnDestroy { /** * @hidden */ - @HostBinding('class.igx-toggle--hidden') - @HostBinding('attr.aria-hidden') public get hiddenClass() { return this.collapsed; } - @HostBinding('class.igx-toggle--hidden-webkit') + /** + * @hidden + */ public get hiddenWebkitClass() { const isSafari = this.platform?.isSafari; const browserVersion = this.platform?.browserVersion; @@ -176,7 +185,6 @@ export class IgxToggleDirective implements IToggleView, OnInit, OnDestroy { /** * @hidden */ - @HostBinding('class.igx-toggle') public get defaultClass() { return !this.collapsed; } @@ -193,6 +201,7 @@ export class IgxToggleDirective implements IToggleView, OnInit, OnDestroy { private _overlayClosingSub: Subscription; private _overlayClosedSub: Subscription; private _overlayContentAppendedSub: Subscription; + private _injector = inject(Injector); /** * @hidden @@ -224,25 +233,28 @@ export class IgxToggleDirective implements IToggleView, OnInit, OnDestroy { } this._collapsed = false; - this.cdr.detectChanges(); - if (!info) { - this.unsubscribe(); - this.subscribe(); - this._overlayId = this.overlayService.attach(this.elementRef, overlaySettings); - } + runInInjectionContext(this._injector, () =>{ + afterNextRender(() => { + if (!info) { + this.unsubscribe(); + this.subscribe(); + this._overlayId = this.overlayService.attach(this.elementRef, overlaySettings); + } - const args: ToggleViewCancelableEventArgs = { cancel: false, owner: this, id: this._overlayId }; - this.opening.emit(args); - if (args.cancel) { - this.unsubscribe(); - this.overlayService.detach(this._overlayId); - this._collapsed = true; - delete this._overlayId; - this.cdr.detectChanges(); - return; - } - this.overlayService.show(this._overlayId, overlaySettings); + const args: ToggleViewCancelableEventArgs = { cancel: false, owner: this, id: this._overlayId }; + this.opening.emit(args); + if (args.cancel) { + this.unsubscribe(); + this.overlayService.detach(this._overlayId); + this._collapsed = true; + delete this._overlayId; + this.cdr.detectChanges(); + return; + } + this.overlayService.show(this._overlayId, overlaySettings); + }); + }); } /** From 13466e5b9ead4ec1df9c4f71ea7f0912a018a866 Mon Sep 17 00:00:00 2001 From: wnvko Date: Fri, 7 Nov 2025 10:50:58 +0200 Subject: [PATCH 2/4] fix(grid-toolbar): use auto position strategy for toolbar dropdowns --- .../src/lib/grids/toolbar/grid-toolbar.base.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/toolbar/grid-toolbar.base.ts b/projects/igniteui-angular/src/lib/grids/toolbar/grid-toolbar.base.ts index cb3a3c69c9a..e386ac9fad6 100644 --- a/projects/igniteui-angular/src/lib/grids/toolbar/grid-toolbar.base.ts +++ b/projects/igniteui-angular/src/lib/grids/toolbar/grid-toolbar.base.ts @@ -9,7 +9,7 @@ import { IgxColumnActionsComponent } from '../column-actions/column-actions.comp import { IgxToggleDirective, ToggleViewCancelableEventArgs, ToggleViewEventArgs } from '../../directives/toggle/toggle.directive'; import { HorizontalAlignment, OverlaySettings, VerticalAlignment } from '../../services/overlay/utilities'; import { IgxToolbarToken } from './token'; -import { ConnectedPositioningStrategy } from '../../services/overlay/position/connected-positioning-strategy'; +import { AutoPositionStrategy } from '../../services/overlay/position/auto-position-strategy'; /* blazorInclude */ /* blazorElement */ @@ -88,7 +88,7 @@ export abstract class BaseToolbarDirective implements OnDestroy { private $sub: Subscription; private _overlaySettings: OverlaySettings = { - positionStrategy: new ConnectedPositioningStrategy({ + positionStrategy: new AutoPositionStrategy({ horizontalDirection: HorizontalAlignment.Left, horizontalStartPoint: HorizontalAlignment.Right, verticalDirection: VerticalAlignment.Bottom, From adb98d5b1bbfc2a368287ff5eaa86037be0846d2 Mon Sep 17 00:00:00 2001 From: wnvko Date: Tue, 11 Nov 2025 14:45:10 +0200 Subject: [PATCH 3/4] fix(toggle): use workaround to apply host bound classes and attributes --- .../lib/directives/toggle/toggle.directive.ts | 52 ++++++++++--------- .../src/lib/services/overlay/overlay.ts | 8 ++- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/projects/igniteui-angular/src/lib/directives/toggle/toggle.directive.ts b/projects/igniteui-angular/src/lib/directives/toggle/toggle.directive.ts index 0c0bd8405c0..2e329eb71f7 100644 --- a/projects/igniteui-angular/src/lib/directives/toggle/toggle.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/toggle/toggle.directive.ts @@ -1,19 +1,15 @@ import { - afterNextRender, ChangeDetectorRef, Directive, ElementRef, EventEmitter, HostListener, - inject, Inject, - Injector, Input, OnDestroy, OnInit, Optional, Output, - runInInjectionContext } from '@angular/core'; import { AbsoluteScrollStrategy } from '../../services/overlay/scroll/absolute-scroll-strategy'; import { CancelableBrowserEventArgs, IBaseEventArgs, PlatformUtil } from '../../core/utils'; @@ -201,7 +197,6 @@ export class IgxToggleDirective implements IToggleView, OnInit, OnDestroy { private _overlayClosingSub: Subscription; private _overlayClosedSub: Subscription; private _overlayContentAppendedSub: Subscription; - private _injector = inject(Injector); /** * @hidden @@ -234,27 +229,34 @@ export class IgxToggleDirective implements IToggleView, OnInit, OnDestroy { this._collapsed = false; - runInInjectionContext(this._injector, () =>{ - afterNextRender(() => { - if (!info) { - this.unsubscribe(); - this.subscribe(); - this._overlayId = this.overlayService.attach(this.elementRef, overlaySettings); - } + // TODO: this is a workaround for the issue introduced by Angular's with Ivy renderer. + // When calling detectChanges(), Angular marks the element for check, but does not update the classes + // immediately, which causes the overlay to calculate incorrect dimensions of target element. + // Overlay show should be called in the next tick to ensure the classes are updated and target element is measured correctly. + // Note: across the codebase, each host binding should be checked and similar fix applied if needed!!! + this.elementRef.nativeElement.className = this.elementRef.nativeElement.className.replace('igx-toggle--hidden', 'igx-toggle'); + this.elementRef.nativeElement.className = this.elementRef.nativeElement.className.replace('igx-toggle--hidden-webkit', 'igx-toggle'); + this.elementRef.nativeElement.removeAttribute('aria-hidden'); - const args: ToggleViewCancelableEventArgs = { cancel: false, owner: this, id: this._overlayId }; - this.opening.emit(args); - if (args.cancel) { - this.unsubscribe(); - this.overlayService.detach(this._overlayId); - this._collapsed = true; - delete this._overlayId; - this.cdr.detectChanges(); - return; - } - this.overlayService.show(this._overlayId, overlaySettings); - }); - }); + this.cdr.detectChanges(); + + if (!info) { + this.unsubscribe(); + this.subscribe(); + this._overlayId = this.overlayService.attach(this.elementRef, overlaySettings); + } + + const args: ToggleViewCancelableEventArgs = { cancel: false, owner: this, id: this._overlayId }; + this.opening.emit(args); + if (args.cancel) { + this.unsubscribe(); + this.overlayService.detach(this._overlayId); + this._collapsed = true; + delete this._overlayId; + this.cdr.detectChanges(); + return; + } + this.overlayService.show(this._overlayId, overlaySettings); } /** diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.ts index 5cfccdf58e7..9267b1dff79 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.ts @@ -431,13 +431,19 @@ export class IgxOverlayService implements OnDestroy { } } this.updateSize(info); + const openAnimation = info.settings.positionStrategy.settings.openAnimation; + const closeAnimation = info.settings.positionStrategy.settings.closeAnimation; info.settings.positionStrategy.position( info.elementRef.nativeElement.parentElement, { width: info.initialSize.width, height: info.initialSize.height }, this._document, true, info.settings.target); - this.addModalClasses(info); + if (openAnimation !== info.settings.positionStrategy.settings.openAnimation || + closeAnimation !== info.settings.positionStrategy.settings.closeAnimation){ + this.addModalClasses(info); + } + this.buildAnimationPlayers(info); if (info.settings.positionStrategy.settings.openAnimation) { // TODO: should we build players again. This was already done in attach!!! // this.buildAnimationPlayers(info); From 7a8dd3d1edc5965e87f4e3aa5a87168aa3af5139 Mon Sep 17 00:00:00 2001 From: wnvko Date: Tue, 11 Nov 2025 14:48:49 +0200 Subject: [PATCH 4/4] chore(overlay): fix typo in overlay --- projects/igniteui-angular/src/lib/services/overlay/overlay.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.ts index 9267b1dff79..e8e511fb15c 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.ts @@ -441,9 +441,9 @@ export class IgxOverlayService implements OnDestroy { info.settings.target); if (openAnimation !== info.settings.positionStrategy.settings.openAnimation || closeAnimation !== info.settings.positionStrategy.settings.closeAnimation){ - this.addModalClasses(info); + this.buildAnimationPlayers(info); } - this.buildAnimationPlayers(info); + this.addModalClasses(info); if (info.settings.positionStrategy.settings.openAnimation) { // TODO: should we build players again. This was already done in attach!!! // this.buildAnimationPlayers(info);