• 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

1.96
/projects/igniteui-angular/grids/core/src/headers/grid-header-row.component.ts
1
import {
2
    ChangeDetectionStrategy,
3
    ChangeDetectorRef,
4
    Component,
5
    DoCheck,
6
    ElementRef,
7
    HostBinding,
8
    Input,
9
    QueryList,
10
    TemplateRef,
11
    ViewChild,
12
    ViewChildren,
13
    booleanAttribute,
14
    inject
15
} from '@angular/core';
16
import { GridType, IgxHeadSelectorTemplateContext } from '../common/grid.interface';
17
import { IgxGridFilteringCellComponent } from '../filtering/base/grid-filtering-cell.component';
18
import { IgxGridFilteringRowComponent } from '../filtering/base/grid-filtering-row.component';
19
import { IgxGridHeaderGroupComponent } from './grid-header-group.component';
20
import { IgxGridHeaderComponent } from './grid-header.component';
21
import { IgxHeaderGroupStylePipe } from './pipes';
22
import { IgxGridTopLevelColumns } from '../common/pipes';
23
import { IgxColumnMovingDropDirective } from '../moving/moving.drop.directive';
24
import { NgTemplateOutlet, NgClass, NgStyle } from '@angular/common';
25
import { IgxGridForOfDirective } from 'igniteui-angular/directives';
26
import { IgxCheckboxComponent } from 'igniteui-angular/checkbox';
27
import { ColumnType, flatten, trackByIdentity } from 'igniteui-angular/core';
28

29
/**
30
 *
31
 * For all intents & purposes treat this component as what a <thead> usually is in the default <table> element.
32
 *
33
 * This container holds the grid header elements and their behavior/interactions.
34
 *
35
 * @hidden @internal
36
 */
37
@Component({
38
    changeDetection: ChangeDetectionStrategy.OnPush,
39
    selector: 'igx-grid-header-row',
40
    templateUrl: './grid-header-row.component.html',
41
    imports: [IgxColumnMovingDropDirective, NgTemplateOutlet, NgClass, IgxGridHeaderGroupComponent, NgStyle, IgxGridForOfDirective, IgxGridFilteringRowComponent, IgxCheckboxComponent, IgxGridTopLevelColumns, IgxHeaderGroupStylePipe]
42
})
43
export class IgxGridHeaderRowComponent implements DoCheck {
3✔
UNCOV
44
    protected ref = inject<ElementRef<HTMLElement>>(ElementRef);
×
UNCOV
45
    protected cdr = inject(ChangeDetectorRef);
×
46

47

48
    /** The grid component containing this element. */
49
    @Input()
50
    public grid: GridType;
51

52
    /** Pinned columns of the grid at start. */
53
    @Input()
UNCOV
54
    public pinnedStartColumnCollection: ColumnType[] = [];
×
55

56
    /** Pinned columns of the grid at end. */
57
    @Input()
UNCOV
58
    public pinnedEndColumnCollection: ColumnType[] = [];
×
59

60

61
    /** Unpinned columns of the grid. */
62
    @Input()
UNCOV
63
    public unpinnedColumnCollection: ColumnType[] = [];
×
64

65
    /**
66
     * @hidden @internal
67
     */
68
    @HostBinding('attr.role')
UNCOV
69
    public role = 'rowgroup';
×
70

71
    @HostBinding('attr.aria-activedescendant')
72
    public get activeDescendant() {
UNCOV
73
        const activeElem = this.navigation.activeNode;
×
74

UNCOV
75
        if (!activeElem || !Object.keys(activeElem).length || activeElem.row >= 0) {
×
UNCOV
76
            return null;
×
77
        }
UNCOV
78
        return `${this.grid.id}_${activeElem.row}_${activeElem.level}_${activeElem.column}`;
×
79
    }
80

81
    @Input({ transform: booleanAttribute })
82
    public hasMRL: boolean;
83

84
    @Input()
85
    public width: number;
86

87
    /**
88
     * Header groups inside the header row.
89
     *
90
     * @remarks
91
     * Note: These are only the top level header groups in case there are multi-column headers
92
     * or a specific column layout. If you want to get the flattened collection use the `groups`
93
     * property below.
94
     *
95
     * @hidden @internal
96
     * */
97
    @ViewChildren(IgxGridHeaderGroupComponent)
98
    public _groups: QueryList<IgxGridHeaderGroupComponent>;
99

100
    /**
101
     * The flattened header groups collection.
102
     *
103
     * @hidden @internal
104
     */
105
    public get groups(): IgxGridHeaderGroupComponent[] {
UNCOV
106
        return flatten(this._groups?.toArray() ?? []);
×
107
    }
108

109
    /** Header components in the header row. */
110
    public get headers(): IgxGridHeaderComponent[] {
111
        return this.groups.map(group => group.header);
×
112
    }
113

114
    /** Filtering cell components in the header row. */
115
    public get filters(): IgxGridFilteringCellComponent[] {
116
        return this.groups.map(group => group.filter);
×
117
    }
118

119
    /**
120
     * Gets a list of all visible leaf columns in the grid.
121
     *
122
     * @hidden @internal
123
     */
124
    public get visibleLeafColumns(): ColumnType[] {
UNCOV
125
        const row = this.grid.gridAPI.get_row_by_index(this.grid.rowList.first?.index || 0);
×
UNCOV
126
        if (row && row.cells) {
×
UNCOV
127
            return row.cells.map(cell => cell.column);
×
128
        }
129
    }
130

131
    /**
132
    * @hidden
133
    * @internal
134
    */
135
    public get isLeafHeaderAriaHidden(): boolean {
UNCOV
136
        return this.grid.navigation.activeNode?.row === -1;
×
137
    }
138

139
    /** The virtualized part of the header row containing the unpinned header groups. */
140
    @ViewChild('headerVirtualContainer', { read: IgxGridForOfDirective, static: true })
141
    public headerContainer: IgxGridForOfDirective<ColumnType, ColumnType[]>;
142

143
    public get headerForOf() {
UNCOV
144
        return this.headerContainer;
×
145
    }
146

147
    @ViewChild('headerDragContainer')
148
    public headerDragContainer: ElementRef<HTMLElement>;
149

150
    @ViewChild('headerSelectorContainer')
151
    public headerSelectorContainer: ElementRef<HTMLElement>;
152

153
    @ViewChild('headerGroupContainer')
154
    public headerGroupContainer: ElementRef<HTMLElement>;
155

156
    @ViewChild('headSelectorBaseTemplate')
157
    public headSelectorBaseTemplate: TemplateRef<IgxHeadSelectorTemplateContext>;
158

159
    @ViewChild(IgxGridFilteringRowComponent)
160
    public filterRow: IgxGridFilteringRowComponent;
161

162
    /**
163
     * Expand/collapse all child grids area in a hierarchical grid.
164
     * `undefined` in the base and tree grids.
165
     *
166
     * @internal @hidden
167
     */
168
    @ViewChild('headerHierarchyExpander')
169
    public headerHierarchyExpander: ElementRef<HTMLElement>;
170

171
    public get navigation() {
UNCOV
172
        return this.grid.navigation;
×
173
    }
174

175
    public get nativeElement() {
UNCOV
176
        return this.ref.nativeElement;
×
177
    }
178

179
    /**
180
     * Returns whether the current grid instance is a hierarchical grid.
181
     * as only hierarchical grids have the `isHierarchicalRecord` method.
182
     *
183
     * @hidden @internal
184
     */
185
    public get isHierarchicalGrid() {
UNCOV
186
        return !!this.grid.isHierarchicalRecord;
×
187
    }
188

189
    public get indentationCSSClasses() {
UNCOV
190
        return `igx-grid__header-indentation igx-grid__row-indentation--level-${this.grid.groupingExpressions.length}`;
×
191
    }
192

193
    public get rowSelectorsContext(): IgxHeadSelectorTemplateContext {
UNCOV
194
        const ctx = {
×
195
            $implicit: {
196
                selectedCount: this.grid.selectionService.filteredSelectedRowIds.length as number,
197
                totalCount: this.grid.totalRowsCountAfterFilter as number
198
            }
199
        } as IgxHeadSelectorTemplateContext;
200

UNCOV
201
        if (this.isHierarchicalGrid) {
×
UNCOV
202
            ctx.$implicit.selectAll = () => this.grid.selectAllRows();
×
UNCOV
203
            ctx.$implicit.deselectAll = () => this.grid.deselectAllRows();
×
204
        }
205

UNCOV
206
        return ctx;
×
207
    }
208

209
    /**
210
     * This hook exists as a workaround for the unfortunate fact
211
     * that when we have pinned columns in the grid, the unpinned columns headers
212
     * are affected by a delayed change detection cycle after a horizontal scroll :(
213
     * Thus, we tell the parent grid change detector to check us at each cycle.
214
     *
215
     * @hidden @internal
216
     */
217
    public ngDoCheck() {
UNCOV
218
        this.cdr.markForCheck();
×
219
    }
220

221
    /**
222
     * @hidden @internal
223
     */
224
    public scroll(event: Event) {
225
        this.grid.preventHeaderScroll(event);
×
226
    }
227

228
    public headerRowSelection(event: MouseEvent) {
UNCOV
229
        if (!this.grid.isMultiRowSelectionEnabled) {
×
UNCOV
230
            return;
×
231
        }
232

UNCOV
233
        if (this.grid.selectionService.areAllRowSelected()) {
×
UNCOV
234
            this.grid.selectionService.clearRowSelection(event);
×
235
        } else {
UNCOV
236
            this.grid.selectionService.selectAllRows(event);
×
237
        }
238
    }
239

240
    /** state persistence switching all pinned columns resets collection */
UNCOV
241
    protected trackPinnedColumn = trackByIdentity;
×
242
}
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