• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-angular / 13561607909

27 Feb 2025 08:03AM UTC coverage: 91.644% (+0.003%) from 91.641%
13561607909

push

github

web-flow
fix(grid): Update grid cell active state selector specificity (#15402)

13328 of 15596 branches covered (85.46%)

26882 of 29333 relevant lines covered (91.64%)

33708.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.11
/projects/igniteui-angular/src/lib/dialog/dialog.component.ts
1
import {
2
    Component,
3
    ElementRef,
4
    EventEmitter,
5
    HostBinding,
6
    Input,
7
    OnDestroy,
8
    OnInit,
9
    Optional,
10
    Output,
11
    ViewChild,
12
    AfterContentInit,
13
    booleanAttribute
14
} from '@angular/core';
15
import { Subject } from 'rxjs';
16
import { takeUntil } from 'rxjs/operators';
17
import { IgxNavigationService, IToggleView } from '../core/navigation';
18
import { IgxButtonType, IgxButtonDirective } from '../directives/button/button.directive';
19
import { IgxRippleDirective } from '../directives/ripple/ripple.directive';
20
import { IgxToggleDirective } from '../directives/toggle/toggle.directive';
21
import { OverlaySettings, GlobalPositionStrategy, NoOpScrollStrategy, PositionSettings } from '../services/public_api';
22
import { IgxFocusDirective } from '../directives/focus/focus.directive';
23
import { IgxFocusTrapDirective } from '../directives/focus-trap/focus-trap.directive';
24
import { CancelableEventArgs, IBaseEventArgs } from '../core/utils';
25
import { fadeIn, fadeOut } from 'igniteui-angular/animations';
26

27
let DIALOG_ID = 0;
2✔
28
/**
29
 * **Ignite UI for Angular Dialog Window** -
30
 * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/dialog.html)
31
 *
32
 * The Ignite UI Dialog Window presents a dialog window to the user which can simply display messages or display
33
 * more complicated visuals such as a user sign-in form.  It also provides a right and left button
34
 * which can be used for custom actions.
35
 *
36
 * Example:
37
 * ```html
38
 * <button type="button" igxButton (click)="form.open()">Show Dialog</button>
39
 * <igx-dialog #form title="Sign In" rightButtonLabel="OK">
40
 *   <div>
41
 *     <igx-input-group>
42
 *       <input type="text" igxInput/>
43
 *       <label igxLabel>Username</label>
44
 *     </igx-input-group>
45
 *   </div>
46
 *   <div>
47
 *     <igx-input-group>
48
 *       <input type="password" igxInput/>
49
 *       <label igxLabel>Password</label>
50
 *     </igx-input-group>
51
 *   </div>
52
 * </igx-dialog>
53
 * ```
54
 */
55
@Component({
56
    selector: 'igx-dialog',
57
    templateUrl: 'dialog-content.component.html',
58
    imports: [IgxToggleDirective, IgxFocusTrapDirective, IgxFocusDirective, IgxButtonDirective, IgxRippleDirective]
59
})
60
export class IgxDialogComponent implements IToggleView, OnInit, OnDestroy, AfterContentInit {
2✔
61
    private static NEXT_ID = 1;
2✔
62
    private static readonly DIALOG_CLASS = 'igx-dialog';
2✔
63

64

65

66
    @ViewChild(IgxToggleDirective, { static: true })
67
    public toggleRef: IgxToggleDirective;
68

69
    /**
70
     * Sets the value of the `id` attribute. If not provided it will be automatically generated.
71
     * ```html
72
     * <igx-dialog [id]="'igx-dialog-56'" #alert title="Notification"
73
     *  leftButtonLabel="OK" (leftButtonSelect)="alert.close()">
74
     * </igx-dialog>
75
     * ```
76
     */
77
    @HostBinding('attr.id')
78
    @Input()
79
    public id = `igx-dialog-${DIALOG_ID++}`;
231✔
80

81
    /**
82
     * Controls whether the dialog should be shown as modal. Defaults to `true`
83
     * ```html
84
     * <igx-dialog [isModal]="false" ></igx-dialog>
85
     * ```
86
     */
87
    @Input({ transform: booleanAttribute })
88
    public get isModal() {
89
        return this._isModal;
231✔
90
    }
91

92
    public set isModal(val: boolean) {
93
        this._overlayDefaultSettings.modal = val;
10✔
94
        this._isModal = val;
10✔
95
    }
96

97
    /**
98
     * Controls whether the dialog should close when `Esc` key is pressed. Defaults to `true`
99
     * ```html
100
     * <igx-dialog [closeOnEscape]="false" ></igx-dialog>
101
     * ```
102
     */
103
    @Input({ transform: booleanAttribute })
104
    public get closeOnEscape() {
105
        return this._closeOnEscape;
×
106
    }
107

108
    public set closeOnEscape(val: boolean) {
109
        this._overlayDefaultSettings.closeOnEscape = val;
×
110
        this._closeOnEscape = val;
×
111
    }
112

113
    /**
114
     * Set whether the Tab key focus is trapped within the dialog when opened.
115
     * Defaults to `true`.
116
     * ```html
117
     * <igx-dialog focusTrap="false""></igx-dialog>
118
     * ```
119
     */
120
    @Input({ transform: booleanAttribute })
121
    public focusTrap = true;
231✔
122

123
    /**
124
     * Sets the title of the dialog.
125
     * ```html
126
     * <igx-dialog title="Notification" #alert leftButtonLabel="OK" (leftButtonSelect)="alert.close()"></igx-dialog>
127
     * ```
128
     */
129
    @Input()
130
    public title = '';
231✔
131

132
    /**
133
     *  Sets the message text of the dialog.
134
     * ```html
135
     * <igx-dialog message="Your email was sent!" #alert leftButtonLabel="OK" (leftButtonSelect)="alert.close()"></igx-dialog>
136
     * ```
137
     */
138
    @Input()
139
    public message = '';
231✔
140

141
    /**
142
     * Sets the `label` of the left button of the dialog.
143
     * ```html
144
     * <igx-dialog leftButtonLabel="OKAY" #alert title="Notification"  (leftButtonSelect)="alert.close()"></igx-dialog>
145
     * ```
146
     */
147
    @Input()
148
    public leftButtonLabel = '';
231✔
149

150
    /**
151
     * Sets the left button `type`. The types are `flat`, `contained` and `fab`.
152
     * The `flat` type button is a rectangle and doesn't have a shadow. <br>
153
     * The `contained` type button is also a rectangle but has a shadow. <br>
154
     * The `fab` type button is a circle with a shadow. <br>
155
     * The default value is `flat`.
156
     * ```html
157
     * <igx-dialog leftButtonType="contained" leftButtonLabel="OKAY" #alert (leftButtonSelect)="alert.close()"></igx-dialog>
158
     * ```
159
     */
160
    @Input()
161
    public leftButtonType: IgxButtonType = 'flat';
231✔
162

163
    /**
164
     * Sets the left button `ripple`. The `ripple` animates a click/tap to a component as a series of fading waves.
165
     * The property accepts all valid CSS color property values.
166
     * ```html
167
     * <igx-dialog leftButtonRipple="green" leftButtonLabel="OKAY" #alert (leftButtonSelect)="alert.close()"></igx-dialog>
168
     * ```
169
     */
170
    @Input()
171
    public leftButtonRipple = '';
231✔
172

173
    /**
174
     * Sets the `label` of the right button of the dialog.
175
     * ```html
176
     * <igx-dialog rightButtonLabel="OKAY" #alert title="Notification"  (leftButtonSelect)="alert.close()"></igx-dialog>
177
     * ```
178
     */
179
    @Input()
180
    public rightButtonLabel = '';
231✔
181

182
    /**
183
     * Sets the right button `type`. The types are `flat`, `contained` and `fab`.
184
     * The `flat` type button is a rectangle and doesn't have a shadow. <br>
185
     * The `contained` type button is also a rectangle but has a shadow. <br>
186
     * The `fab` type button is a circle with a shadow. <br>
187
     * The default value is `flat`.
188
     * ```html
189
     * <igx-dialog rightButtonType="fab" rightButtonLabel="OKAY" #alert (leftButtonSelect)="alert.close()"></igx-dialog>
190
     * ```
191
     */
192
    @Input()
193
    public rightButtonType: IgxButtonType = 'flat';
231✔
194

195
    /**
196
     * Sets the right button `ripple`.
197
     * ```html
198
     * <igx-dialog rightButtonRipple="green" rightButtonLabel="OKAY" #alert (leftButtonSelect)="alert.close()"></igx-dialog>
199
     * ```
200
     */
201
    @Input()
202
    public rightButtonRipple = '';
231✔
203

204
    /**
205
     * Gets/Sets whether the dialog should close on click outside the component. By default it's false.
206
     * ```html
207
     * <igx-dialog closeOnOutsideSelect="true" leftButtonLabel="Cancel" (leftButtonSelect)="dialog.close()"
208
     * rightButtonLabel="OK" rightButtonRipple="#4CAF50" (rightButtonSelect)="onDialogOKSelected($event)">
209
     * </igx-dialog>
210
     * ```
211
     */
212
    @Input({ transform: booleanAttribute })
213
    public get closeOnOutsideSelect() {
214
        return this._closeOnOutsideSelect;
241✔
215
    }
216

217
    public set closeOnOutsideSelect(val: boolean) {
218
        this._overlayDefaultSettings.closeOnOutsideClick = val;
12✔
219
        this._closeOnOutsideSelect = val;
12✔
220
    }
221

222
    /**
223
     * Get the position and animation settings used by the dialog.
224
     * ```typescript
225
     * @ViewChild('alert', { static: true }) public alert: IgxDialogComponent;
226
     * let currentPosition: PositionSettings = this.alert.positionSettings
227
     * ```
228
     */
229
    @Input()
230
    public get positionSettings(): PositionSettings {
231
        return this._positionSettings;
6✔
232
    }
233

234
    /**
235
     * Set the position and animation settings used by the dialog.
236
     * ```typescript
237
     * import { slideInLeft, slideOutRight } from 'igniteui-angular';
238
     * ...
239
     * @ViewChild('alert', { static: true }) public alert: IgxDialogComponent;
240
     *  public newPositionSettings: PositionSettings = {
241
     *      openAnimation: useAnimation(slideInTop, { params: { duration: '2000ms' } }),
242
     *      closeAnimation: useAnimation(slideOutBottom, { params: { duration: '2000ms'} }),
243
     *      horizontalDirection: HorizontalAlignment.Left,
244
     *      verticalDirection: VerticalAlignment.Middle,
245
     *      horizontalStartPoint: HorizontalAlignment.Left,
246
     *      verticalStartPoint: VerticalAlignment.Middle,
247
     *      minSize: { height: 100, width: 100 }
248
     *  };
249
     * this.alert.positionSettings = this.newPositionSettings;
250
     * ```
251
     */
252
    public set positionSettings(settings: PositionSettings) {
253
        this._positionSettings = settings;
4✔
254
        this._overlayDefaultSettings.positionStrategy = new GlobalPositionStrategy(this._positionSettings);
4✔
255
    }
256

257
    /**
258
     * The default `tabindex` attribute for the component
259
     *
260
     * @hidden
261
     */
262
    @HostBinding('attr.tabindex')
263
    public tabindex = -1;
231✔
264

265
    /**
266
     * An event that is emitted before the dialog is opened.
267
     * ```html
268
     * <igx-dialog (opening)="onDialogOpenHandler($event)" (leftButtonSelect)="dialog.close()" rightButtonLabel="OK">
269
     * </igx-dialog>
270
     * ```
271
     */
272
    @Output()
273
    public opening = new EventEmitter<IDialogCancellableEventArgs>();
231✔
274

275
    /**
276
     * An event that is emitted after the dialog is opened.
277
     * ```html
278
     * <igx-dialog (opened)="onDialogOpenedHandler($event)" (leftButtonSelect)="dialog.close()" rightButtonLabel="OK">
279
     * </igx-dialog>
280
     * ```
281
     */
282
    @Output()
283
    public opened = new EventEmitter<IDialogEventArgs>();
231✔
284

285
    /**
286
     * An event that is emitted before the dialog is closed.
287
     * ```html
288
     * <igx-dialog (closing)="onDialogCloseHandler($event)" title="Confirmation" leftButtonLabel="Cancel" rightButtonLabel="OK">
289
     * </igx-dialog>
290
     * ```
291
     */
292
    @Output()
293
    public closing = new EventEmitter<IDialogCancellableEventArgs>();
231✔
294

295
    /**
296
     * An event that is emitted after the dialog is closed.
297
     * ```html
298
     * <igx-dialog (closed)="onDialogClosedHandler($event)" title="Confirmation" leftButtonLabel="Cancel" rightButtonLabel="OK">
299
     * </igx-dialog>
300
     * ```
301
     */
302
    @Output()
303
    public closed = new EventEmitter<IDialogEventArgs>();
231✔
304

305
    /**
306
     * An event that is emitted when the left button is clicked.
307
     * ```html
308
     * <igx-dialog (leftButtonSelect)="onDialogOKSelected($event)" #dialog leftButtonLabel="OK" rightButtonLabel="Cancel">
309
     * </igx-dialog>
310
     * ```
311
     */
312
    @Output()
313
    public leftButtonSelect = new EventEmitter<IDialogEventArgs>();
231✔
314

315
    /**
316
     * An event that is emitted when the right button is clicked.
317
     * ```html
318
     * <igx-dialog (rightButtonSelect)="onDialogOKSelected($event)"
319
     * #dialog title="Confirmation" (leftButtonSelect)="dialog.close()" rightButtonLabel="OK"
320
     * rightButtonRipple="#4CAF50" closeOnOutsideSelect="true">
321
     * </igx-dialog>
322
     * ```
323
     */
324
    @Output()
325
    public rightButtonSelect = new EventEmitter<IDialogEventArgs>();
231✔
326

327
    /**
328
     * @hidden
329
     */
330
    @Output() public isOpenChange = new EventEmitter<boolean>();
231✔
331

332
    /**
333
     * @hidden
334
     */
335
    public get element() {
336
        return this.elementRef.nativeElement;
×
337
    }
338

339
    /**
340
     * Returns the value of state. Possible state values are "open" or "close".
341
     * ```typescript
342
     * @ViewChild("MyDialog")
343
     * public dialog: IgxDialogComponent;
344
     * ngAfterViewInit() {
345
     *     let dialogState = this.dialog.state;
346
     * }
347
     * ```
348
     */
349
    public get state(): string {
350
        return this.isOpen ? 'open' : 'close';
×
351
    }
352

353
    /**
354
     * State of the dialog.
355
     *
356
     * ```typescript
357
     * // get
358
     * let dialogIsOpen = this.dialog.isOpen;
359
     * ```
360
     *
361
     * ```html
362
     * <!--set-->
363
     * <igx-dialog [isOpen]='false'></igx-dialog>
364
     * ```
365
     *
366
     * Two-way data binding.
367
     * ```html
368
     * <!--set-->
369
     * <igx-dialog [(isOpen)]='model.isOpen'></igx-dialog>
370
     * ```
371
     */
372
    @Input({ transform: booleanAttribute })
373
    public get isOpen() {
374
        return this.toggleRef ? !this.toggleRef.collapsed : false;
10,174!
375
    }
376
    public set isOpen(value: boolean) {
377
        if (value !== this.isOpen) {
4✔
378
            this.isOpenChange.emit(value);
3✔
379
            if (value) {
3✔
380
                requestAnimationFrame(() => {
2✔
381
                    this.open();
2✔
382
                });
383
            } else {
384
                this.close();
1✔
385
            }
386
        }
387
    }
388

389
    @HostBinding('class.igx-dialog--hidden')
390
    public get isCollapsed() {
391
        return this.toggleRef.collapsed;
5,082✔
392
    }
393

394
    /**
395
     * Returns the value of the role of the dialog. The valid values are `dialog`, `alertdialog`, `alert`.
396
     * ```typescript
397
     * @ViewChild("MyDialog")
398
     * public dialog: IgxDialogComponent;
399
     * ngAfterViewInit() {
400
     *     let dialogRole = this.dialog.role;
401
     * }
402
     *  ```
403
     */
404
    @Input()
405
    public get role() {
406
        if (this.leftButtonLabel !== '' && this.rightButtonLabel !== '') {
5,130✔
407
            return 'dialog';
5,034✔
408
        } else if (
96✔
409
            this.leftButtonLabel !== '' ||
116✔
410
            this.rightButtonLabel !== ''
411
        ) {
412
            return 'alertdialog';
76✔
413
        } else {
414
            return 'alert';
20✔
415
        }
416
    }
417

418
    /**
419
     * Returns the value of the title id.
420
     * ```typescript
421
     *  @ViewChild("MyDialog")
422
     * public dialog: IgxDialogComponent;
423
     * ngAfterViewInit() {
424
     *     let dialogTitle = this.dialog.titleId;
425
     * }
426
     * ```
427
     */
428
    @Input()
429
    public get titleId() {
430
        return this._titleId;
10,241✔
431
    }
432

433
    protected destroy$ = new Subject<boolean>();
231✔
434

435
    private _positionSettings: PositionSettings = {
231✔
436
        openAnimation: fadeIn,
437
        closeAnimation: fadeOut
438
    };
439

440
    private _overlayDefaultSettings: OverlaySettings;
441
    private _closeOnOutsideSelect = false;
231✔
442
    private _closeOnEscape = true;
231✔
443
    private _isModal = true;
231✔
444
    private _titleId: string;
445

446
    constructor(
447
        private elementRef: ElementRef,
231✔
448
        @Optional() private navService: IgxNavigationService
231✔
449
    ) {
450
        this._titleId = IgxDialogComponent.NEXT_ID++ + '_title';
231✔
451

452
        this._overlayDefaultSettings = {
231✔
453
            positionStrategy: new GlobalPositionStrategy(this._positionSettings),
454
            scrollStrategy: new NoOpScrollStrategy(),
455
            modal: this.isModal,
456
            closeOnEscape: this._closeOnEscape,
457
            closeOnOutsideClick: this.closeOnOutsideSelect
458
        };
459
    }
460

461
    public ngAfterContentInit() {
462
        this.toggleRef.closing.pipe(takeUntil(this.destroy$)).subscribe((eventArgs) => this.emitCloseFromDialog(eventArgs));
231✔
463
        this.toggleRef.closed.pipe(takeUntil(this.destroy$)).subscribe((eventArgs) => this.emitClosedFromDialog(eventArgs));
231✔
464
        this.toggleRef.opened.pipe(takeUntil(this.destroy$)).subscribe((eventArgs) => this.emitOpenedFromDialog(eventArgs));
231✔
465
    }
466

467
    /**
468
     * A method that opens the dialog.
469
     *
470
     * @memberOf {@link IgxDialogComponent}
471
     * ```html
472
     * <button type="button" (click)="dialog.open() igxButton="contained">Trigger Dialog</button>
473
     * <igx-dialog #dialog></igx-dialog>
474
     * ```
475
     */
476
    public open(overlaySettings: OverlaySettings = this._overlayDefaultSettings) {
30✔
477
        const eventArgs: IDialogCancellableEventArgs = { dialog: this, event: null, cancel: false };
30✔
478
        this.opening.emit(eventArgs);
30✔
479
        if (!eventArgs.cancel) {
30✔
480
            overlaySettings = { ...{}, ... this._overlayDefaultSettings, ...overlaySettings };
30✔
481
            this.toggleRef.open(overlaySettings);
30✔
482
            this.isOpenChange.emit(true);
30✔
483
            if (!this.leftButtonLabel && !this.rightButtonLabel) {
30✔
484
                this.toggleRef.element.focus();
4✔
485
            }
486
        }
487

488
    }
489

490
    /**
491
     * A method that that closes the dialog.
492
     *
493
     *  @memberOf {@link IgxDialogComponent}
494
     * ```html
495
     * <button type="button" (click)="dialog.close() igxButton="contained">Trigger Dialog</button>
496
     * <igx-dialog #dialog></igx-dialog>
497
     * ```
498
     */
499
    public close() {
500
        // `closing` will emit from `toggleRef.closing` subscription
501
        this.toggleRef?.close();
53✔
502
    }
503

504

505
    /**
506
     * A method that opens/closes the dialog.
507
     *
508
     * @memberOf {@link IgxDialogComponent}
509
     * ```html
510
     * <button type="button" (click)="dialog.toggle() igxButton="contained">Trigger Dialog</button>
511
     * <igx-dialog #dialog></igx-dialog>
512
     * ```
513
     */
514
    public toggle() {
515
        if (this.isOpen) {
×
516
            this.close();
×
517
        } else {
518
            this.open();
×
519
        }
520
    }
521

522
    /**
523
     * @hidden
524
     */
525
    public onDialogSelected(event) {
526
        event.stopPropagation();
10✔
527
        if (
10✔
528
            this.isOpen &&
23✔
529
            this.closeOnOutsideSelect &&
530
            event.target.classList.contains(IgxDialogComponent.DIALOG_CLASS)
531
        ) {
532
            this.close();
3✔
533
        }
534
    }
535

536
    /**
537
     * @hidden
538
     */
539
    public onInternalLeftButtonSelect(event) {
540
        this.leftButtonSelect.emit({ dialog: this, event });
4✔
541
    }
542

543
    /**
544
     * @hidden
545
     */
546
    public onInternalRightButtonSelect(event) {
547
        this.rightButtonSelect.emit({ dialog: this, event });
3✔
548
    }
549

550
    /**
551
     * @hidden
552
     */
553
    public ngOnInit() {
554
        if (this.navService && this.id) {
231✔
555
            this.navService.add(this.id, this);
231✔
556
        }
557
    }
558
    /**
559
     * @hidden
560
     */
561
    public ngOnDestroy() {
562
        if (this.navService && this.id) {
231✔
563
            this.navService.remove(this.id);
231✔
564
        }
565
    }
566

567
    private emitCloseFromDialog(eventArgs) {
568
        const dialogEventsArgs = { dialog: this, event: eventArgs.event, cancel: eventArgs.cancel };
19✔
569
        this.closing.emit(dialogEventsArgs);
19✔
570
        eventArgs.cancel = dialogEventsArgs.cancel;
19✔
571
        if (!eventArgs.cancel) {
19✔
572
            this.isOpenChange.emit(false);
19✔
573
        }
574
    }
575

576
    private emitClosedFromDialog(eventArgs) {
577
        this.closed.emit({ dialog: this, event: eventArgs.event });
16✔
578
    }
579

580
    private emitOpenedFromDialog(eventArgs) {
581
        this.opened.emit({ dialog: this, event: eventArgs.event });
18✔
582
    }
583
}
584

585
export interface IDialogEventArgs extends IBaseEventArgs {
586
    dialog: IgxDialogComponent;
587
    event: Event;
588
}
589

590
export interface IDialogCancellableEventArgs extends IDialogEventArgs, CancelableEventArgs { }
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc