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

IgniteUI / igniteui-angular / 12237118419

09 Dec 2024 01:55PM CUT coverage: 91.585% (-0.03%) from 91.613%
12237118419

Pull #15150

github

web-flow
Merge 4d9d2b458 into 90b93b228
Pull Request #15150: fix(*): icon service doesn't work with scoped themes

12977 of 15214 branches covered (85.3%)

45 of 53 new or added lines in 5 files covered. (84.91%)

1 existing line in 1 file now uncovered.

26293 of 28709 relevant lines covered (91.58%)

33975.95 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

221
        this.themeToken.onChange((theme) => {
2,492✔
222
            if (this._theme !== theme) {
2,492!
NEW
223
                this._theme = theme;
×
NEW
224
                this.cdr.detectChanges();
×
225
            }
226
        });
227
    }
228

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

442
    private setComponentTheme() {
443
        if (!this.themeToken.preferToken) {
2,492✔
444
            const theme = getComponentTheme(this.element.nativeElement);
2,492✔
445

446
            if (theme && theme !== this._theme) {
2,492!
NEW
447
                this.themeToken.set(theme);
×
NEW
448
                this.cdr.markForCheck();
×
449
            }
450
        }
451
    }
452

453
    /** @hidden @internal */
454
    public ngAfterViewInit() {
455
        this.setComponentTheme();
2,492✔
456
    }
457
}
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