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

IgniteUI / igniteui-angular / 12166030900

04 Dec 2024 06:28PM UTC coverage: 91.601% (-0.02%) from 91.625%
12166030900

Pull #15140

github

web-flow
Merge 9322a9f27 into 47b2886a0
Pull Request #15140: fix(*): icon service doesn't work with scoped themes

12984 of 15223 branches covered (85.29%)

56 of 64 new or added lines in 5 files covered. (87.5%)

4 existing lines in 3 files now uncovered.

26326 of 28740 relevant lines covered (91.6%)

33986.03 hits per line

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

84.85
/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
    AfterViewInit,
4
    ChangeDetectorRef,
5
    Component,
6
    ContentChild,
7
    ContentChildren,
8
    DestroyRef,
9
    ElementRef,
10
    HostBinding,
11
    HostListener, Inject, Input,
12
    Optional, QueryList, booleanAttribute,
13
    inject
14
} from '@angular/core';
15
import { IInputResourceStrings, InputResourceStringsEN } from '../core/i18n/input-resources';
16
import { PlatformUtil, getComponentTheme } from '../core/utils';
17
import { IgxButtonDirective } from '../directives/button/button.directive';
18
import { IgxHintDirective } from '../directives/hint/hint.directive';
19
import {
20
    IgxInputDirective,
21
    IgxInputState
22
} from '../directives/input/input.directive';
23
import { IgxPrefixDirective } from '../directives/prefix/prefix.directive';
24
import { IgxSuffixDirective } from '../directives/suffix/suffix.directive';
25

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

32
@Component({
33
    selector: 'igx-input-group',
34
    templateUrl: 'input-group.component.html',
35
    providers: [{ provide: IgxInputGroupBase, useExisting: IgxInputGroupComponent }],
36
    imports: [NgIf, NgTemplateOutlet, IgxPrefixDirective, IgxButtonDirective, NgClass, IgxSuffixDirective, IgxIconComponent, NgSwitch, NgSwitchCase, NgSwitchDefault]
37
})
38
export class IgxInputGroupComponent implements IgxInputGroupBase, AfterViewInit {
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,492✔
68

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

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

77
    /** @hidden */
78
    @HostBinding('class.igx-input-group--focused')
79
    public isFocused = false;
2,492✔
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,492✔
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,492✔
104

105
    /** @hidden */
106
    @HostBinding('class.igx-input-group--warning')
107
    public hasWarning = false;
2,492✔
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,492✔
124
    private _type: IgxInputGroupType = null;
2,492✔
125
    private _filled = false;
2,492✔
126
    private _theme: IgxTheme;
127
    private _prefersTokenizedTheme = false;
2,492✔
128
    private _resourceStrings = getCurrentResourceStrings(InputResourceStringsEN);
2,492✔
129

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

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

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

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

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

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

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

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

210
    constructor(
211
        public element: ElementRef<HTMLElement>,
2,492✔
212
        @Optional()
213
        @Inject(IGX_INPUT_GROUP_TYPE)
214
        private _inputGroupType: IgxInputGroupType,
2,492✔
215
        @Inject(DOCUMENT)
216
        private document: any,
2,492✔
217
        private platform: PlatformUtil,
2,492✔
218
        private cdr: ChangeDetectorRef,
2,492✔
219
        @Inject(THEME_TOKEN)
220
        private themeToken: ThemeToken
2,492✔
221
    ) {
222
        this._theme = this.themeToken.theme;
2,492✔
223
        this._prefersTokenizedTheme = this.themeToken.preferToken;
2,492✔
224

225
        const { unsubscribe } = this.themeToken.onChange((theme) => {
2,492✔
226
            if (this._theme !== theme) {
2,492!
NEW
227
                this._theme = theme;
×
NEW
228
                this.cdr.detectChanges();
×
229
            }
230
        });
231

232
        this._destroyRef.onDestroy(() => unsubscribe);
2,492✔
233
    }
234

235
    /** @hidden */
236
    @HostListener('click', ['$event'])
237
    public onClick(event: MouseEvent) {
238
        if (
150✔
239
            !this.isFocused &&
303✔
240
            event.target !== this.input.nativeElement &&
241
            !this.suppressInputAutofocus
242
        ) {
243
            this.input.focus();
66✔
244
        }
245
    }
246

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

255
    /** @hidden @internal */
256
    public hintClickHandler(event: MouseEvent) {
257
        event.stopPropagation();
2✔
258
    }
259

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

274
    /** @hidden @internal */
275
    @HostBinding('class.igx-input-group--prefixed')
276
    public get hasPrefixes() {
277
        return this._prefixes.length > 0 || this.isFileType;
26,608✔
278
    }
279

280
    /** @hidden @internal */
281
    public set prefixes(items: QueryList<IgxPrefixDirective>) {
282
        this._prefixes = items;
448✔
283
    }
284

285
    /** @hidden @internal */
286
    @HostBinding('class.igx-input-group--suffixed')
287
    public get hasSuffixes() {
288
        return this._suffixes.length > 0 || this.isFileType && this.isFilled;
26,608✔
289
    }
290

291
    /** @hidden @internal */
292
    public set suffixes(items: QueryList<IgxPrefixDirective>) {
293
        this._suffixes = items;
35✔
294
    }
295

296
    /**
297
     * Returns whether the `IgxInputGroupComponent` has border.
298
     * ```typescript
299
     * @ViewChild("MyInputGroup")
300
     * public inputGroup: IgxInputGroupComponent;
301
     * ngAfterViewInit(){
302
     *    let inputBorder = this.inputGroup.hasBorder;
303
     * }
304
     * ```
305
     */
306
    public get hasBorder() {
307
        return (
26,608✔
308
            (this.type === 'line' || this.type === 'box') &&
67,946✔
309
            this._theme === 'material'
310
        );
311
    }
312

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

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

342
    /** @hidden @internal */
343
    public uploadButtonHandler() {
344
        this.input.nativeElement.click();
×
345
    }
346

347
    /** @hidden @internal */
348
    public clearValueHandler() {
349
        this.input.clear();
2✔
350
    }
351

352
    /** @hidden @internal */
353
    @HostBinding('class.igx-input-group--file')
354
    public get isFileType() {
355
        return this.input.type === 'file';
129,954✔
356
    }
357

358
    /** @hidden @internal */
359
    public get fileNames() {
360
        return this.input.fileNames || this._resourceStrings.igx_input_file_placeholder;
70✔
361
    }
362

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

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

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

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

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

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

443
    /** @hidden */
444
    public set filled(val) {
445
        this._filled = val;
×
446
    }
447

448
    private setComponentTheme() {
449
        if (!this._prefersTokenizedTheme) {
2,492✔
450
            const theme = getComponentTheme(this.element.nativeElement);
2,492✔
451

452
            if (theme && theme !== this._theme) {
2,492!
NEW
453
                this.themeToken.set(theme);
×
NEW
454
                this.cdr.markForCheck();
×
455
            }
456
        }
457
    }
458

459
    /** @hidden @internal */
460
    public ngAfterViewInit() {
461
        this.setComponentTheme();
2,492✔
462
    }
463
}
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