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

IgniteUI / igniteui-angular / 28358286454

29 Jun 2026 08:17AM UTC coverage: 90.127% (-0.05%) from 90.174%
28358286454

Pull #17246

github

web-flow
Merge 21687d939 into 07bdcd752
Pull Request #17246: fix(pivot-grid): fix date format based on the localization

14921 of 17392 branches covered (85.79%)

Branch coverage included in aggregate %.

29 of 32 new or added lines in 4 files covered. (90.63%)

735 existing lines in 76 files now uncovered.

29992 of 32441 relevant lines covered (92.45%)

34632.46 hits per line

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

84.17
/projects/igniteui-angular/combo/src/combo/combo-dropdown.component.ts
1
import { Component, QueryList, OnDestroy, AfterViewInit, ContentChildren, Input, booleanAttribute, inject, ChangeDetectionStrategy } from '@angular/core';
2
import { IgxComboBase, IGX_COMBO_COMPONENT } from './combo.common';
3
import { IgxComboAddItemComponent } from './combo-add-item.component';
4
import { IgxComboAPIService } from './combo.api';
5
import { IgxComboItemComponent } from './combo-item.component';
6
import { IgxToggleDirective } from 'igniteui-angular/directives';
7
import { DropDownActionKey, IDropDownBase, IGX_DROPDOWN_BASE, IgxDropDownComponent, IgxDropDownItemBaseDirective } from 'igniteui-angular/drop-down';
8

9
/** @hidden */
10
@Component({
11
    selector: 'igx-combo-drop-down',
12
    templateUrl: '../../../drop-down/src/drop-down/drop-down.component.html',
13
    providers: [{ provide: IGX_DROPDOWN_BASE, useExisting: IgxComboDropDownComponent }],
14
    changeDetection: ChangeDetectionStrategy.Eager,
15
    imports: [IgxToggleDirective]
16
})
17
export class IgxComboDropDownComponent extends IgxDropDownComponent implements IDropDownBase, OnDestroy, AfterViewInit {
3✔
18
    public combo = inject<IgxComboBase>(IGX_COMBO_COMPONENT);
448✔
19
    protected comboAPI = inject(IgxComboAPIService);
448✔
20

21
    private _activeDescendantId: string | null = null;
448✔
22

23
    /** @hidden @internal */
24
    @Input({ transform: booleanAttribute })
25
    public singleMode = false;
448✔
26

27
    /**
28
     * @hidden
29
     * @internal
30
     */
31
    @ContentChildren(IgxComboItemComponent, { descendants: true })
32
    public override children: QueryList<IgxDropDownItemBaseDirective> = null;
448✔
33

34
    /** @hidden @internal */
35
    public override get scrollContainer(): HTMLElement {
36
        // TODO: Update, use public API if possible:
37
        return this.virtDir.dc.location.nativeElement;
1✔
38
    }
39

40
    protected get isScrolledToLast(): boolean {
UNCOV
41
        const scrollTop = this.virtDir.scrollPosition;
×
UNCOV
42
        const scrollHeight = this.virtDir.getScroll().scrollHeight;
×
UNCOV
43
        return Math.floor(scrollTop + this.virtDir.igxForContainerSize) === scrollHeight;
×
44
    }
45

46
    protected get lastVisibleIndex(): number {
UNCOV
47
        return this.combo.totalItemCount ?
×
48
            Math.floor(this.combo.itemsMaxHeight / this.combo.itemHeight) :
49
            this.items.length - 1;
50
    }
51

52
    protected get sortedChildren(): IgxDropDownItemBaseDirective[] {
53
        if (this.children !== undefined) {
127✔
54
            return this.children.toArray()
127✔
55
                .sort((a: IgxDropDownItemBaseDirective, b: IgxDropDownItemBaseDirective) => a.index - b.index);
1,293✔
56
        }
UNCOV
57
        return null;
×
58
    }
59

60
    /**
61
     * @hidden @internal
62
     */
63
    public override get focusedItem(): IgxDropDownItemBaseDirective | null {
64
        return super.focusedItem;
1,034✔
65
    }
66

67
    /**
68
     * @hidden @internal
69
     * Returns a stable aria-activedescendant id, unaffected by virtual scroll position.
70
     * The base class computes this from the live focusedItem getter, which reads from the
71
     * children QueryList. During virtual scroll the QueryList is recycled, so the getter
72
     * can return null mid-CD-cycle causing NG0100 in zoneless apps. The id is cached instead.
73
     */
74
    public override get activeDescendant(): string | null {
75
        return this._activeDescendantId;
8,898✔
76
    }
77

78
    /** @hidden @internal */
79
    public override set focusedItem(item: IgxDropDownItemBaseDirective | null) {
80
        if (!item) {
244✔
81
            this._activeDescendantId = null;
88✔
82
        } else if (item.id !== undefined) {
156✔
83
            this._activeDescendantId = item.id;
29✔
84
        } else {
85
            // Virtual { value, index } object passed by navigateItem() under virtual scrolling.
86
            const resolved = this.children?.find(e => e.index === item.index);
382✔
87
            this._activeDescendantId = resolved?.id ?? null;
127✔
88
        }
89
        super.focusedItem = item;
244✔
90
    }
91

92
    /**
93
     * Get all non-header items
94
     *
95
     * ```typescript
96
     * let myDropDownItems = this.dropdown.items;
97
     * ```
98
     */
99
    public override get items(): IgxComboItemComponent[] {
100
        const items: IgxComboItemComponent[] = [];
127✔
101
        if (this.children !== undefined) {
127✔
102
            const sortedChildren = this.sortedChildren as IgxComboItemComponent[];
127✔
103
            for (const child of sortedChildren) {
127✔
104
                if (!child.isHeader) {
849✔
105
                    items.push(child);
640✔
106
                }
107
            }
108
        }
109

110
        return items;
127✔
111
    }
112

113
    /**
114
     * @hidden @internal
115
     */
116
    public onFocus() {
117
        this.focusedItem = this._focusedItem || this.items[0];
33✔
118
        this.combo.setActiveDescendant();
33✔
119
    }
120

121
    /**
122
     * @hidden @internal
123
     */
124
    public onBlur(_evt?) {
125
        this.focusedItem = null;
65✔
126
        this.combo.setActiveDescendant();
65✔
127
    }
128

129
    /**
130
     * @hidden @internal
131
     */
132
    public override onToggleOpened() {
133
        this.opened.emit();
86✔
134
    }
135

136
    /**
137
     * @hidden
138
     */
139
    public override navigateFirst() {
140
        this.navigateItem(this.virtDir.igxForOf.findIndex(e => !e?.isHeader));
54✔
141
        this.combo.setActiveDescendant();
29✔
142
    }
143

144
    /**
145
     * @hidden
146
     */
147
    public override navigatePrev() {
148
        if (this._focusedItem && this._focusedItem.index === 0 && this.virtDir.state.startIndex === 0) {
8✔
149
            this.combo.focusSearchInput(false);
2✔
150
            this.focusedItem = null;
2✔
151
        } else {
152
            super.navigatePrev();
6✔
153
        }
154
        this.combo.setActiveDescendant();
8✔
155
    }
156

157

158
    /**
159
     * @hidden
160
     */
161
    public override navigateNext() {
162
        const lastIndex = this.combo.totalItemCount ? this.combo.totalItemCount - 1 : this.virtDir.igxForOf.length - 1;
24!
163
        if (this._focusedItem && this._focusedItem.index === lastIndex) {
24✔
164
            this.focusAddItemButton();
1✔
165
        } else {
166
            super.navigateNext();
23✔
167
        }
168
        this.combo.setActiveDescendant();
24✔
169
    }
170

171
    /**
172
     * @hidden @internal
173
     */
174
    public override selectItem(item: IgxDropDownItemBaseDirective) {
175
        if (item === null || item === undefined) {
7!
UNCOV
176
            return;
×
177
        }
178
        this.comboAPI.set_selected_item(item.itemID);
7✔
179
        this._activeDescendantId = item.id ?? null;
7!
180
        this._focusedItem = item;
7✔
181
        this.combo.setActiveDescendant();
7✔
182
    }
183

184
    /**
185
     * @hidden @internal
186
     */
187
    public override updateScrollPosition() {
188
        this.virtDir.getScroll().scrollTop = this._scrollPosition;
178✔
189
    }
190

191
    /**
192
     * @hidden @internal
193
     */
194
    public override onItemActionKey(key: DropDownActionKey, event?: KeyboardEvent) {
195
        switch (key) {
17✔
196
            case DropDownActionKey.ENTER:
197
                this.handleEnter();
1✔
198
                break;
1✔
199
            case DropDownActionKey.SPACE:
200
                this.handleSpace();
9✔
201
                break;
9✔
202
            case DropDownActionKey.ESCAPE:
203
                this.close();
2✔
204
                break;
2✔
205
            case DropDownActionKey.TAB:
206
                this.close(event);
5✔
207
        }
208
    }
209

210
    public override ngAfterViewInit() {
211
        this.virtDir.getScroll().addEventListener('scroll', this.scrollHandler);
410✔
212
    }
213

214
    /**
215
     * @hidden @internal
216
     */
217
    public override ngOnDestroy(): void {
218
        this.virtDir.getScroll().removeEventListener('scroll', this.scrollHandler);
448✔
219
        super.ngOnDestroy();
448✔
220
    }
221

222
    protected override scrollToHiddenItem(_newItem: any): void { }
223

224
    protected scrollHandler = () => {
448✔
225
        this.comboAPI.disableTransitions = true;
22✔
226
    };
227

228
    private handleEnter() {
229
        if (this.isAddItemFocused()) {
1✔
230
            this.combo.addItemToCollection();
1✔
231
            return;
1✔
232
        }
UNCOV
233
        if (this.singleMode && this.focusedItem) {
×
UNCOV
234
            this.combo.select(this.focusedItem.itemID);
×
235
        }
236

UNCOV
237
        this.close();
×
238
    }
239

240
    private handleSpace() {
241
        if (this.isAddItemFocused()) {
9✔
242
            return;
2✔
243
        } else {
244
            this.selectItem(this.focusedItem);
7✔
245
        }
246
    }
247

248
    private isAddItemFocused(): boolean {
249
        return this.focusedItem instanceof IgxComboAddItemComponent;
10✔
250
    }
251

252
    private focusAddItemButton() {
253
        if (this.combo.isAddButtonVisible()) {
1!
UNCOV
254
            this.focusedItem = this.items[this.items.length - 1];
×
255
        }
256
    }
257
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc