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

IgniteUI / igniteui-angular / 13416627295

19 Feb 2025 03:46PM CUT coverage: 91.615% (+0.02%) from 91.595%
13416627295

Pull #15246

github

web-flow
Merge 2a114cdda into 10ddb05cf
Pull Request #15246: fix(excel-export): Get correct grid column collection from row island…

12987 of 15218 branches covered (85.34%)

3 of 3 new or added lines in 1 file covered. (100.0%)

380 existing lines in 31 files now uncovered.

26385 of 28800 relevant lines covered (91.61%)

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

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

65

66

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

434
    protected destroy$ = new Subject<boolean>();
22✔
435

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

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

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

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

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

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

489
    }
490

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

505

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

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

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

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

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

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

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

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

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

591
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

© 2025 Coveralls, Inc