• 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.22
/projects/igniteui-angular/grids/grid/src/groupby-row.component.ts
1
import {
2
    ChangeDetectionStrategy,
3
    ChangeDetectorRef,
4
    Component,
5
    ElementRef,
6
    HostBinding,
7
    HostListener,
8
    Input,
9
    ViewChild,
10
    TemplateRef,
11
    OnDestroy,
12
    inject
13
} from '@angular/core';
14
import { NgTemplateOutlet } from '@angular/common';
15
import { takeUntil } from 'rxjs/operators';
16
import { Subject } from 'rxjs';
17
import {
18
    GridSelectionMode,
19
    GridType,
20
    IGX_GRID_BASE,
21
    IgxColumnFormatterPipe,
22
    IgxFilteringService,
23
    IgxGridSelectionService,
24
    ISelectionNode
25
} from 'igniteui-angular/grids/core';
26
import { IgxGridRowComponent } from './grid-row.component';
27
import { IgxIconComponent } from 'igniteui-angular/icon';
28
import { IgxBadgeComponent } from 'igniteui-angular/badge';
29
import { IgxCheckboxComponent } from 'igniteui-angular/checkbox';
30
import { GridColumnDataType, IGroupByRecord, IgxNumberFormatterPipe, IgxDateFormatterPipe, IgxCurrencyFormatterPipe, IgxPercentFormatterPipe } from 'igniteui-angular/core';
31

32
@Component({
33
    changeDetection: ChangeDetectionStrategy.OnPush,
34
    selector: 'igx-grid-groupby-row',
35
    templateUrl: './groupby-row.component.html',
36
    imports: [
37
        NgTemplateOutlet,
38
        IgxNumberFormatterPipe,
39
        IgxDateFormatterPipe,
40
        IgxPercentFormatterPipe,
41
        IgxCurrencyFormatterPipe,
42
        IgxIconComponent,
43
        IgxBadgeComponent,
44
        IgxCheckboxComponent,
45
        IgxColumnFormatterPipe
46
    ]
47
})
48
export class IgxGridGroupByRowComponent implements OnDestroy {
3✔
UNCOV
49
    public grid = inject<GridType>(IGX_GRID_BASE);
×
UNCOV
50
    public gridSelection = inject(IgxGridSelectionService);
×
UNCOV
51
    public element = inject(ElementRef);
×
UNCOV
52
    public cdr = inject(ChangeDetectorRef);
×
UNCOV
53
    public filteringService = inject(IgxFilteringService);
×
54

55
    /**
56
     * @hidden
57
     */
58
    @Input()
59
    public hideGroupRowSelectors: boolean;
60

61
    /**
62
     * @hidden
63
     */
64
    @Input()
65
    public rowDraggable: boolean;
66

67
    /**
68
     * Sets the index of the row.
69
     * ```html
70
     * <igx-grid-groupby-row [gridID]="id" [index]="rowIndex" [groupRow]="rowData" #row></igx-grid-groupby-row>
71
     * ```
72
     */
73
    @Input()
74
    public index: number;
75

76
    /**
77
     * Sets the id of the grid the row belongs to.
78
     * ```html
79
     * <igx-grid-groupby-row [gridID]="id" [index]="rowIndex" [groupRow]="rowData" #row></igx-grid-groupby-row>
80
     * ```
81
     */
82
    @Input()
83
    public gridID: string;
84

85
    /**
86
     * The group record the component renders for.
87
     * ```typescript
88
     * <igx-grid-groupby-row [gridID]="id" [index]="rowIndex" [groupRow]="rowData" #row></igx-grid-groupby-row>
89
     * ```
90
     */
91
    @Input()
92
    public groupRow: IGroupByRecord;
93

94
    /**
95
     * Returns a reference of the content of the group.
96
     * ```typescript
97
     * const groupRowContent = this.grid1.rowList.first.groupContent;
98
     * ```
99
     */
100
    @ViewChild('groupContent', { static: true })
101
    public groupContent: ElementRef;
102

103
    /**
104
     * @hidden
105
     */
106
    @Input()
UNCOV
107
    protected isFocused = false;
×
108

109
    /**
110
     * @hidden
111
     */
112
    @ViewChild('defaultGroupByExpandedTemplate', { read: TemplateRef, static: true })
113
    protected defaultGroupByExpandedTemplate: TemplateRef<any>;
114

115
    /**
116
     * @hidden
117
     */
118
    @ViewChild('defaultGroupByCollapsedTemplate', { read: TemplateRef, static: true })
119
    protected defaultGroupByCollapsedTemplate: TemplateRef<any>;
120

121
    /**
122
     * @hidden
123
     */
UNCOV
124
    protected destroy$ = new Subject<void>();
×
125

126
    /**
127
     * @hidden
128
     */
UNCOV
129
    protected defaultCssClass = 'igx-grid__group-row';
×
130

131
    /**
132
     * @hidden
133
     */
UNCOV
134
    protected paddingIndentationCssClass = 'igx-grid__group-row--padding-level';
×
135

136
    /**
137
     * Returns whether the row is focused.
138
     * ```
139
     * let gridRowFocused = this.grid1.rowList.first.focused;
140
     * ```
141
     */
142
    public get focused(): boolean {
UNCOV
143
        return this.isActive();
×
144
    }
145

146
    /** @hidden @internal */
147
    public get currencyCode(): string {
148
        return this.grid.i18nFormatter.getCurrencyCode(this.grid.locale, this.groupRow.column.pipeArgs.currencyCode);
×
149
    }
150

151
    constructor() {
UNCOV
152
        this.gridSelection.selectedRowsChange.pipe(takeUntil(this.destroy$)).subscribe(() => {
×
UNCOV
153
            this.cdr.markForCheck();
×
154
        });
155
    }
156

157

158
    @HostListener('pointerdown')
159
    public activate() {
UNCOV
160
        this.grid.navigation.setActiveNode({ row: this.index });
×
161
    }
162

163
    @HostListener('click', ['$event'])
164
    public onClick(event: MouseEvent) {
UNCOV
165
        this.grid.rowClick.emit({
×
166
            row: this.grid.createRow(this.index),
167
            event
168
        });
169
    }
170

171
    /**
172
     * @hidden
173
     * @internal
174
     */
175
    public ngOnDestroy(): void {
UNCOV
176
        this.destroy$.next();
×
UNCOV
177
        this.destroy$.complete();
×
178
    }
179

180
    /**
181
     * Returns whether the group row is expanded.
182
     * ```typescript
183
     * const groupRowExpanded = this.grid1.rowList.first.expanded;
184
     * ```
185
     */
186
    public get expanded(): boolean {
UNCOV
187
        return this.grid.isExpandedGroup(this.groupRow);
×
188
    }
189

190
    /**
191
     * @hidden
192
     */
193
    @HostBinding('attr.aria-describedby')
194
    public get describedBy(): string {
UNCOV
195
        const grRowExpr = this.groupRow.expression !== undefined ? this.groupRow.expression.fieldName : '';
×
UNCOV
196
        return this.gridID + '_' + grRowExpr;
×
197
    }
198

199
    @HostBinding('attr.data-rowIndex')
200
    public get dataRowIndex() {
UNCOV
201
        return this.index;
×
202
    }
203

204
    /**
205
     * Returns a reference to the underlying HTML element.
206
     * ```typescript
207
     * const groupRowElement = this.nativeElement;
208
     * ```
209
     */
210
    public get nativeElement(): any {
UNCOV
211
        return this.element.nativeElement;
×
212
    }
213

214
    @HostBinding('attr.id')
215
    public get attrCellID() {
UNCOV
216
        return `${this.gridID}_${this.index}`;
×
217
    }
218

219
    /**
220
     * Returns the style classes applied to the group rows.
221
     * ```typescript
222
     * const groupCssStyles = this.grid1.rowList.first.styleClasses;
223
     * ```
224
     */
225
    @HostBinding('class')
226
    public get styleClasses(): string {
UNCOV
227
        return `${this.defaultCssClass} ` + `${this.paddingIndentationCssClass}-` + this.groupRow.level +
×
228
            (this.isActive() ? ` ${this.defaultCssClass}--active` : '');
×
229
    }
230

231
    /**
232
     * @hidden @internal
233
     */
234
    @HostBinding('attr.role')
UNCOV
235
    public role = 'row';
×
236

237
    public isActive() {
UNCOV
238
        return this.grid.navigation.activeNode ? this.grid.navigation.activeNode.row === this.index : false;
×
239
    }
240

241
    /**
242
     * @hidden @internal
243
     */
244
    public getRowID(rowData): IgxGridRowComponent {
UNCOV
245
        return this.grid.primaryKey ? rowData[this.grid.primaryKey] : rowData;
×
246
    }
247

248
    /**
249
     * @hidden @internal
250
     */
251
    public onGroupSelectorClick(event) {
UNCOV
252
        if (!this.grid.isMultiRowSelectionEnabled) {
×
UNCOV
253
            return;
×
254
        }
UNCOV
255
        event.stopPropagation();
×
UNCOV
256
        if (this.areAllRowsInTheGroupSelected) {
×
UNCOV
257
            this.gridSelection.deselectRows(this.groupRow.records.map(x => this.getRowID(x)));
×
258
        } else {
UNCOV
259
            this.gridSelection.selectRows(this.groupRow.records.map(x => this.getRowID(x)));
×
260
        }
261
    }
262

263
    /**
264
     * Toggles the group row.
265
     * ```typescript
266
     * this.grid1.rowList.first.toggle()
267
     * ```
268
     */
269
    public toggle() {
UNCOV
270
        this.grid.toggleGroup(this.groupRow);
×
271
    }
272

273
    public get iconTemplate() {
UNCOV
274
        if (this.expanded) {
×
UNCOV
275
            return this.grid.rowExpandedIndicatorTemplate || this.defaultGroupByExpandedTemplate;
×
276
        } else {
UNCOV
277
            return this.grid.rowCollapsedIndicatorTemplate || this.defaultGroupByCollapsedTemplate;
×
278
        }
279
    }
280

281
    protected get selectionNode(): ISelectionNode {
282
        return {
×
283
            row: this.index,
284
            column: this.gridSelection.activeElement ? this.gridSelection.activeElement.column : 0
×
285
        };
286
    }
287

288
    /**
289
     * @hidden @internal
290
    */
291
    public get dataType(): any {
UNCOV
292
        const column = this.groupRow.column;
×
UNCOV
293
        return (column && column.dataType) || GridColumnDataType.String;
×
294
    }
295

296
    /**
297
     * @hidden @internal
298
     */
299
    public get formatter(): any {
UNCOV
300
        const column = this.groupRow.column;
×
UNCOV
301
        return (column && column.formatter) || null;
×
302
    }
303

304
    /**
305
     * @hidden @internal
306
     */
307
    public get areAllRowsInTheGroupSelected(): boolean {
UNCOV
308
        return this.groupRow.records.every(x => this.gridSelection.isRowSelected(this.getRowID(x)));
×
309
    }
310

311
    /**
312
     * @hidden @internal
313
     */
314
    public get selectedRowsInTheGroup(): any[] {
UNCOV
315
        const selectedIds = new Set(this.gridSelection.filteredSelectedRowIds);
×
UNCOV
316
        return this.groupRow.records.filter(rowID => selectedIds.has(this.getRowID(rowID)));
×
317
    }
318

319
    /**
320
     * @hidden @internal
321
     */
322
    public get groupByRowCheckboxIndeterminateState(): boolean {
UNCOV
323
        if (this.selectedRowsInTheGroup.length > 0) {
×
UNCOV
324
            return !this.areAllRowsInTheGroupSelected;
×
325
        }
UNCOV
326
        return false;
×
327
    }
328

329
    /**
330
     * @hidden @internal
331
     */
332
    public get groupByRowSelectorBaseAriaLabel(): string {
UNCOV
333
        const ariaLabel: string = this.areAllRowsInTheGroupSelected ?
×
334
            this.grid.resourceStrings.igx_grid_groupByArea_deselect_message : this.grid.resourceStrings.igx_grid_groupByArea_select_message;
UNCOV
335
        return ariaLabel.replace('{0}', this.groupRow.expression.fieldName).replace('{1}', this.groupRow.value);
×
336
    }
337

338
    /**
339
     * @hidden @internal
340
     */
341
    public get showRowSelectors(): boolean {
UNCOV
342
        return this.grid.rowSelection !== GridSelectionMode.none && !this.hideGroupRowSelectors;
×
343
    }
344

345
}
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