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

IgniteUI / igniteui-angular / 13367998041

17 Feb 2025 10:21AM CUT coverage: 91.612% (+0.007%) from 91.605%
13367998041

Pull #15318

github

web-flow
Merge 127739986 into f70d5774f
Pull Request #15318: Fixing tab navigation in simple combo - 19.0

12996 of 15234 branches covered (85.31%)

26345 of 28757 relevant lines covered (91.61%)

34103.61 hits per line

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

84.38
/projects/igniteui-angular/src/lib/input-group/input-group.component.ts
1
import { DOCUMENT, NgIf, NgTemplateOutlet, NgClass, NgSwitch, NgSwitchCase, NgSwitchDefault } 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
} from '@angular/core';
14
import { IInputResourceStrings, InputResourceStringsEN } from '../core/i18n/input-resources';
15
import { PlatformUtil, getComponentTheme } from '../core/utils';
16
import { IgxButtonDirective } from '../directives/button/button.directive';
17
import { IgxHintDirective } from '../directives/hint/hint.directive';
18
import {
19
    IgxInputDirective,
20
    IgxInputState
21
} from '../directives/input/input.directive';
22
import { IgxPrefixDirective } from '../directives/prefix/prefix.directive';
23
import { IgxSuffixDirective } from '../directives/suffix/suffix.directive';
24

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

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

47
    /**
48
     * Returns the resource strings.
49
     */
50
    public get resourceStrings(): IInputResourceStrings {
51
        return this._resourceStrings;
35✔
52
    }
53

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

68
    /** @hidden */
69
    @HostBinding('class.igx-input-group--placeholder')
70
    public hasPlaceholder = false;
2,519✔
71

72
    /** @hidden */
73
    @HostBinding('class.igx-input-group--required')
74
    public isRequired = false;
2,519✔
75

76
    /** @hidden */
77
    @HostBinding('class.igx-input-group--focused')
78
    public isFocused = false;
2,519✔
79

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

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

104
    /** @hidden */
105
    @HostBinding('class.igx-input-group--warning')
106
    public hasWarning = false;
2,519✔
107

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

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

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

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

122
    private _destroyRef = inject(DestroyRef);
2,519✔
123
    private _type: IgxInputGroupType = null;
2,519✔
124
    private _filled = false;
2,519✔
125
    private _theme: IgxTheme;
126
    private _resourceStrings = getCurrentResourceStrings(InputResourceStringsEN);
2,519✔
127

128
    /** @hidden */
129
    @HostBinding('class.igx-input-group--valid')
130
    public get validClass(): boolean {
131
        return this.input.valid === IgxInputState.VALID;
26,803✔
132
    }
133

134
    /** @hidden */
135
    @HostBinding('class.igx-input-group--invalid')
136
    public get invalidClass(): boolean {
137
        return this.input.valid === IgxInputState.INVALID;
26,803✔
138
    }
139

140
    /** @hidden */
141
    @HostBinding('class.igx-input-group--filled')
142
    public get isFilled() {
143
        return this._filled || (this.input && this.input.value);
26,873✔
144
    }
145

146
    /** @hidden */
147
    @HostBinding('class.igx-input-group--textarea-group')
148
    public get textAreaClass(): boolean {
149
        return this.input.isTextArea;
26,803✔
150
    }
151

152
    /**
153
     * Sets how the input will be styled.
154
     * Allowed values of type IgxInputGroupType.
155
     * ```html
156
     * <igx-input-group [type]="'search'">
157
     * ```
158
     */
159
    @Input()
160
    public set type(value: IgxInputGroupType) {
161
        this._type = value;
1,806✔
162
    }
163

164
    /**
165
     * Returns the type of the `IgxInputGroupComponent`. How the input is styled.
166
     * The default is `line`.
167
     * ```typescript
168
     * @ViewChild("MyInputGroup")
169
     * public inputGroup: IgxInputGroupComponent;
170
     * ngAfterViewInit(){
171
     *    let inputType = this.inputGroup.type;
172
     * }
173
     * ```
174
     */
175
    public get type() {
176
        return this._type || this._inputGroupType || 'line';
151,776✔
177
    }
178

179
    /**
180
     * Sets the theme of the input.
181
     * Allowed values of type IgxInputGroupTheme.
182
     * ```typescript
183
     * @ViewChild("MyInputGroup")
184
     * public inputGroup: IgxInputGroupComponent;
185
     * ngAfterViewInit() {
186
     *  let inputTheme = 'fluent';
187
     * }
188
     */
189
    @Input()
190
    public set theme(value: IgxTheme) {
191
        this._theme = value;
×
192
    }
193

194
    /**
195
     * Returns the theme of the input.
196
     * The returned value is of type IgxInputGroupType.
197
     * ```typescript
198
     * @ViewChild("MyInputGroup")
199
     * public inputGroup: IgxInputGroupComponent;
200
     * ngAfterViewInit() {
201
     *  let inputTheme = this.inputGroup.theme;
202
     * }
203
     */
204
    public get theme(): IgxTheme {
205
        return this._theme;
26,803✔
206
    }
207

208
    constructor(
209
        public element: ElementRef<HTMLElement>,
2,519✔
210
        @Optional()
211
        @Inject(IGX_INPUT_GROUP_TYPE)
212
        private _inputGroupType: IgxInputGroupType,
2,519✔
213
        @Inject(DOCUMENT)
214
        private document: any,
2,519✔
215
        private platform: PlatformUtil,
2,519✔
216
        private cdr: ChangeDetectorRef,
2,519✔
217
        @Inject(THEME_TOKEN)
218
        private themeToken: ThemeToken
2,519✔
219
    ) {
220
        this._theme = this.themeToken.theme;
2,519✔
221
        const themeChange = this.themeToken.onChange((theme) => {
2,519✔
222
            if (this._theme !== theme) {
2,519!
223
                this._theme = theme;
×
224
                this.cdr.detectChanges();
×
225
            }
226
        });
227
        this._destroyRef.onDestroy(() => themeChange.unsubscribe());
2,519✔
228
    }
229

230
    /** @hidden */
231
    @HostListener('click', ['$event'])
232
    public onClick(event: MouseEvent) {
233
        if (
152✔
234
            !this.isFocused &&
308✔
235
            event.target !== this.input.nativeElement &&
236
            !this.suppressInputAutofocus
237
        ) {
238
            this.input.focus();
67✔
239
        }
240
    }
241

242
    /** @hidden */
243
    @HostListener('pointerdown', ['$event'])
244
    public onPointerDown(event: PointerEvent) {
245
        if (this.isFocused && event.target !== this.input.nativeElement) {
11✔
246
            event.preventDefault();
3✔
247
        }
248
    }
249

250
    /** @hidden @internal */
251
    public hintClickHandler(event: MouseEvent) {
252
        event.stopPropagation();
2✔
253
    }
254

255
    /**
256
     * Returns whether the `IgxInputGroupComponent` has hints.
257
     * ```typescript
258
     * @ViewChild("MyInputGroup")
259
     * public inputGroup: IgxInputGroupComponent;
260
     * ngAfterViewInit(){
261
     *    let inputHints = this.inputGroup.hasHints;
262
     * }
263
     * ```
264
     */
265
    public get hasHints() {
266
        return this.hints.length > 0;
×
267
    }
268

269
    /** @hidden @internal */
270
    @HostBinding('class.igx-input-group--prefixed')
271
    public get hasPrefixes() {
272
        return this._prefixes.length > 0 || this.isFileType;
26,803✔
273
    }
274

275
    /** @hidden @internal */
276
    public set prefixes(items: QueryList<IgxPrefixDirective>) {
277
        this._prefixes = items;
471✔
278
    }
279

280
    /** @hidden @internal */
281
    @HostBinding('class.igx-input-group--suffixed')
282
    public get hasSuffixes() {
283
        return this._suffixes.length > 0 || this.isFileType && this.isFilled;
26,803✔
284
    }
285

286
    /** @hidden @internal */
287
    public set suffixes(items: QueryList<IgxPrefixDirective>) {
288
        this._suffixes = items;
35✔
289
    }
290

291
    /**
292
     * Returns whether the `IgxInputGroupComponent` has border.
293
     * ```typescript
294
     * @ViewChild("MyInputGroup")
295
     * public inputGroup: IgxInputGroupComponent;
296
     * ngAfterViewInit(){
297
     *    let inputBorder = this.inputGroup.hasBorder;
298
     * }
299
     * ```
300
     */
301
    public get hasBorder() {
302
        return (
26,803✔
303
            (this.type === 'line' || this.type === 'box') &&
68,527✔
304
            this._theme === 'material'
305
        );
306
    }
307

308
    /**
309
     * Returns whether the `IgxInputGroupComponent` type is line.
310
     * ```typescript
311
     * @ViewChild("MyInputGroup1")
312
     * public inputGroup: IgxInputGroupComponent;
313
     * ngAfterViewInit(){
314
     *    let isTypeLine = this.inputGroup.isTypeLine;
315
     * }
316
     * ```
317
     */
318
    public get isTypeLine(): boolean {
319
        return this.type === 'line' && this._theme === 'material';
45✔
320
    }
321

322
    /**
323
     * Returns whether the `IgxInputGroupComponent` type is box.
324
     * ```typescript
325
     * @ViewChild("MyInputGroup1")
326
     * public inputGroup: IgxInputGroupComponent;
327
     * ngAfterViewInit(){
328
     *    let isTypeBox = this.inputGroup.isTypeBox;
329
     * }
330
     * ```
331
     */
332
    @HostBinding('class.igx-input-group--box')
333
    public get isTypeBox() {
334
        return this.type === 'box' && this._theme === 'material';
53,616✔
335
    }
336

337
    /** @hidden @internal */
338
    public uploadButtonHandler() {
339
        this.input.nativeElement.click();
×
340
    }
341

342
    /** @hidden @internal */
343
    public clearValueHandler() {
344
        this.input.clear();
2✔
345
    }
346

347
    /** @hidden @internal */
348
    @HostBinding('class.igx-input-group--file')
349
    public get isFileType() {
350
        return this.input.type === 'file';
130,873✔
351
    }
352

353
    /** @hidden @internal */
354
    public get fileNames() {
355
        return this.input.fileNames || this._resourceStrings.igx_input_file_placeholder;
70✔
356
    }
357

358
    /**
359
     * Returns whether the `IgxInputGroupComponent` type is border.
360
     * ```typescript
361
     * @ViewChild("MyInputGroup1")
362
     * public inputGroup: IgxInputGroupComponent;
363
     * ngAfterViewInit(){
364
     *    let isTypeBorder = this.inputGroup.isTypeBorder;
365
     * }
366
     * ```
367
     */
368
    @HostBinding('class.igx-input-group--border')
369
    public get isTypeBorder() {
370
        return this.type === 'border' && this._theme === 'material';
26,813✔
371
    }
372

373
    /**
374
     * Returns true if the `IgxInputGroupComponent` theme is Fluent.
375
     * ```typescript
376
     * @ViewChild("MyInputGroup1")
377
     * public inputGroup: IgxInputGroupComponent;
378
     * ngAfterViewInit(){
379
     *    let isTypeFluent = this.inputGroup.isTypeFluent;
380
     * }
381
     * ```
382
     */
383
    @HostBinding('class.igx-input-group--fluent')
384
    public get isTypeFluent() {
385
        return this._theme === 'fluent';
26,803✔
386
    }
387

388
    /**
389
     * Returns true if the `IgxInputGroupComponent` theme is Bootstrap.
390
     * ```typescript
391
     * @ViewChild("MyInputGroup1")
392
     * public inputGroup: IgxInputGroupComponent;
393
     * ngAfterViewInit(){
394
     *    let isTypeBootstrap = this.inputGroup.isTypeBootstrap;
395
     * }
396
     * ```
397
     */
398
    @HostBinding('class.igx-input-group--bootstrap')
399
    public get isTypeBootstrap() {
400
        return this._theme === 'bootstrap';
26,803✔
401
    }
402

403
    /**
404
     * Returns true if the `IgxInputGroupComponent` theme is Indigo.
405
     * ```typescript
406
     * @ViewChild("MyInputGroup1")
407
     * public inputGroup: IgxInputGroupComponent;
408
     * ngAfterViewInit(){
409
     *    let isTypeIndigo = this.inputGroup.isTypeIndigo;
410
     * }
411
     * ```
412
     */
413
    @HostBinding('class.igx-input-group--indigo')
414
    public get isTypeIndigo() {
415
        return this._theme === 'indigo';
26,803✔
416
    }
417

418
    /**
419
     * Returns whether the `IgxInputGroupComponent` type is search.
420
     * ```typescript
421
     * @ViewChild("MyInputGroup1")
422
     * public inputGroup: IgxInputGroupComponent;
423
     * ngAfterViewInit(){
424
     *    let isTypeSearch = this.inputGroup.isTypeSearch;
425
     * }
426
     * ```
427
     */
428
    @HostBinding('class.igx-input-group--search')
429
    public get isTypeSearch() {
430
        return this.type === 'search';
26,813✔
431
    }
432

433
    /** @hidden */
434
    public get filled() {
435
        return this._filled;
×
436
    }
437

438
    /** @hidden */
439
    public set filled(val) {
440
        this._filled = val;
×
441
    }
442

443
    private setComponentTheme() {
444
        if (!this.themeToken.preferToken) {
18,391✔
445
            const theme = getComponentTheme(this.element.nativeElement);
18,391✔
446

447
            if (theme && theme !== this._theme) {
18,391!
448
                this.theme = theme;
×
449
                this.cdr.markForCheck();
×
450
            }
451
        }
452
    }
453

454
    /** @hidden @internal */
455
    public ngAfterContentChecked() {
456
        this.setComponentTheme();
18,391✔
457
    }
458
}
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