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

IgniteUI / igniteui-angular / 12300330513

12 Dec 2024 04:10PM CUT coverage: 91.592% (-0.03%) from 91.621%
12300330513

push

github

web-flow
Merge pull request #15120 from IgniteUI/19.0.x

Mass Merge 19.0.x to master

12984 of 15225 branches covered (85.28%)

86 of 106 new or added lines in 16 files covered. (81.13%)

12 existing lines in 3 files now uncovered.

26320 of 28736 relevant lines covered (91.59%)

34007.75 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
    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 _resourceStrings = getCurrentResourceStrings(InputResourceStringsEN);
2,492✔
128

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

135
    /** @hidden */
136
    @HostBinding('class.igx-input-group--invalid')
137
    public get invalidClass(): boolean {
138
        return this.input.valid === IgxInputState.INVALID;
26,604✔
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,674✔
145
    }
146

147
    /** @hidden */
148
    @HostBinding('class.igx-input-group--textarea-group')
149
    public get textAreaClass(): boolean {
150
        return this.input.isTextArea;
26,604✔
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()
161
    public set type(value: IgxInputGroupType) {
162
        this._type = value;
1,671✔
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,590✔
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,604✔
207
    }
208

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

446
    private setComponentTheme() {
447
        if (!this.themeToken.preferToken) {
2,492✔
448
            const theme = getComponentTheme(this.element.nativeElement);
2,492✔
449

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

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