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

IgniteUI / igniteui-angular / 23354069329

20 Mar 2026 05:11PM UTC coverage: 9.846% (-79.6%) from 89.462%
23354069329

Pull #17071

github

web-flow
Merge 742ad5a5c into 0018afe92
Pull Request #17071: fix(IgxGrid): Do not apply width constraint to groups.

905 of 16404 branches covered (5.52%)

Branch coverage included in aggregate %.

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

24265 existing lines in 328 files now uncovered.

3714 of 30509 relevant lines covered (12.17%)

6.21 hits per line

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

0.88
/projects/igniteui-angular/src/lib/input-group/input-group.component.ts
1
import { NgTemplateOutlet, NgClass } from '@angular/common';
2
import {
3
    ChangeDetectorRef,
4
    Component,
5
    ContentChild,
6
    ContentChildren,
7
    DestroyRef,
8
    ElementRef,
9
    HostBinding,
10
    HostListener, Inject, Input,
11
    Optional, QueryList, booleanAttribute,
12
    inject,
13
    DOCUMENT,
14
    AfterContentChecked
15
} from '@angular/core';
16
import { IInputResourceStrings, InputResourceStringsEN } from '../core/i18n/input-resources';
17
import { PlatformUtil, getComponentTheme } from '../core/utils';
18
import { IgxButtonDirective } from '../directives/button/button.directive';
19
import { IgxHintDirective } from '../directives/hint/hint.directive';
20
import {
21
    IgxInputDirective,
22
    IgxInputState
23
} from '../directives/input/input.directive';
24
import { IgxPrefixDirective } from '../directives/prefix/prefix.directive';
25
import { IgxSuffixDirective } from '../directives/suffix/suffix.directive';
26

27
import { IgxInputGroupBase } from './input-group.common';
28
import { IgxInputGroupType, IGX_INPUT_GROUP_TYPE } from './inputGroupType';
29
import { IgxIconComponent } from '../icon/icon.component';
30
import { getCurrentResourceStrings } from '../core/i18n/resources';
31
import { IgxTheme, THEME_TOKEN, ThemeToken } from '../services/theme/theme.token';
32

33
@Component({
34
    selector: 'igx-input-group',
35
    templateUrl: 'input-group.component.html',
36
    providers: [{ provide: IgxInputGroupBase, useExisting: IgxInputGroupComponent }],
37
    imports: [NgTemplateOutlet, IgxPrefixDirective, IgxButtonDirective, IgxSuffixDirective, IgxIconComponent]
38
})
39
export class IgxInputGroupComponent implements IgxInputGroupBase, AfterContentChecked {
3✔
40
    /**
41
     * Sets the resource strings.
42
     * By default it uses EN resources.
43
     */
44
    @Input()
45
    public set resourceStrings(value: IInputResourceStrings) {
46
        this._resourceStrings = Object.assign({}, this._resourceStrings, value);
×
47
    }
48

49
    /**
50
     * Returns the resource strings.
51
     */
52
    public get resourceStrings(): IInputResourceStrings {
UNCOV
53
        return this._resourceStrings;
×
54
    }
55

56
    /**
57
     * Property that enables/disables the auto-generated class of the `IgxInputGroupComponent`.
58
     * By default applied the class is applied.
59
     * ```typescript
60
     *  @ViewChild("MyInputGroup")
61
     *  public inputGroup: IgxInputGroupComponent;
62
     *  ngAfterViewInit(){
63
     *  this.inputGroup.defaultClass = false;
64
     * ```
65
     * }
66
     */
67
    @HostBinding('class.igx-input-group')
UNCOV
68
    public defaultClass = true;
×
69

70
    /** @hidden */
71
    @HostBinding('class.igx-input-group--placeholder')
UNCOV
72
    public hasPlaceholder = false;
×
73

74
    /** @hidden */
75
    @HostBinding('class.igx-input-group--required')
UNCOV
76
    public isRequired = false;
×
77

78
    /** @hidden */
79
    @HostBinding('class.igx-input-group--focused')
UNCOV
80
    public isFocused = false;
×
81

82
    /**
83
     * @hidden @internal
84
     * When truthy, disables the `IgxInputGroupComponent`.
85
     * Controlled by the underlying `IgxInputDirective`.
86
     * ```html
87
     * <igx-input-group [disabled]="true"></igx-input-group>
88
     * ```
89
     */
90
    @HostBinding('class.igx-input-group--disabled')
UNCOV
91
    public disabled = false;
×
92

93
    /**
94
     * Prevents automatically focusing the input when clicking on other elements in the input group (e.g. prefix or suffix).
95
     *
96
     * @remarks Automatic focus causes software keyboard to show on mobile devices.
97
     *
98
     * @example
99
     * ```html
100
     * <igx-input-group [suppressInputAutofocus]="true"></igx-input-group>
101
     * ```
102
     */
103
    @Input({ transform: booleanAttribute })
UNCOV
104
    public suppressInputAutofocus = false;
×
105

106
    /** @hidden */
107
    @HostBinding('class.igx-input-group--warning')
UNCOV
108
    public hasWarning = false;
×
109

110
    /** @hidden */
111
    @ContentChildren(IgxHintDirective, { read: IgxHintDirective })
112
    protected hints: QueryList<IgxHintDirective>;
113

114
    @ContentChildren(IgxPrefixDirective, { read: IgxPrefixDirective, descendants: true })
115
    protected _prefixes: QueryList<IgxPrefixDirective>;
116

117
    @ContentChildren(IgxSuffixDirective, { read: IgxSuffixDirective, descendants: true })
118
    protected _suffixes: QueryList<IgxSuffixDirective>;
119

120
    /** @hidden */
121
    @ContentChild(IgxInputDirective, { read: IgxInputDirective, static: true })
122
    protected input: IgxInputDirective;
123

UNCOV
124
    private _destroyRef = inject(DestroyRef);
×
UNCOV
125
    private _type: IgxInputGroupType = null;
×
UNCOV
126
    private _filled = false;
×
127
    private _theme: IgxTheme;
UNCOV
128
    private _resourceStrings = getCurrentResourceStrings(InputResourceStringsEN);
×
129
    private _readOnly: undefined | boolean;
130

131
    /** @hidden @internal */
132
    @HostBinding('class.igx-input-group--readonly')
133
    public get readOnly(): boolean {
UNCOV
134
        return this._readOnly ?? (this.input?.nativeElement.readOnly || false);
×
135
    }
136

137
    /** @hidden @internal */
138
    public set readOnly(value: boolean) {
UNCOV
139
        this._readOnly = value;
×
140
    }
141

142
    /** @hidden */
143
    @HostBinding('class.igx-input-group--valid')
144
    public get validClass(): boolean {
UNCOV
145
        return this.input.valid === IgxInputState.VALID;
×
146
    }
147

148
    /** @hidden */
149
    @HostBinding('class.igx-input-group--invalid')
150
    public get invalidClass(): boolean {
UNCOV
151
        return this.input.valid === IgxInputState.INVALID;
×
152
    }
153

154
    /** @hidden */
155
    @HostBinding('class.igx-input-group--filled')
156
    public get isFilled() {
UNCOV
157
        return this._filled || (this.input && this.input.value);
×
158
    }
159

160
    /** @hidden */
161
    @HostBinding('class.igx-input-group--textarea-group')
162
    public get textAreaClass(): boolean {
UNCOV
163
        return this.input.isTextArea;
×
164
    }
165

166
    /**
167
     * Sets how the input will be styled.
168
     * Allowed values of type IgxInputGroupType.
169
     * ```html
170
     * <igx-input-group [type]="'search'">
171
     * ```
172
     */
173
    @Input()
174
    public set type(value: IgxInputGroupType) {
UNCOV
175
        this._type = value;
×
176
    }
177

178
    /**
179
     * Returns the type of the `IgxInputGroupComponent`. How the input is styled.
180
     * The default is `line`.
181
     * ```typescript
182
     * @ViewChild("MyInputGroup")
183
     * public inputGroup: IgxInputGroupComponent;
184
     * ngAfterViewInit(){
185
     *    let inputType = this.inputGroup.type;
186
     * }
187
     * ```
188
     */
189
    public get type() {
UNCOV
190
        return this._type || this._inputGroupType || 'line';
×
191
    }
192

193
    /**
194
     * Sets the theme of the input.
195
     * Allowed values of type IgxInputGroupTheme.
196
     * ```typescript
197
     * @ViewChild("MyInputGroup")
198
     * public inputGroup: IgxInputGroupComponent;
199
     * ngAfterViewInit() {
200
     *  let inputTheme = 'fluent';
201
     * }
202
     */
203
    @Input()
204
    public set theme(value: IgxTheme) {
205
        this._theme = value;
×
206
    }
207

208
    /**
209
     * Returns the theme of the input.
210
     * The returned value is of type IgxInputGroupType.
211
     * ```typescript
212
     * @ViewChild("MyInputGroup")
213
     * public inputGroup: IgxInputGroupComponent;
214
     * ngAfterViewInit() {
215
     *  let inputTheme = this.inputGroup.theme;
216
     * }
217
     */
218
    public get theme(): IgxTheme {
UNCOV
219
        return this._theme;
×
220
    }
221

222
    constructor(
UNCOV
223
        public element: ElementRef<HTMLElement>,
×
224
        @Optional()
225
        @Inject(IGX_INPUT_GROUP_TYPE)
UNCOV
226
        private _inputGroupType: IgxInputGroupType,
×
227
        @Inject(DOCUMENT)
UNCOV
228
        private document: any,
×
UNCOV
229
        private platform: PlatformUtil,
×
UNCOV
230
        private cdr: ChangeDetectorRef,
×
231
        @Inject(THEME_TOKEN)
UNCOV
232
        private themeToken: ThemeToken
×
233
    ) {
UNCOV
234
        this._theme = this.themeToken.theme;
×
UNCOV
235
        const themeChange = this.themeToken.onChange((theme) => {
×
UNCOV
236
            if (this._theme !== theme) {
×
237
                this._theme = theme;
×
238
                this.cdr.detectChanges();
×
239
            }
240
        });
UNCOV
241
        this._destroyRef.onDestroy(() => themeChange.unsubscribe());
×
242
    }
243

244
    /** @hidden */
245
    @HostListener('click', ['$event'])
246
    public onClick(event: MouseEvent) {
UNCOV
247
        if (
×
248
            !this.isFocused &&
×
249
            event.target !== this.input.nativeElement &&
250
            !this.suppressInputAutofocus
251
        ) {
UNCOV
252
            this.input.focus();
×
253
        }
254
    }
255

256
    /** @hidden */
257
    @HostListener('pointerdown', ['$event'])
258
    public onPointerDown(event: PointerEvent) {
UNCOV
259
        if (this.isFocused && event.target !== this.input.nativeElement) {
×
UNCOV
260
            event.preventDefault();
×
261
        }
262
    }
263

264
    /** @hidden @internal */
265
    public hintClickHandler(event: MouseEvent) {
UNCOV
266
        event.stopPropagation();
×
267
    }
268

269
    /**
270
     * Returns whether the `IgxInputGroupComponent` has hints.
271
     * ```typescript
272
     * @ViewChild("MyInputGroup")
273
     * public inputGroup: IgxInputGroupComponent;
274
     * ngAfterViewInit(){
275
     *    let inputHints = this.inputGroup.hasHints;
276
     * }
277
     * ```
278
     */
279
    public get hasHints() {
280
        return this.hints.length > 0;
×
281
    }
282

283
    /** @hidden @internal */
284
    @HostBinding('class.igx-input-group--prefixed')
285
    public get hasPrefixes() {
UNCOV
286
        return this._prefixes.length > 0;
×
287
    }
288

289
    /** @hidden @internal */
290
    public set prefixes(items: QueryList<IgxPrefixDirective>) {
UNCOV
291
        this._prefixes = items;
×
292
    }
293

294
    /** @hidden @internal */
295
    @HostBinding('class.igx-input-group--suffixed')
296
    public get hasSuffixes() {
UNCOV
297
        return this._suffixes.length > 0 || this.isFileType && this.isFilled;
×
298
    }
299

300
    /** @hidden @internal */
301
    public set suffixes(items: QueryList<IgxSuffixDirective>) {
UNCOV
302
        this._suffixes = items;
×
303
    }
304

305
    /**
306
     * Returns whether the `IgxInputGroupComponent` has border.
307
     * ```typescript
308
     * @ViewChild("MyInputGroup")
309
     * public inputGroup: IgxInputGroupComponent;
310
     * ngAfterViewInit(){
311
     *    let inputBorder = this.inputGroup.hasBorder;
312
     * }
313
     * ```
314
     */
315
    public get hasBorder() {
UNCOV
316
        return (
×
317
            (this.type === 'line' || this.type === 'box') &&
×
318
            this._theme === 'material'
319
        );
320
    }
321

322
    /**
323
     * Returns whether the `IgxInputGroupComponent` type is line.
324
     * ```typescript
325
     * @ViewChild("MyInputGroup1")
326
     * public inputGroup: IgxInputGroupComponent;
327
     * ngAfterViewInit(){
328
     *    let isTypeLine = this.inputGroup.isTypeLine;
329
     * }
330
     * ```
331
     */
332
    public get isTypeLine(): boolean {
UNCOV
333
        return this.type === 'line' && this._theme === 'material';
×
334
    }
335

336
    /**
337
     * Returns whether the `IgxInputGroupComponent` type is box.
338
     * ```typescript
339
     * @ViewChild("MyInputGroup1")
340
     * public inputGroup: IgxInputGroupComponent;
341
     * ngAfterViewInit(){
342
     *    let isTypeBox = this.inputGroup.isTypeBox;
343
     * }
344
     * ```
345
     */
346
    @HostBinding('class.igx-input-group--box')
347
    public get isTypeBox() {
UNCOV
348
        return this.type === 'box' && this._theme === 'material';
×
349
    }
350

351
    /** @hidden @internal */
352
    public clearValueHandler() {
UNCOV
353
        this.input.clear();
×
354
    }
355

356
    /** @hidden @internal */
357
    @HostBinding('class.igx-input-group--file')
358
    public get isFileType() {
UNCOV
359
        return this.input.type === 'file';
×
360
    }
361

362
    /** @hidden @internal */
363
    @HostBinding('class.igx-file-input')
364
    public get isFileInput() {
UNCOV
365
        return this.input.type === 'file';
×
366
    }
367

368
    /** @hidden @internal */
369
    @HostBinding('class.igx-file-input--filled')
370
    public get isFileInputFilled() {
UNCOV
371
        return this.isFileType && this.isFilled;
×
372
    }
373

374
    /** @hidden @internal */
375
    @HostBinding('class.igx-file-input--focused')
376
    public get isFileInputFocused() {
UNCOV
377
        return this.isFileType && this.isFocused;
×
378
    }
379

380
    /** @hidden @internal */
381
    @HostBinding('class.igx-file-input--disabled')
382
    public get isFileInputDisabled() {
UNCOV
383
        return this.isFileType && this.disabled;
×
384
    }
385

386
    /** @hidden @internal */
387
    public get fileNames() {
UNCOV
388
        return this.input.fileNames || this._resourceStrings.igx_input_file_placeholder;
×
389
    }
390

391
    /**
392
     * Returns whether the `IgxInputGroupComponent` type is border.
393
     * ```typescript
394
     * @ViewChild("MyInputGroup1")
395
     * public inputGroup: IgxInputGroupComponent;
396
     * ngAfterViewInit(){
397
     *    let isTypeBorder = this.inputGroup.isTypeBorder;
398
     * }
399
     * ```
400
     */
401
    @HostBinding('class.igx-input-group--border')
402
    public get isTypeBorder() {
UNCOV
403
        return this.type === 'border' && this._theme === 'material';
×
404
    }
405

406
    /**
407
     * Returns true if the `IgxInputGroupComponent` theme is Fluent.
408
     * ```typescript
409
     * @ViewChild("MyInputGroup1")
410
     * public inputGroup: IgxInputGroupComponent;
411
     * ngAfterViewInit(){
412
     *    let isTypeFluent = this.inputGroup.isTypeFluent;
413
     * }
414
     * ```
415
     */
416
    @HostBinding('class.igx-input-group--fluent')
417
    public get isTypeFluent() {
UNCOV
418
        return this._theme === 'fluent';
×
419
    }
420

421
    /**
422
     * Returns true if the `IgxInputGroupComponent` theme is Bootstrap.
423
     * ```typescript
424
     * @ViewChild("MyInputGroup1")
425
     * public inputGroup: IgxInputGroupComponent;
426
     * ngAfterViewInit(){
427
     *    let isTypeBootstrap = this.inputGroup.isTypeBootstrap;
428
     * }
429
     * ```
430
     */
431
    @HostBinding('class.igx-input-group--bootstrap')
432
    public get isTypeBootstrap() {
UNCOV
433
        return this._theme === 'bootstrap';
×
434
    }
435

436
    /**
437
     * Returns true if the `IgxInputGroupComponent` theme is Indigo.
438
     * ```typescript
439
     * @ViewChild("MyInputGroup1")
440
     * public inputGroup: IgxInputGroupComponent;
441
     * ngAfterViewInit(){
442
     *    let isTypeIndigo = this.inputGroup.isTypeIndigo;
443
     * }
444
     * ```
445
     */
446
    @HostBinding('class.igx-input-group--indigo')
447
    public get isTypeIndigo() {
UNCOV
448
        return this._theme === 'indigo';
×
449
    }
450

451
    /**
452
     * Returns whether the `IgxInputGroupComponent` type is search.
453
     * ```typescript
454
     * @ViewChild("MyInputGroup1")
455
     * public inputGroup: IgxInputGroupComponent;
456
     * ngAfterViewInit(){
457
     *    let isTypeSearch = this.inputGroup.isTypeSearch;
458
     * }
459
     * ```
460
     */
461
    @HostBinding('class.igx-input-group--search')
462
    public get isTypeSearch() {
UNCOV
463
        if(!this.isFileType && !this.input.isTextArea) {
×
UNCOV
464
            return this.type === 'search';
×
465
        }
466
    }
467

468
    /** @hidden */
469
    public get filled() {
470
        return this._filled;
×
471
    }
472

473
    /** @hidden */
474
    public set filled(val) {
475
        this._filled = val;
×
476
    }
477

478
    private setComponentTheme() {
UNCOV
479
        if (!this.themeToken.preferToken) {
×
UNCOV
480
            const theme = getComponentTheme(this.element.nativeElement);
×
481

UNCOV
482
            if (theme && theme !== this._theme) {
×
483
                this.theme = theme;
×
484
                this.cdr.markForCheck();
×
485
            }
486
        }
487
    }
488

489
    /** @hidden @internal */
490
    public ngAfterContentChecked() {
UNCOV
491
        this.setComponentTheme();
×
492
    }
493
}
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