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

IgniteUI / igniteui-angular / 26023601418

18 May 2026 08:57AM UTC coverage: 4.854% (-85.3%) from 90.174%
26023601418

Pull #17281

github

web-flow
Merge e7ce7a18e into 5a85df190
Pull Request #17281: feat: Added virtual scroll component and sample implementation

400 of 17347 branches covered (2.31%)

Branch coverage included in aggregate %.

63 of 222 new or added lines in 4 files covered. (28.38%)

27932 existing lines in 341 files now uncovered.

2022 of 32547 relevant lines covered (6.21%)

0.72 hits per line

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

0.99
/projects/igniteui-angular/select/src/select/select-navigation.directive.ts
1
import { Directive, Input, OnDestroy } from '@angular/core';
2
import { Subscription, timer } from 'rxjs';
3
import { IgxSelectItemComponent } from './select-item.component';
4
import { IgxSelectBase } from './select.common';
5
import { IgxDropDownItemNavigationDirective } from 'igniteui-angular/drop-down';
6

7
/** @hidden @internal */
8
@Directive({
9
    selector: '[igxSelectItemNavigation]',
10
    standalone: true
11
})
12
export class IgxSelectItemNavigationDirective extends IgxDropDownItemNavigationDirective implements OnDestroy {
3✔
UNCOV
13
    protected override _target: IgxSelectBase = null;
×
14

15
    @Input('igxSelectItemNavigation')
16
    public override get target(): IgxSelectBase {
UNCOV
17
        return this._target;
×
18
    }
19
    public override set target(target: IgxSelectBase) {
UNCOV
20
        this._target = target ? target : this.dropdown as IgxSelectBase;
×
21
    }
22

23
    /** Captures keydown events and calls the appropriate handlers on the target component */
24
    public override handleKeyDown(event: KeyboardEvent) {
UNCOV
25
        if (!event) {
×
26
            return;
×
27
        }
28

UNCOV
29
        const key = event.key.toLowerCase();
×
UNCOV
30
        if (event.altKey && (key === 'arrowdown' || key === 'arrowup' || key === 'down' || key === 'up')) {
×
UNCOV
31
            this.target.toggle();
×
UNCOV
32
            return;
×
33
        }
34

UNCOV
35
        if (this.target.collapsed) {
×
UNCOV
36
            switch (key) {
×
37
                case 'space':
38
                case 'spacebar':
39
                case ' ':
40
                case 'enter':
UNCOV
41
                    event.preventDefault();
×
UNCOV
42
                    this.target.open();
×
UNCOV
43
                    return;
×
44
                case 'arrowdown':
45
                case 'down':
UNCOV
46
                    this.target.navigateNext();
×
UNCOV
47
                    this.target.selectItem(this.target.focusedItem);
×
UNCOV
48
                    event.preventDefault();
×
UNCOV
49
                    return;
×
50
                case 'arrowup':
51
                case 'up':
UNCOV
52
                    this.target.navigatePrev();
×
UNCOV
53
                    this.target.selectItem(this.target.focusedItem);
×
UNCOV
54
                    event.preventDefault();
×
UNCOV
55
                    return;
×
56
                default:
UNCOV
57
                    break;
×
58
            }
UNCOV
59
        } else if (key === 'tab' || event.shiftKey && key === 'tab') {
×
UNCOV
60
            this.target.close();
×
61
        }
62

UNCOV
63
        super.handleKeyDown(event);
×
UNCOV
64
        this.captureKey(event);
×
65
    }
66

UNCOV
67
    private inputStream = '';
×
UNCOV
68
    private clearStream$ = Subscription.EMPTY;
×
69

70
    public captureKey(event: KeyboardEvent) {
71
        // relying only on key, available on all major browsers:
72
        // https://caniuse.com/#feat=keyboardevent-key (IE/Edge quirk doesn't affect letter typing)
UNCOV
73
        if (!event || !event.key || event.key.length > 1 || event.key === ' ' || event.key === 'spacebar') {
×
74
            // ignore longer keys ('Alt', 'ArrowDown', etc) AND spacebar (used of open/close)
UNCOV
75
            return;
×
76
        }
77

UNCOV
78
        this.clearStream$.unsubscribe();
×
UNCOV
79
        this.clearStream$ = timer(500).subscribe(() => {
×
UNCOV
80
            this.inputStream = '';
×
81
        });
82

UNCOV
83
        this.inputStream += event.key;
×
UNCOV
84
        const focusedItem = this.target.focusedItem as IgxSelectItemComponent;
×
85

86
        // select the item
UNCOV
87
        if (focusedItem && this.inputStream.length > 1 && focusedItem.itemText.toLowerCase().startsWith(this.inputStream.toLowerCase())) {
×
UNCOV
88
            return;
×
89
        }
UNCOV
90
        this.activateItemByText(this.inputStream);
×
91
    }
92

93
    public activateItemByText(text: string) {
UNCOV
94
        const items = this.target.items as IgxSelectItemComponent[];
×
95

96
        // ^ this is focused OR selected if the dd is closed
97

UNCOV
98
        let nextItem = this.findNextItem(items, text);
×
99

100
        // If there is no such an item starting with the current text input stream AND the last Char in the input stream
101
        // is the same as the first one, find next item starting with the same first Char.
102
        // Covers cases of holding down the same key Ex: "pppppp" that iterates trough list items starting with "p".
UNCOV
103
        if (!nextItem && text.charAt(0) === text.charAt(text.length - 1)) {
×
UNCOV
104
            text = text.slice(0, 1);
×
UNCOV
105
            nextItem = this.findNextItem(items, text);
×
106
        }
107

108
        // If there is no other item to be found, do not change the active item.
UNCOV
109
        if (!nextItem) {
×
UNCOV
110
            return;
×
111
        }
112

UNCOV
113
        if (this.target.collapsed) {
×
UNCOV
114
            this.target.selectItem(nextItem);
×
115
        }
UNCOV
116
        this.target.navigateItem(items.indexOf(nextItem));
×
117
    }
118

119
    public ngOnDestroy(): void {
UNCOV
120
        this.clearStream$.unsubscribe();
×
121
    }
122

123
    private findNextItem(items: IgxSelectItemComponent[],  text: string) {
UNCOV
124
        const activeItemIndex = items.indexOf(this.target.focusedItem as IgxSelectItemComponent) || 0;
×
125

126
        // Match next item in ddl items and wrap around if needed
UNCOV
127
        return items.slice(activeItemIndex + 1).find(x => !x.disabled && (x.itemText.toLowerCase().startsWith(text.toLowerCase()))) ||
×
UNCOV
128
            items.slice(0, activeItemIndex).find(x => !x.disabled && (x.itemText.toLowerCase().startsWith(text.toLowerCase())));
×
129
    }
130
}
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