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

IgniteUI / igniteui-angular / 16193550997

10 Jul 2025 11:12AM UTC coverage: 4.657% (-87.0%) from 91.64%
16193550997

Pull #16028

github

web-flow
Merge f7a9963b8 into 87246e3ce
Pull Request #16028: fix(radio-group): dynamically added radio buttons do not initialize

178 of 15764 branches covered (1.13%)

18 of 19 new or added lines in 2 files covered. (94.74%)

25721 existing lines in 324 files now uncovered.

1377 of 29570 relevant lines covered (4.66%)

0.53 hits per line

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

1.0
/projects/igniteui-angular/src/lib/list/list-item.component.ts
1
import {
2
    ChangeDetectionStrategy,
3
    Component,
4
    ElementRef,
5
    HostBinding,
6
    HostListener,
7
    Input,
8
    Renderer2,
9
    ViewChild,
10
    booleanAttribute
11
} from '@angular/core';
12

13
import {
14
    IgxListPanState,
15
    IListChild,
16
    IgxListBaseDirective
17
} from './list.common';
18

19
import { HammerGesturesManager } from '../core/touch';
20
import { rem } from '../core/utils';
21
import { NgTemplateOutlet } from '@angular/common';
22

23
/**
24
 * The Ignite UI List Item component is a container intended for row items in the Ignite UI for Angular List component.
25
 *
26
 * Example:
27
 * ```html
28
 * <igx-list>
29
 *   <igx-list-item isHeader="true">Contacts</igx-list-item>
30
 *   <igx-list-item *ngFor="let contact of contacts">
31
 *     <span class="name">{{ contact.name }}</span>
32
 *     <span class="phone">{{ contact.phone }}</span>
33
 *   </igx-list-item>
34
 * </igx-list>
35
 * ```
36
 */
37
@Component({
38
    providers: [HammerGesturesManager],
39
    selector: 'igx-list-item',
40
    templateUrl: 'list-item.component.html',
41
    changeDetection: ChangeDetectionStrategy.OnPush,
42
    imports: [NgTemplateOutlet]
43
})
44
export class IgxListItemComponent implements IListChild {
3✔
45
    /**
46
     * Provides a reference to the template's base element shown when left panning a list item.
47
     * ```typescript
48
     * const leftPanTmpl = this.listItem.leftPanningTemplateElement;
49
     * ```
50
     */
51
    @ViewChild('leftPanningTmpl')
52
    public leftPanningTemplateElement;
53

54
    /**
55
     * Provides a reference to the template's base element shown when right panning a list item.
56
     * ```typescript
57
     * const rightPanTmpl = this.listItem.rightPanningTemplateElement;
58
     * ```
59
     */
60
    @ViewChild('rightPanningTmpl')
61
    public rightPanningTemplateElement;
62

63
    /**
64
     * Sets/gets whether the `list item` is a header.
65
     * ```html
66
     * <igx-list-item [isHeader] = "true">Header</igx-list-item>
67
     * ```
68
     * ```typescript
69
     * let isHeader =  this.listItem.isHeader;
70
     * ```
71
     *
72
     * @memberof IgxListItemComponent
73
     */
74
    @Input({ transform: booleanAttribute })
75
    public isHeader: boolean;
76

77
    /**
78
     * Sets/gets whether the `list item` is hidden.
79
     * By default the `hidden` value is `false`.
80
     * ```html
81
     * <igx-list-item [hidden] = "true">Hidden Item</igx-list-item>
82
     * ```
83
     * ```typescript
84
     * let isHidden =  this.listItem.hidden;
85
     * ```
86
     *
87
     * @memberof IgxListItemComponent
88
     */
89
    @Input({ transform: booleanAttribute })
UNCOV
90
    public hidden = false;
×
91

92
    /**
93
     * Sets/gets the `aria-label` attribute of the `list item`.
94
     * ```typescript
95
     * this.listItem.ariaLabel = "Item1";
96
     * ```
97
     * ```typescript
98
     * let itemAriaLabel = this.listItem.ariaLabel;
99
     * ```
100
     *
101
     * @memberof IgxListItemComponent
102
     */
103
    @HostBinding('attr.aria-label')
104
    public ariaLabel: string;
105

106
    /**
107
     * Gets the `touch-action` style of the `list item`.
108
     * ```typescript
109
     * let touchAction = this.listItem.touchAction;
110
     * ```
111
     */
112
    @HostBinding('style.touch-action')
UNCOV
113
    public touchAction = 'pan-y';
×
114

115
    /**
116
     * @hidden
117
     */
UNCOV
118
    private _panState: IgxListPanState = IgxListPanState.NONE;
×
119

120
    /**
121
     * @hidden
122
     */
UNCOV
123
    private panOffset = 0;
×
124

125
    /**
126
     * @hidden
127
     */
UNCOV
128
    private _index: number = null;
×
129

130
    /**
131
     * @hidden
132
     */
UNCOV
133
    private lastPanDir = IgxListPanState.NONE;
×
134

UNCOV
135
    private _role: string = '';
×
UNCOV
136
    private _selected = false;;
×
137

138
    /**
139
     * Gets the `panState` of a `list item`.
140
     * ```typescript
141
     * let itemPanState =  this.listItem.panState;
142
     * ```
143
     *
144
     * @memberof IgxListItemComponent
145
     */
146
    public get panState(): IgxListPanState {
UNCOV
147
        return this._panState;
×
148
    }
149

150
    /**
151
     * Gets the `index` of a `list item`.
152
     * ```typescript
153
     * let itemIndex =  this.listItem.index;
154
     * ```
155
     *
156
     * @memberof IgxListItemComponent
157
     */
158
    @Input()
159
    public get index(): number {
UNCOV
160
        return this._index !== null ? this._index : this.list.children.toArray().indexOf(this);
×
161
    }
162

163
    /**
164
     * Sets the `index` of the `list item`.
165
     * ```typescript
166
     * this.listItem.index = index;
167
     * ```
168
     *
169
     * @memberof IgxListItemComponent
170
     */
171
    public set index(value: number) {
UNCOV
172
        this._index = value;
×
173
    }
174

175
    /**
176
     * Returns an element reference to the list item.
177
     * ```typescript
178
     * let listItemElement =  this.listItem.element.
179
     * ```
180
     *
181
     * @memberof IgxListItemComponent
182
     */
183
    public get element() {
UNCOV
184
        return this.elementRef.nativeElement;
×
185
    }
186

187
    /**
188
     * Returns a reference container which contains the list item's content.
189
     * ```typescript
190
     * let listItemContainer =  this.listItem.contentElement.
191
     * ```
192
     *
193
     * @memberof IgxListItemComponent
194
     */
195
    public get contentElement() {
UNCOV
196
        const candidates = this.element.getElementsByClassName('igx-list__item-content');
×
UNCOV
197
        return (candidates && candidates.length > 0) ? candidates[0] : null;
×
198
    }
199

200
    /**
201
     * Returns the `context` object which represents the `template context` binding into the `list item container`
202
     * by providing the `$implicit` declaration which is the `IgxListItemComponent` itself.
203
     * ```typescript
204
     * let listItemComponent = this.listItem.context;
205
     * ```
206
     */
207
    public get context(): any {
UNCOV
208
        return {
×
209
            $implicit: this
210
        };
211
    }
212

213
    /**
214
     * Gets the width of a `list item`.
215
     * ```typescript
216
     * let itemWidth = this.listItem.width;
217
     * ```
218
     *
219
     * @memberof IgxListItemComponent
220
     */
221
    public get width() {
UNCOV
222
        if (this.element) {
×
UNCOV
223
            return this.element.offsetWidth;
×
224
        }
225
    }
226

227
    /**
228
     * Gets the maximum left position of the `list item`.
229
     * ```typescript
230
     * let maxLeft = this.listItem.maxLeft;
231
     * ```
232
     *
233
     * @memberof IgxListItemComponent
234
     */
235
    public get maxLeft() {
UNCOV
236
        return -this.width;
×
237
    }
238

239
    /**
240
     * Gets the maximum right position of the `list item`.
241
     * ```typescript
242
     * let maxRight = this.listItem.maxRight;
243
     * ```
244
     *
245
     * @memberof IgxListItemComponent
246
     */
247
    public get maxRight() {
UNCOV
248
        return this.width;
×
249
    }
250

251
    /** @hidden @internal */
252
    public get offsetWidthInRem() {
UNCOV
253
        return rem(this.element.offsetWidth);
×
254
    }
255

256
    /** @hidden @internal */
257
    public get offsetHeightInRem() {
UNCOV
258
        return rem(this.element.offsetHeight);
×
259
    }
260

261
    constructor(
UNCOV
262
        public list: IgxListBaseDirective,
×
UNCOV
263
        private elementRef: ElementRef,
×
UNCOV
264
        private _renderer: Renderer2) {
×
265
    }
266

267
    /**
268
     * Gets/Sets the `role` attribute of the `list item`.
269
     * ```typescript
270
     * let itemRole =  this.listItem.role;
271
     * ```
272
     *
273
     * @memberof IgxListItemComponent
274
     */
275
    @HostBinding('attr.role')
276
    @Input()
277
    public get role() {
UNCOV
278
        return this._role ? this._role : this.isHeader ? 'separator' : 'listitem';
×
279
    }
280

281
    public set role(val: string) {
UNCOV
282
        this._role = val;
×
283
    }
284

285
    /**
286
     * Sets/gets whether the `list item` is selected.
287
     * Selection is only applied to non-header items.
288
     * When selected, the CSS class 'igx-list__item-base--selected' is added to the item.
289
     * ```html
290
     * <igx-list-item [selected]="true">Selected Item</igx-list-item>
291
     * ```
292
     * ```typescript
293
     * let isSelected = this.listItem.selected;
294
     * this.listItem.selected = true;
295
     * ```
296
     *
297
     * @memberof IgxListItemComponent
298
     */
299
    @HostBinding('class.igx-list__item-base--selected')
300
    @Input({ transform: booleanAttribute })
301
    public get selected() {
UNCOV
302
        return this._selected && !this.isHeader;
×
303
    }
304

305
    public set selected(value: boolean) {
UNCOV
306
        this._selected = value;
×
307
    }
308

309
    /**
310
     * Indicates whether `list item` should have header style.
311
     * ```typescript
312
     * let headerStyle =  this.listItem.headerStyle;
313
     * ```
314
     *
315
     * @memberof IgxListItemComponent
316
     */
317
    @HostBinding('class.igx-list__header')
318
    public get headerStyle(): boolean {
UNCOV
319
        return this.isHeader;
×
320
    }
321

322
    /**
323
     * Applies the inner style of the `list item` if the item is not counted as header.
324
     * ```typescript
325
     * let innerStyle =  this.listItem.innerStyle;
326
     * ```
327
     *
328
     * @memberof IgxListItemComponent
329
     */
330
    @HostBinding('class.igx-list__item-base')
331
    public get innerStyle(): boolean {
UNCOV
332
        return !this.isHeader;
×
333
    }
334

335
    /**
336
     * Returns string value which describes the display mode of the `list item`.
337
     * ```typescript
338
     * let isHidden = this.listItem.display;
339
     * ```
340
     *
341
     * @memberof IgxListItemComponent
342
     */
343
    @HostBinding('style.display')
344
    public get display(): string {
UNCOV
345
        return this.hidden ? 'none' : '';
×
346
    }
347

348
    /**
349
     * @hidden
350
     */
351
    @HostListener('click', ['$event'])
352
    public clicked(evt) {
UNCOV
353
        this.list.itemClicked.emit({ item: this, event: evt, direction: this.lastPanDir });
×
UNCOV
354
        this.lastPanDir = IgxListPanState.NONE;
×
355
    }
356

357
    /**
358
     * @hidden
359
     */
360
    @HostListener('panstart')
361
    public panStart() {
UNCOV
362
        if (this.isTrue(this.isHeader)) {
×
363
            return;
×
364
        }
UNCOV
365
        if (!this.isTrue(this.list.allowLeftPanning) && !this.isTrue(this.list.allowRightPanning)) {
×
UNCOV
366
            return;
×
367
        }
368

UNCOV
369
        this.list.startPan.emit({ item: this, direction: this.lastPanDir, keepitem: false });
×
370
    }
371

372
    /**
373
     * @hidden
374
     */
375
    @HostListener('pancancel')
376
    public panCancel() {
UNCOV
377
        this.resetPanPosition();
×
UNCOV
378
        this.list.endPan.emit({ item: this, direction: this.lastPanDir, keepItem: false });
×
379
    }
380

381
    /**
382
     * @hidden
383
     */
384
    @HostListener('panmove', ['$event'])
385
    public panMove(ev) {
UNCOV
386
        if (this.isTrue(this.isHeader)) {
×
387
            return;
×
388
        }
UNCOV
389
        if (!this.isTrue(this.list.allowLeftPanning) && !this.isTrue(this.list.allowRightPanning)) {
×
UNCOV
390
            return;
×
391
        }
UNCOV
392
        const isPanningToLeft = ev.deltaX < 0;
×
UNCOV
393
        if (isPanningToLeft && this.isTrue(this.list.allowLeftPanning)) {
×
UNCOV
394
            this.showLeftPanTemplate();
×
UNCOV
395
            this.setContentElementLeft(Math.max(this.maxLeft, ev.deltaX));
×
UNCOV
396
        } else if (!isPanningToLeft && this.isTrue(this.list.allowRightPanning)) {
×
UNCOV
397
            this.showRightPanTemplate();
×
UNCOV
398
            this.setContentElementLeft(Math.min(this.maxRight, ev.deltaX));
×
399
        }
400
    }
401

402
    /**
403
     * @hidden
404
     */
405
    @HostListener('panend')
406
    public panEnd() {
UNCOV
407
        if (this.isTrue(this.isHeader)) {
×
408
            return;
×
409
        }
UNCOV
410
        if (!this.isTrue(this.list.allowLeftPanning) && !this.isTrue(this.list.allowRightPanning)) {
×
UNCOV
411
            return;
×
412
        }
413

414
        // the translation offset of the current list item content
UNCOV
415
        const relativeOffset = this.panOffset;
×
UNCOV
416
        const widthTriggeringGrip = this.width * this.list.panEndTriggeringThreshold;
×
417

UNCOV
418
        if (relativeOffset === 0) {
×
UNCOV
419
            return; // no panning has occured
×
420
        }
421

UNCOV
422
        const dir = relativeOffset > 0 ? IgxListPanState.RIGHT : IgxListPanState.LEFT;
×
UNCOV
423
        this.lastPanDir = dir;
×
424

UNCOV
425
        const args = { item: this, direction: dir, keepItem: false };
×
UNCOV
426
        this.list.endPan.emit(args);
×
427

UNCOV
428
        const oldPanState = this._panState;
×
UNCOV
429
        if (Math.abs(relativeOffset) < widthTriggeringGrip) {
×
UNCOV
430
            this.resetPanPosition();
×
UNCOV
431
            this.list.resetPan.emit(this);
×
UNCOV
432
            return;
×
433
        }
434

UNCOV
435
        if (dir === IgxListPanState.LEFT) {
×
UNCOV
436
            this.list.leftPan.emit(args);
×
437
        } else {
UNCOV
438
            this.list.rightPan.emit(args);
×
439
        }
440

UNCOV
441
        if (args.keepItem === true) {
×
UNCOV
442
            this.setContentElementLeft(0);
×
UNCOV
443
            this._panState = IgxListPanState.NONE;
×
444
        } else {
UNCOV
445
            if (dir === IgxListPanState.LEFT) {
×
UNCOV
446
                this.setContentElementLeft(this.maxLeft);
×
UNCOV
447
                this._panState = IgxListPanState.LEFT;
×
448
            } else {
UNCOV
449
                this.setContentElementLeft(this.maxRight);
×
UNCOV
450
                this._panState = IgxListPanState.RIGHT;
×
451
            }
452
        }
453

UNCOV
454
        if (oldPanState !== this._panState) {
×
UNCOV
455
            const args2 = { oldState: oldPanState, newState: this._panState, item: this };
×
UNCOV
456
            this.list.panStateChange.emit(args2);
×
457
        }
UNCOV
458
        this.hideLeftAndRightPanTemplates();
×
459
    }
460

461
    /**
462
     * @hidden
463
     */
464
    private showLeftPanTemplate() {
UNCOV
465
        this.setLeftAndRightTemplatesVisibility('visible', 'hidden');
×
466
    }
467

468
    /**
469
     * @hidden
470
     */
471
    private showRightPanTemplate() {
UNCOV
472
        this.setLeftAndRightTemplatesVisibility('hidden', 'visible');
×
473
    }
474

475
    /**
476
     * @hidden
477
     */
478
    private hideLeftAndRightPanTemplates() {
UNCOV
479
        setTimeout(() => {
×
UNCOV
480
            this.setLeftAndRightTemplatesVisibility('hidden', 'hidden');
×
481
        }, 500);
482
    }
483

484
    /**
485
     * @hidden
486
     */
487
    private setLeftAndRightTemplatesVisibility(leftVisibility, rightVisibility) {
UNCOV
488
        if (this.leftPanningTemplateElement && this.leftPanningTemplateElement.nativeElement) {
×
UNCOV
489
            this.leftPanningTemplateElement.nativeElement.style.visibility = leftVisibility;
×
490
        }
UNCOV
491
        if (this.rightPanningTemplateElement && this.rightPanningTemplateElement.nativeElement) {
×
UNCOV
492
            this.rightPanningTemplateElement.nativeElement.style.visibility = rightVisibility;
×
493
        }
494
    }
495

496
    /**
497
     * @hidden
498
     */
499
    private setContentElementLeft(value: number) {
UNCOV
500
        this.panOffset = value;
×
UNCOV
501
        this.contentElement.style.transform = 'translateX(' + value + 'px)';
×
502
    }
503

504
    /**
505
     * @hidden
506
     */
507
    private isTrue(value: boolean): boolean {
UNCOV
508
        if (typeof (value) === 'boolean') {
×
UNCOV
509
            return value;
×
510
        } else {
UNCOV
511
            return value === 'true';
×
512
        }
513
    }
514

515
    /**
516
     * @hidden
517
     */
518
    private resetPanPosition() {
UNCOV
519
        this.setContentElementLeft(0);
×
UNCOV
520
        this._panState = IgxListPanState.NONE;
×
UNCOV
521
        this.hideLeftAndRightPanTemplates();
×
522
    }
523
}
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