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

IgniteUI / igniteui-angular / 13367757484

17 Feb 2025 10:08AM CUT coverage: 91.59% (-0.02%) from 91.607%
13367757484

Pull #15317

github

web-flow
Merge 2ba10379e into f9afd2aad
Pull Request #15317: Fixing tab navigation in simple combo - 18.2

12988 of 15226 branches covered (85.3%)

26322 of 28739 relevant lines covered (91.59%)

33995.51 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
    standalone: true,
36
    imports: [NgIf, NgTemplateOutlet, IgxPrefixDirective, IgxButtonDirective, NgClass, IgxSuffixDirective, IgxIconComponent, NgSwitch, NgSwitchCase, NgSwitchDefault]
37
})
38
export class IgxInputGroupComponent implements IgxInputGroupBase {
2✔
39
    /**
40
     * Sets the resource strings.
41
     * By default it uses EN resources.
42
     */
43
    @Input()
44
    public set resourceStrings(value: IInputResourceStrings) {
45
        this._resourceStrings = Object.assign({}, this._resourceStrings, value);
×
46
    }
47

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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