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

IgniteUI / igniteui-angular / 12197035990

06 Dec 2024 10:18AM CUT coverage: 91.581% (-0.03%) from 91.613%
12197035990

Pull #15150

github

web-flow
Merge 01de31589 into 07d155736
Pull Request #15150: fix(*): icon service doesn't work with scoped themes

12977 of 15215 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.

26303 of 28721 relevant lines covered (91.58%)

33939.44 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
    standalone: true,
37
    imports: [NgIf, NgTemplateOutlet, IgxPrefixDirective, IgxButtonDirective, NgClass, IgxSuffixDirective, IgxIconComponent, NgSwitch, NgSwitchCase, NgSwitchDefault]
38
})
39
export class IgxInputGroupComponent implements IgxInputGroupBase, AfterViewInit {
2✔
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 {
53
        return this._resourceStrings;
35✔
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')
68
    public defaultClass = true;
2,492✔
69

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

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

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

106
    /** @hidden */
107
    @HostBinding('class.igx-input-group--warning')
108
    public hasWarning = false;
2,492✔
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

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

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

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

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

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

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

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

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

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

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

226
        const { unsubscribe } = this.themeToken.onChange((theme) => {
2,492✔
227
            if (this._theme !== theme) {
2,492!
NEW
228
                this._theme = 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,456✔
279
    }
280

281
    /** @hidden @internal */
282
    public set prefixes(items: QueryList<IgxPrefixDirective>) {
283
        this._prefixes = items;
443✔
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,456✔
290
    }
291

292
    /** @hidden @internal */
293
    public set suffixes(items: QueryList<IgxPrefixDirective>) {
294
        this._suffixes = items;
33✔
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,456✔
309
            (this.type === 'line' || this.type === 'box') &&
67,490✔
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';
52,922✔
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,304✔
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,466✔
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,456✔
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,456✔
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,456✔
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,466✔
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

© 2025 Coveralls, Inc