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

IgniteUI / igniteui-angular / 13331632524

14 Feb 2025 02:51PM UTC coverage: 22.015% (-69.6%) from 91.622%
13331632524

Pull #15372

github

web-flow
Merge d52d57714 into bcb78ae0a
Pull Request #15372: chore(*): test ci passing

1990 of 15592 branches covered (12.76%)

431 of 964 new or added lines in 18 files covered. (44.71%)

19956 existing lines in 307 files now uncovered.

6452 of 29307 relevant lines covered (22.02%)

249.17 hits per line

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

1.03
/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 { NgIf, 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: [NgIf, NgTemplateOutlet]
43
})
44
export class IgxListItemComponent implements IListChild {
2✔
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 = '';
×
136

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

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

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

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

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

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

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

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

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

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

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

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

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

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

284
    /**
285
     * Indicates whether `list item` should have header style.
286
     * ```typescript
287
     * let headerStyle =  this.listItem.headerStyle;
288
     * ```
289
     *
290
     * @memberof IgxListItemComponent
291
     */
292
    @HostBinding('class.igx-list__header')
293
    public get headerStyle(): boolean {
UNCOV
294
        return this.isHeader;
×
295
    }
296

297
    /**
298
     * Applies the inner style of the `list item` if the item is not counted as header.
299
     * ```typescript
300
     * let innerStyle =  this.listItem.innerStyle;
301
     * ```
302
     *
303
     * @memberof IgxListItemComponent
304
     */
305
    @HostBinding('class.igx-list__item-base')
306
    public get innerStyle(): boolean {
UNCOV
307
        return !this.isHeader;
×
308
    }
309

310
    /**
311
     * Returns string value which describes the display mode of the `list item`.
312
     * ```typescript
313
     * let isHidden = this.listItem.display;
314
     * ```
315
     *
316
     * @memberof IgxListItemComponent
317
     */
318
    @HostBinding('style.display')
319
    public get display(): string {
UNCOV
320
        return this.hidden ? 'none' : '';
×
321
    }
322

323
    /**
324
     * @hidden
325
     */
326
    @HostListener('click', ['$event'])
327
    public clicked(evt) {
UNCOV
328
        this.list.itemClicked.emit({ item: this, event: evt, direction: this.lastPanDir });
×
UNCOV
329
        this.lastPanDir = IgxListPanState.NONE;
×
330
    }
331

332
    /**
333
     * @hidden
334
     */
335
    @HostListener('panstart')
336
    public panStart() {
UNCOV
337
        if (this.isTrue(this.isHeader)) {
×
338
            return;
×
339
        }
UNCOV
340
        if (!this.isTrue(this.list.allowLeftPanning) && !this.isTrue(this.list.allowRightPanning)) {
×
UNCOV
341
            return;
×
342
        }
343

UNCOV
344
        this.list.startPan.emit({ item: this, direction: this.lastPanDir, keepitem: false });
×
345
    }
346

347
    /**
348
     * @hidden
349
     */
350
    @HostListener('pancancel')
351
    public panCancel() {
UNCOV
352
        this.resetPanPosition();
×
UNCOV
353
        this.list.endPan.emit({ item: this, direction: this.lastPanDir, keepItem: false });
×
354
    }
355

356
    /**
357
     * @hidden
358
     */
359
    @HostListener('panmove', ['$event'])
360
    public panMove(ev) {
UNCOV
361
        if (this.isTrue(this.isHeader)) {
×
362
            return;
×
363
        }
UNCOV
364
        if (!this.isTrue(this.list.allowLeftPanning) && !this.isTrue(this.list.allowRightPanning)) {
×
UNCOV
365
            return;
×
366
        }
UNCOV
367
        const isPanningToLeft = ev.deltaX < 0;
×
UNCOV
368
        if (isPanningToLeft && this.isTrue(this.list.allowLeftPanning)) {
×
UNCOV
369
            this.showLeftPanTemplate();
×
UNCOV
370
            this.setContentElementLeft(Math.max(this.maxLeft, ev.deltaX));
×
UNCOV
371
        } else if (!isPanningToLeft && this.isTrue(this.list.allowRightPanning)) {
×
UNCOV
372
            this.showRightPanTemplate();
×
UNCOV
373
            this.setContentElementLeft(Math.min(this.maxRight, ev.deltaX));
×
374
        }
375
    }
376

377
    /**
378
     * @hidden
379
     */
380
    @HostListener('panend')
381
    public panEnd() {
UNCOV
382
        if (this.isTrue(this.isHeader)) {
×
383
            return;
×
384
        }
UNCOV
385
        if (!this.isTrue(this.list.allowLeftPanning) && !this.isTrue(this.list.allowRightPanning)) {
×
UNCOV
386
            return;
×
387
        }
388

389
        // the translation offset of the current list item content
UNCOV
390
        const relativeOffset = this.panOffset;
×
UNCOV
391
        const widthTriggeringGrip = this.width * this.list.panEndTriggeringThreshold;
×
392

UNCOV
393
        if (relativeOffset === 0) {
×
UNCOV
394
            return; // no panning has occured
×
395
        }
396

UNCOV
397
        const dir = relativeOffset > 0 ? IgxListPanState.RIGHT : IgxListPanState.LEFT;
×
UNCOV
398
        this.lastPanDir = dir;
×
399

UNCOV
400
        const args = { item: this, direction: dir, keepItem: false };
×
UNCOV
401
        this.list.endPan.emit(args);
×
402

UNCOV
403
        const oldPanState = this._panState;
×
UNCOV
404
        if (Math.abs(relativeOffset) < widthTriggeringGrip) {
×
UNCOV
405
            this.resetPanPosition();
×
UNCOV
406
            this.list.resetPan.emit(this);
×
UNCOV
407
            return;
×
408
        }
409

UNCOV
410
        if (dir === IgxListPanState.LEFT) {
×
UNCOV
411
            this.list.leftPan.emit(args);
×
412
        } else {
UNCOV
413
            this.list.rightPan.emit(args);
×
414
        }
415

UNCOV
416
        if (args.keepItem === true) {
×
UNCOV
417
            this.setContentElementLeft(0);
×
UNCOV
418
            this._panState = IgxListPanState.NONE;
×
419
        } else {
UNCOV
420
            if (dir === IgxListPanState.LEFT) {
×
UNCOV
421
                this.setContentElementLeft(this.maxLeft);
×
UNCOV
422
                this._panState = IgxListPanState.LEFT;
×
423
            } else {
UNCOV
424
                this.setContentElementLeft(this.maxRight);
×
UNCOV
425
                this._panState = IgxListPanState.RIGHT;
×
426
            }
427
        }
428

UNCOV
429
        if (oldPanState !== this._panState) {
×
UNCOV
430
            const args2 = { oldState: oldPanState, newState: this._panState, item: this };
×
UNCOV
431
            this.list.panStateChange.emit(args2);
×
432
        }
UNCOV
433
        this.hideLeftAndRightPanTemplates();
×
434
    }
435

436
    /**
437
     * @hidden
438
     */
439
    private showLeftPanTemplate() {
UNCOV
440
        this.setLeftAndRightTemplatesVisibility('visible', 'hidden');
×
441
    }
442

443
    /**
444
     * @hidden
445
     */
446
    private showRightPanTemplate() {
UNCOV
447
        this.setLeftAndRightTemplatesVisibility('hidden', 'visible');
×
448
    }
449

450
    /**
451
     * @hidden
452
     */
453
    private hideLeftAndRightPanTemplates() {
UNCOV
454
        setTimeout(() => {
×
UNCOV
455
            this.setLeftAndRightTemplatesVisibility('hidden', 'hidden');
×
456
        }, 500);
457
    }
458

459
    /**
460
     * @hidden
461
     */
462
    private setLeftAndRightTemplatesVisibility(leftVisibility, rightVisibility) {
UNCOV
463
        if (this.leftPanningTemplateElement && this.leftPanningTemplateElement.nativeElement) {
×
UNCOV
464
            this.leftPanningTemplateElement.nativeElement.style.visibility = leftVisibility;
×
465
        }
UNCOV
466
        if (this.rightPanningTemplateElement && this.rightPanningTemplateElement.nativeElement) {
×
UNCOV
467
            this.rightPanningTemplateElement.nativeElement.style.visibility = rightVisibility;
×
468
        }
469
    }
470

471
    /**
472
     * @hidden
473
     */
474
    private setContentElementLeft(value: number) {
UNCOV
475
        this.panOffset = value;
×
UNCOV
476
        this.contentElement.style.transform = 'translateX(' + value + 'px)';
×
477
    }
478

479
    /**
480
     * @hidden
481
     */
482
    private isTrue(value: boolean): boolean {
UNCOV
483
        if (typeof (value) === 'boolean') {
×
UNCOV
484
            return value;
×
485
        } else {
UNCOV
486
            return value === 'true';
×
487
        }
488
    }
489

490
    /**
491
     * @hidden
492
     */
493
    private resetPanPosition() {
UNCOV
494
        this.setContentElementLeft(0);
×
UNCOV
495
        this._panState = IgxListPanState.NONE;
×
UNCOV
496
        this.hideLeftAndRightPanTemplates();
×
497
    }
498
}
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