diff --git a/projects/igniteui-angular/dialog/src/dialog/dialog.component.spec.ts b/projects/igniteui-angular/dialog/src/dialog/dialog.component.spec.ts
index 64edc2735ec..81acbb65d1b 100644
--- a/projects/igniteui-angular/dialog/src/dialog/dialog.component.spec.ts
+++ b/projects/igniteui-angular/dialog/src/dialog/dialog.component.spec.ts
@@ -1,4 +1,4 @@
-import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core';
+import { Component, ViewChild, ChangeDetectionStrategy, provideZonelessChangeDetection, signal } from '@angular/core';
import { TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
@@ -691,3 +691,59 @@ class PositionSettingsDialogComponent {
};
}
+
+@Component({
+ template: `
+ `,
+ changeDetection: ChangeDetectionStrategy.Eager,
+ imports: [IgxDialogComponent]
+})
+class ZonelessDialogHostComponent {
+ @ViewChild('dialog', { static: true }) public dialog: IgxDialogComponent;
+ public readonly open = signal(false);
+}
+
+describe('Dialog - zoneless change detection', () => {
+ const DIALOG_WINDOW = '.igx-dialog__window';
+
+ const nextFrame = () => new Promise((resolve) => requestAnimationFrame(() => resolve()));
+
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [NoopAnimationsModule, ZonelessDialogHostComponent],
+ providers: [provideZonelessChangeDetection()]
+ }).compileComponents();
+ }));
+
+ afterEach(() => {
+ UIInteractions.clearOverlay();
+ });
+
+ it('renders the dialog when isOpen is set from an asynchronous callback', async () => {
+ const fixture = TestBed.createComponent(ZonelessDialogHostComponent);
+ fixture.detectChanges();
+
+ const host = fixture.debugElement.query(By.css('igx-dialog')).nativeElement as HTMLElement;
+ const dialog = fixture.componentInstance.dialog;
+
+ await new Promise(resolve => {
+ setTimeout(() => {
+ fixture.componentInstance.open.set(true);
+ resolve();
+ });
+ });
+ await fixture.whenStable();
+ await nextFrame();
+ await fixture.whenStable();
+
+ const dialogWindow = document.querySelector(DIALOG_WINDOW);
+ expect(dialog.isOpen).toBeTrue();
+ expect(dialog.isCollapsed).toBeFalse();
+ expect(dialogWindow).withContext('dialog window is in the DOM').not.toBeNull();
+ expect(dialogWindow?.getClientRects().length ?? 0)
+ .withContext('dialog window is actually rendered').toBeGreaterThan(0);
+ expect(host.classList.contains('igx-dialog--hidden'))
+ .withContext('host class mirrors isCollapsed')
+ .toBeFalse();
+ });
+});
diff --git a/projects/igniteui-angular/dialog/src/dialog/dialog.component.ts b/projects/igniteui-angular/dialog/src/dialog/dialog.component.ts
index 1761eb9248f..d9e8902f220 100644
--- a/projects/igniteui-angular/dialog/src/dialog/dialog.component.ts
+++ b/projects/igniteui-angular/dialog/src/dialog/dialog.component.ts
@@ -1,4 +1,4 @@
-import { Component, ElementRef, EventEmitter, HostBinding, Input, OnDestroy, OnInit, Output, ViewChild, AfterContentInit, booleanAttribute, inject, ChangeDetectionStrategy } from '@angular/core';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, Input, OnDestroy, OnInit, Output, ViewChild, AfterContentInit, booleanAttribute, inject } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { IgxNavigationService, IToggleView } from 'igniteui-angular/core';
@@ -46,6 +46,7 @@ let DIALOG_ID = 0;
imports: [IgxToggleDirective, IgxFocusTrapDirective, IgxFocusDirective, IgxButtonDirective, IgxRippleDirective]
})
export class IgxDialogComponent implements IToggleView, OnInit, OnDestroy, AfterContentInit {
+ private cdr = inject(ChangeDetectorRef);
private elementRef = inject(ElementRef);
private navService = inject(IgxNavigationService, { optional: true });
@@ -370,6 +371,7 @@ export class IgxDialogComponent implements IToggleView, OnInit, OnDestroy, After
if (value) {
requestAnimationFrame(() => {
this.open();
+ this.cdr.markForCheck();
});
} else {
this.close();