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

IgniteUI / igniteui-angular / 6850015339

13 Nov 2023 12:33PM UTC coverage: 92.266% (-0.02%) from 92.282%
6850015339

push

github

web-flow
Merge pull request #13669 from IgniteUI/mdragnev/esf-15.1.x

Add support for navigation in the ESF search list [15.1.x]

15350 of 18038 branches covered (0.0%)

46 of 54 new or added lines in 3 files covered. (85.19%)

24 existing lines in 4 files now uncovered.

26925 of 29182 relevant lines covered (92.27%)

29682.16 hits per line

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

97.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
} from '@angular/core';
11

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

18
import { HammerGesturesManager } from '../core/touch';
19
import { rem } from '../core/utils';
20

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

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

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

74
    /**
75
     * Sets/gets whether the `list item` is hidden.
76
     * By default the `hidden` value is `false`.
77
     * ```html
78
     * <igx-list-item [hidden] = "true">Hidden Item</igx-list-item>
72✔
79
     * ```
80
     * ```typescript
81
     * let isHidden =  this.listItem.hidden;
82
     * ```
83
     *
84
     * @memberof IgxListItemComponent
85
     */
86
    @Input()
87
    public hidden = false;
88

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

103
    /**
104
     * Gets the `touch-action` style of the `list item`.
13✔
105
     * ```typescript
106
     * let touchAction = this.listItem.touchAction;
107
     * ```
108
     */
109
    @HostBinding('style.touch-action')
110
    public touchAction = 'pan-y';
111

112
    /**
113
     * @hidden
114
     */
115
    private _panState: IgxListPanState = IgxListPanState.NONE;
12✔
116

117
    /**
118
     * @hidden
119
     */
72✔
120
    private panOffset = 0;
121

122
    /**
123
     * @hidden
72✔
124
     */
125
    private _index: number = null;
126

1,867✔
127
    /**
1,867✔
128
     * @hidden
1,867✔
129
     */
1,867✔
130
    private lastPanDir = IgxListPanState.NONE;
1,867✔
131

132
    private _role: string = '';
133

134
    /**
1,867✔
135
     * Gets the `panState` of a `list item`.
136
     * ```typescript
137
     * let itemPanState =  this.listItem.panState;
138
     * ```
1,867✔
139
     *
140
     * @memberof IgxListItemComponent
141
     */
142
    public get panState(): IgxListPanState {
1,867✔
143
        return this._panState;
144
    }
145

146
    /**
1,867✔
147
     * Gets the `index` of a `list item`.
1,867✔
148
     * ```typescript
149
     * let itemIndex =  this.listItem.index;
150
     * ```
16,937✔
151
     *
152
     * @memberof IgxListItemComponent
153
     */
1,049✔
154
    @Input()
155
    public get index(): number {
156
        return this._index !== null ? this._index : this.list.children.toArray().indexOf(this);
16,932✔
157
    }
158

159
    /**
16,932✔
160
     * Sets the `index` of the `list item`.
161
     * ```typescript
162
     * this.listItem.index = index;
16,932✔
163
     * ```
164
     *
165
     * @memberof IgxListItemComponent
58✔
166
     */
58✔
167
    public set index(value: number) {
168
        this._index = value;
169
    }
21!
UNCOV
170

×
171
    /**
172
     * Returns an element reference to the list item.
21✔
173
     * ```typescript
2✔
174
     * let listItemElement =  this.listItem.element.
175
     * ```
19✔
176
     *
177
     * @memberof IgxListItemComponent
178
     */
2✔
179
    public get element() {
2✔
180
        return this.elementRef.nativeElement;
181
    }
182

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

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

15✔
209
    /**
2✔
210
     * Gets the width of a `list item`.
211
     * ```typescript
13✔
212
     * let itemWidth = this.listItem.width;
13✔
213
     * ```
13✔
214
     *
13✔
215
     * @memberof IgxListItemComponent
13✔
216
     */
13✔
217
    public get width() {
5✔
218
        if (this.element) {
5✔
219
            return this.element.offsetWidth;
5✔
220
        }
221
    }
8✔
222

4✔
223
    /**
224
     * Gets the maximum left position of the `list item`.
225
     * ```typescript
4✔
226
     * let maxLeft = this.listItem.maxLeft;
227
     * ```
8✔
228
     *
2✔
229
     * @memberof IgxListItemComponent
2✔
230
     */
231
    public get maxLeft() {
232
        return -this.width;
6✔
233
    }
3✔
234

3✔
235
    /**
236
     * Gets the maximum right position of the `list item`.
237
     * ```typescript
3✔
238
     * let maxRight = this.listItem.maxRight;
3✔
239
     * ```
240
     *
241
     * @memberof IgxListItemComponent
8✔
242
     */
6✔
243
    public get maxRight() {
6✔
244
        return this.width;
245
    }
8✔
246

247
    /** @hidden @internal */
248
    public get offsetWidthInRem() {
249
        return rem(this.element.offsetWidth);
250
    }
251

9✔
252
    /** @hidden @internal */
253
    public get offsetHeightInRem() {
254
        return rem(this.element.offsetHeight);
255
    }
256

257
    constructor(
8✔
258
        public list: IgxListBaseDirective,
259
        private elementRef: ElementRef,
260
        private _renderer: Renderer2) {
261
    }
262

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

277
    public set role(val: string) {
278
        this._role = val;
279
    }
280

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

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

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

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

2✔
329
    /**
330
     * @hidden
331
     */
332
    @HostListener('panstart')
333
    public panStart() {
334
        if (this.isTrue(this.isHeader)) {
335
            return;
336
        }
337
        if (!this.isTrue(this.list.allowLeftPanning) && !this.isTrue(this.list.allowRightPanning)) {
338
            return;
339
        }
340

341
        this.list.startPan.emit({ item: this, direction: this.lastPanDir, keepitem: false });
342
    }
343

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

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

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

386
        // the translation offset of the current list item content
387
        const relativeOffset = this.panOffset;
388
        const widthTriggeringGrip = this.width * this.list.panEndTriggeringThreshold;
389

390
        if (relativeOffset === 0) {
391
            return; // no panning has occured
392
        }
393

394
        const dir = relativeOffset > 0 ? IgxListPanState.RIGHT : IgxListPanState.LEFT;
395
        this.lastPanDir = dir;
396

397
        const args = { item: this, direction: dir, keepItem: false};
398
        this.list.endPan.emit(args);
399

400
        const oldPanState = this._panState;
401
        if (Math.abs(relativeOffset) < widthTriggeringGrip) {
402
            this.resetPanPosition();
403
            this.list.resetPan.emit(this);
404
            return;
405
        }
406

407
        if (dir === IgxListPanState.LEFT) {
408
            this.list.leftPan.emit(args);
409
        } else {
410
            this.list.rightPan.emit(args);
411
        }
412

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

426
        if (oldPanState !== this._panState) {
427
            const args2 = { oldState: oldPanState, newState: this._panState, item: this };
428
            this.list.panStateChange.emit(args2);
429
        }
430
        this.hideLeftAndRightPanTemplates();
431
    }
432

433
    /**
434
     * @hidden
435
     */
436
    private showLeftPanTemplate() {
437
        this.setLeftAndRightTemplatesVisibility('visible', 'hidden');
438
    }
439

440
    /**
441
     * @hidden
442
     */
443
    private showRightPanTemplate() {
444
        this.setLeftAndRightTemplatesVisibility('hidden', 'visible');
445
    }
446

447
    /**
448
     * @hidden
449
     */
450
    private hideLeftAndRightPanTemplates() {
451
        setTimeout(() => {
452
            this.setLeftAndRightTemplatesVisibility('hidden', 'hidden');
453
        }, 500);
454
    }
455

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

468
    /**
469
     * @hidden
470
     */
471
    private setContentElementLeft(value: number) {
472
        this.panOffset = value;
473
        this.contentElement.style.transform = 'translateX(' + value + 'px)';
474
    }
475

476
    /**
477
     * @hidden
478
     */
479
    private isTrue(value: boolean): boolean {
480
        if (typeof (value) === 'boolean') {
481
            return value;
482
        } else {
483
            return value === 'true';
484
        }
485
    }
486

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