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

IgniteUI / igniteui-angular / 12162723460

04 Dec 2024 03:16PM UTC coverage: 91.594% (-0.03%) from 91.625%
12162723460

Pull #15140

github

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

12987 of 15227 branches covered (85.29%)

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

3 existing lines in 2 files now uncovered.

26324 of 28740 relevant lines covered (91.59%)

34042.73 hits per line

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

85.07
/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
        const { theme, preferToken } = this.themeToken;
2,492✔
223
        this._theme = theme;
2,492✔
224
        this._prefersTokenizedTheme = preferToken;
2,492✔
225

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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