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

IgniteUI / igniteui-angular / 13964021430

20 Mar 2025 07:24AM CUT coverage: 91.532%. First build
13964021430

Pull #15224

github

web-flow
Merge 4346704fb into e9e83f6b5
Pull Request #15224: fix(pivot-grid): added createRow method for grid based events - 18.2

12992 of 15243 branches covered (85.23%)

0 of 18 new or added lines in 2 files covered. (0.0%)

26321 of 28756 relevant lines covered (91.53%)

34010.81 hits per line

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

88.84
/projects/igniteui-angular/src/lib/grids/grid-public-row.ts
1
import { IGroupByRecord } from '../data-operations/groupby-record.interface';
2
import { IgxAddRow, IgxEditRow } from './common/crud.service';
3
import { GridSummaryCalculationMode, GridSummaryPosition } from './common/enums';
4
import { IgxGridCell } from './grid-public-cell';
5
import { IgxSummaryResult } from './summaries/grid-summary';
6
import { ITreeGridRecord } from './tree-grid/tree-grid.interfaces';
7
import { mergeWith } from 'lodash-es';
8
import { CellType, GridServiceType, GridType, IGridValidationState, RowType, ValidationStatus } from './common/grid.interface';
9
import { IgxPivotGridComponent } from './pivot-grid/public_api';
10
import { PivotUtil } from './pivot-grid/pivot-util';
11

12
abstract class BaseRow implements RowType {
13
    public index: number;
14
    /**
15
     * The grid that contains the row.
16
     */
17
    public grid: GridType;
18
    protected _data?: any;
19

20
    /**
21
     * Returns the view index calculated per the grid page.
22
     */
23
    public get viewIndex(): number {
24
        return this.index + this.grid.page * this.grid.perPage;
×
25
    }
26

27
    /**
28
     * Gets the row key.
29
     * A row in the grid is identified either by:
30
     * - primaryKey data value,
31
     * - the whole rowData, if the primaryKey is omitted.
32
     *
33
     * ```typescript
34
     * let rowKey = row.key;
35
     * ```
36
     */
37
    public get key(): any {
38
        const data = this._data ?? this.grid.dataView[this.index];
2,659!
39
        const primaryKey = this.grid.primaryKey;
2,659✔
40
        return primaryKey ? data[primaryKey] : data;
2,659✔
41
    }
42

43
    /**
44
     * Gets if this represents add row UI
45
     *
46
     * ```typescript
47
     * let isAddRow = row.addRowUI;
48
     * ```
49
     */
50
    public get addRowUI(): boolean {
51
        return !!this.grid.crudService.row &&
×
52
            this.grid.crudService.row.getClassName() === IgxAddRow.name &&
53
            this.grid.crudService.row.id === this.key;
54
    }
55

56
    /** Gets the validation status and errors, if any.
57
    * ```typescript
58
    * let validation = row.validation;
59
    * let errors = validation.errors;
60
    * ```
61
    */
62
    public get validation(): IGridValidationState {
63
        const formGroup = this.grid.validation.getFormGroup(this.key);
×
64
        return { status: formGroup?.status as ValidationStatus || 'VALID', errors: formGroup?.errors } as const;
×
65
    }
66

67
    /**
68
     * The data record that populates the row.
69
     *
70
     * ```typescript
71
     * let rowData = row.data;
72
     * ```
73
     */
74
    public get data(): any {
75
        if (this.inEditMode) {
2,710✔
76
            return mergeWith(this.grid.dataCloneStrategy.clone(this._data ?? this.grid.dataView[this.index]),
520!
77
                this.grid.transactions.getAggregatedValue(this.key, false),
78
                (objValue, srcValue) => {
79
                    if (Array.isArray(srcValue)) {
226!
80
                        return objValue = srcValue;
×
81
                    }
82
                });
83
        }
84
        return this._data ?? this.grid.dataView[this.index];
2,190!
85
    }
86

87
    /**
88
     * Returns if the row is currently in edit mode.
89
     */
90
    public get inEditMode(): boolean {
91
        if (this.grid.rowEditable) {
3,528✔
92
            const editRowState = this.grid.crudService.row;
1,425✔
93
            return (editRowState && editRowState.id === this.key) || false;
1,425✔
94
        } else {
95
            return false;
2,103✔
96
        }
97
    }
98

99
    /**
100
     * Gets whether the row is pinned.
101
     * Default value is `false`.
102
     * ```typescript
103
     * const isPinned = row.pinned;
104
     * ```
105
     */
106
    public get pinned(): boolean {
107
        return this.grid.isRecordPinned(this.data);
19✔
108
    }
109

110
    /**
111
     * Sets whether the row is pinned.
112
     * Default value is `false`.
113
     * ```typescript
114
     * row.pinned = !row.pinned;
115
     * ```
116
     */
117
    public set pinned(val: boolean) {
118
        if (val) {
2✔
119
            this.pin();
1✔
120
        } else {
121
            this.unpin();
1✔
122
        }
123
    }
124

125
    /**
126
     * Gets the row expanded/collapsed state.
127
     *
128
     * ```typescript
129
     * const isExpanded = row.expanded;
130
     * ```
131
     */
132
    public get expanded(): boolean {
133
        return this.grid.gridAPI.get_row_expansion_state(this.data);
5✔
134
    }
135

136
    /**
137
     * Expands/collapses the row.
138
     *
139
     * ```typescript
140
     * row.expanded = true;
141
     * ```
142
     */
143
    public set expanded(val: boolean) {
144
        this.grid.gridAPI.set_row_expansion_state(this.key, val);
5✔
145
    }
146

147
    /**
148
     * Gets whether the row is selected.
149
     * Default value is `false`.
150
     * ```typescript
151
     * row.selected = true;
152
     * ```
153
     */
154
    public get selected(): boolean {
155
        return this.grid.selectionService.isRowSelected(this.key);
442✔
156
    }
157

158
    /**
159
     * Sets whether the row is selected.
160
     * Default value is `false`.
161
     * ```typescript
162
     * row.selected = !row.selected;
163
     * ```
164
     */
165
    public set selected(val: boolean) {
166
        if (val) {
3✔
167
            this.grid.selectionService.selectRowsWithNoEvent([this.key]);
2✔
168
        } else {
169
            this.grid.selectionService.deselectRowsWithNoEvent([this.key]);
1✔
170
        }
171
        this.grid.cdr.markForCheck();
3✔
172
    }
173

174
    /**
175
     * Returns if the row is in delete state.
176
     */
177
    public get deleted(): boolean {
178
        return this.grid.gridAPI.row_deleted_transaction(this.key);
148✔
179
    }
180

181
    /**
182
     * Returns if the row has child rows. Always return false for IgxGridRow.
183
     */
184
    public get hasChildren(): boolean {
185
        return false;
1✔
186
    }
187

188
    public get disabled(): boolean {
189
        return this.grid.isGhostRecord(this.data);
62✔
190
    }
191

192
    /**
193
     * Gets the rendered cells in the row component.
194
     */
195
    public get cells(): CellType[] {
196
        const res: CellType[] = [];
3,803✔
197
        this.grid.columns.forEach(col => {
3,803✔
198
            const cell: CellType = new IgxGridCell(this.grid, this.index, col);
42,039✔
199
            res.push(cell);
42,039✔
200
        });
201
        return res;
3,803✔
202
    }
203

204
    /**
205
     * Pins the specified row.
206
     * This method emits `onRowPinning` event.
207
     *
208
     * ```typescript
209
     * // pin the selected row from the grid
210
     * this.grid.selectedRows[0].pin();
211
     * ```
212
     */
213
    public pin(): boolean {
214
        return this.grid.pinRow(this.key, this.index);
28✔
215
    }
216

217
    /**
218
     * Unpins the specified row.
219
     * This method emits `onRowPinning` event.
220
     *
221
     * ```typescript
222
     * // unpin the selected row from the grid
223
     * this.grid.selectedRows[0].unpin();
224
     * ```
225
     */
226
    public unpin(): boolean {
227
        return this.grid.unpinRow(this.key);
9✔
228
    }
229

230
    /**
231
     * Updates the specified row object and the data source record with the passed value.
232
     *
233
     * ```typescript
234
     * // update the second selected row's value
235
     * let newValue = "Apple";
236
     * this.grid.selectedRows[1].update(newValue);
237
     * ```
238
     */
239
    public update(value: any): void {
240
        const crudService = this.grid.crudService;
17✔
241
        if (crudService.cellInEditMode && crudService.cell.id.rowID === this.key) {
17!
242
            this.grid.transactions.endPending(false);
×
243
        }
244
        const row = new IgxEditRow(this.key, this.index, this.data, this.grid);
17✔
245
        this.grid.gridAPI.update_row(row, value);
17✔
246
        this.grid.notifyChanges();
17✔
247
    }
248

249
    /**
250
     * Removes the specified row from the grid's data source.
251
     * This method emits `onRowDeleted` event.
252
     *
253
     * ```typescript
254
     * // delete the third selected row from the grid
255
     * this.grid.selectedRows[2].delete();
256
     * ```
257
     */
258
    public delete(): void {
259
        this.grid.deleteRowById(this.key);
15✔
260
    }
261
}
262

263
export class IgxGridRow extends BaseRow implements RowType {
264
    /**
265
     * @hidden
266
     */
267
    constructor(
268
        public override grid: GridType,
71,463✔
269
        public override index: number, data?: any
71,463✔
270
    ) {
271
        super();
71,463✔
272
        this._data = data && data.addRow && data.recordRef ? data.recordRef : data;
71,463!
273
    }
274

275
    /**
276
     * Returns the view index calculated per the grid page.
277
     */
278
    public override get viewIndex(): number {
279
        if (this.grid.paginator) {
8✔
280
            const precedingDetailRows = [];
5✔
281
            const precedingGroupRows = [];
5✔
282
            const firstRow = this.grid.dataView[0];
5✔
283
            const hasDetailRows = this.grid.expansionStates.size;
5✔
284
            const hasGroupedRows = this.grid.groupingExpressions.length;
5✔
285
            let precedingSummaryRows = 0;
5✔
286
            const firstRowInd = this.grid.groupingFlatResult.indexOf(firstRow);
5✔
287

288
            // from groupingFlatResult, resolve two other collections:
289
            // precedingGroupedRows -> use it to resolve summaryRow for each group in previous pages
290
            // precedingDetailRows -> ise it to resolve the detail row for each expanded grid row in previous pages
291
            if (hasDetailRows || hasGroupedRows) {
5✔
292
                this.grid.groupingFlatResult.forEach((r, ind) => {
1✔
293
                    const rowID = this.grid.primaryKey ? r[this.grid.primaryKey] : r;
69!
294
                    if (hasGroupedRows && ind < firstRowInd && this.grid.isGroupByRecord(r)) {
69✔
295
                        precedingGroupRows.push(r);
3✔
296
                    }
297
                    if (this.grid.expansionStates.get(rowID) && ind < firstRowInd && !this.grid.isGroupByRecord(r)) {
69!
298
                        precedingDetailRows.push(r);
×
299
                    }
300
                });
301
            }
302

303
            if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) {
5✔
304
                // if firstRow is a child of the last item in precedingGroupRows,
305
                // then summaryRow for this given groupedRecord is rendered after firstRow,
306
                // i.e. need to decrease firstRowInd to account for the above.
307
                precedingSummaryRows = precedingGroupRows.filter(gr => this.grid.isExpandedGroup(gr)).length;
5✔
308
                if (this.grid.summaryPosition === GridSummaryPosition.bottom && precedingGroupRows.length &&
5✔
309
                    precedingGroupRows[precedingGroupRows.length - 1].records.indexOf(firstRow) > -1) {
310
                    precedingSummaryRows += -1;
1✔
311
                }
312
            }
313

314
            return precedingDetailRows.length + precedingSummaryRows + firstRowInd + this.index;
5✔
315
        } else {
316
            return this.index;
3✔
317
        }
318
    }
319

320
    /**
321
     * Returns the parent row, if grid is grouped.
322
     */
323
    public get parent(): RowType {
324
        let parent: IgxGroupByRow;
325
        if (!this.grid.groupingExpressions.length) {
3✔
326
            return undefined;
1✔
327
        }
328

329
        let i = this.index - 1;
2✔
330
        while (i >= 0 && !parent) {
2✔
331
            const rec = this.grid.dataView[i];
2✔
332
            if (this.grid.isGroupByRecord(rec)) {
2✔
333
                parent = new IgxGroupByRow(this.grid, i, rec);
2✔
334
            }
335
            i--;
2✔
336
        }
337
        return parent;
2✔
338
    }
339
}
340

341
export class IgxTreeGridRow extends BaseRow implements RowType {
342
    /**
343
     * @hidden
344
     */
345
    constructor(
346
        public override grid: GridType,
12,943✔
347
        public override index: number, data?: any, private _treeRow?: ITreeGridRecord
12,943✔
348
    ) {
349
        super();
12,943✔
350
        this._data = data && data.addRow && data.recordRef ? data.recordRef : data;
12,943!
351
    }
352

353
    /**
354
     * Returns the view index calculated per the grid page.
355
     */
356
    public override get viewIndex(): number {
357
        if (this.grid.hasSummarizedColumns && this.grid.page > 0) {
6✔
358
            if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) {
2✔
359
                const firstRowIndex = this.grid.processedExpandedFlatData.indexOf(this.grid.dataView[0].data);
2✔
360
                // firstRowIndex is based on data result after all pipes triggered, excluding summary pipe
361
                const precedingSummaryRows = this.grid.summaryPosition === GridSummaryPosition.bottom ?
2✔
362
                    this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) :
363
                    this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) + 1;
364
                // there is a summary row for each root record, so we calculate how many root records are rendered before the current row
365
                return firstRowIndex + precedingSummaryRows + this.index;
2✔
366
            }
367
        }
368
        return this.index + this.grid.page * this.grid.perPage;
4✔
369
    }
370

371
    /**
372
     *  The data passed to the row component.
373
     *
374
     * ```typescript
375
     * let selectedRowData = this.grid.selectedRows[0].data;
376
     * ```
377
     */
378
    public override get data(): any {
379
        if (this.inEditMode) {
810✔
380
            return mergeWith(this.grid.dataCloneStrategy.clone(this._data ?? this.grid.dataView[this.index]),
52!
381
                this.grid.transactions.getAggregatedValue(this.key, false),
382
                (objValue, srcValue) => {
383
                    if (Array.isArray(srcValue)) {
42!
384
                        return objValue = srcValue;
×
385
                    }
386
                });
387
        }
388
        const rec = this.grid.dataView[this.index];
758✔
389
        return this._data ? this._data : this.grid.isTreeRow(rec) ? rec.data : rec;
758!
390
    }
391

392
    /**
393
     * Returns the child rows.
394
     */
395
    public get children(): RowType[] {
396
        const children: IgxTreeGridRow[] = [];
7✔
397
        if (this.treeRow.expanded) {
7✔
398
            this.treeRow.children.forEach((rec, i) => {
7✔
399
                const row = new IgxTreeGridRow(this.grid, this.index + 1 + i, rec.data);
8✔
400
                children.push(row);
8✔
401
            });
402
        }
403
        return children;
7✔
404
    }
405

406
    /**
407
     * Returns the parent row.
408
     */
409
    public get parent(): RowType {
410
        const row = this.grid.getRowByKey(this.treeRow.parent?.key);
15✔
411
        return row;
15✔
412
    }
413

414
    /**
415
     * Returns true if child rows exist. Always return false for IgxGridRow.
416
     */
417
    public override get hasChildren(): boolean {
418
        if (this.treeRow.children) {
2✔
419
            return this.treeRow.children.length > 0;
1✔
420
        } else {
421
            return false;
1✔
422
        }
423
    }
424

425
    /**
426
     * The `ITreeGridRecord` with metadata about the row in the context of the tree grid.
427
     *
428
     * ```typescript
429
     * const rowParent = this.treeGrid.getRowByKey(1).treeRow.parent;
430
     * ```
431
     */
432
    public get treeRow(): ITreeGridRecord {
433
        return this._treeRow ?? this.grid.records.get(this.key);
140✔
434
    }
435

436
    /**
437
     * Gets whether the row is pinned.
438
     *
439
     * ```typescript
440
     * let isPinned = row.pinned;
441
     * ```
442
     */
443
    public override get pinned(): boolean {
444
        return this.grid.isRecordPinned(this);
8✔
445
    }
446

447
    /**
448
     * Sets whether the row is pinned.
449
     * Default value is `false`.
450
     * ```typescript
451
     * row.pinned = !row.pinned;
452
     * ```
453
     */
454
    public override set pinned(val: boolean) {
455
        if (val) {
4✔
456
            this.pin();
2✔
457
        } else {
458
            this.unpin();
2✔
459
        }
460
    }
461

462
    /**
463
     * Gets whether the row is expanded.
464
     *
465
     * ```typescript
466
     * let esExpanded = row.expanded;
467
     * ```
468
     */
469
    public override get expanded(): boolean {
470
        return this.grid.gridAPI.get_row_expansion_state(this.treeRow);
4✔
471
    }
472

473
    /**
474
     * Expands/collapses the row.
475
     *
476
     * ```typescript
477
     * row.expanded = true;
478
     * ```
479
     */
480
    public override set expanded(val: boolean) {
481
        this.grid.gridAPI.set_row_expansion_state(this.key, val);
6✔
482
    }
483

484
    public override get disabled(): boolean {
485
        // TODO cell
486
        return this.grid.isGhostRecord(this.data) ? this.treeRow.isFilteredOutParent === undefined : false;
16!
487
    }
488

489
    private getRootParent(row: ITreeGridRecord): ITreeGridRecord {
490
        while (row.parent) {
2✔
491
            row = row.parent;
4✔
492
        }
493
        return row;
2✔
494
    }
495
}
496

497
export class IgxHierarchicalGridRow extends BaseRow implements RowType {
498
    /**
499
     * @hidden
500
     */
501
    constructor(
502
        public override grid: GridType,
363✔
503
        public override index: number, data?: any
363✔
504
    ) {
505
        super();
363✔
506
        this._data = data && data.addRow && data.recordRef ? data.recordRef : data;
363!
507
    }
508

509
    /**
510
     * Returns true if row islands exist.
511
     */
512
    public override get hasChildren(): boolean {
513
        return !!this.grid.childLayoutKeys.length;
1✔
514
    }
515

516
    /**
517
     * Returns the view index calculated per the grid page.
518
     */
519
    public override get viewIndex() {
520
        const firstRowInd = this.grid.filteredSortedData.indexOf(this.grid.dataView[0]);
1✔
521
        const expandedRows = this.grid.filteredSortedData.filter((rec, ind) => {
1✔
522
            const rowID = this.grid.primaryKey ? rec[this.grid.primaryKey] : rec;
7!
523
            return this.grid.expansionStates.get(rowID) && ind < firstRowInd;
7✔
524
        });
525
        return firstRowInd + expandedRows.length + this.index;
1✔
526
    }
527

528
    /**
529
     * Gets the rendered cells in the row component.
530
     */
531
    public override get cells(): CellType[] {
532
        const res: CellType[] = [];
37✔
533
        this.grid.columns.forEach(col => {
37✔
534
            const cell: CellType = new IgxGridCell(this.grid, this.index, col);
184✔
535
            res.push(cell);
184✔
536
        });
537
        return res;
37✔
538
    }
539
}
540

541
export class IgxGroupByRow implements RowType {
542
    /**
543
     * Returns the row index.
544
     */
545
    public index: number;
546

547
    /**
548
     * The grid that contains the row.
549
     */
550
    public grid: GridType;
551

552
    /**
553
     * Returns always true, because this is in instance of an IgxGroupByRow.
554
     */
555
    public isGroupByRow: boolean;
556

557
    /**
558
     * The IGroupByRecord object, representing the group record, if the row is a GroupByRow.
559
     */
560
    public get groupRow(): IGroupByRecord {
561
        return this._groupRow ? this._groupRow : this.grid.dataView[this.index];
19!
562
    }
563

564
    /**
565
     * Returns the child rows.
566
     */
567
    public get children(): RowType[] {
568
        const children: IgxGridRow[] = [];
11✔
569
        this.groupRow.records.forEach((rec, i) => {
11✔
570
            const row = new IgxGridRow(this.grid, this.index + 1 + i, rec);
11✔
571
            children.push(row);
11✔
572
        });
573
        return children;
11✔
574
    }
575

576
    /**
577
     * Returns the view index calculated per the grid page.
578
     */
579
    public get viewIndex(): number {
580
        if (this.grid.page) {
2✔
581
            const precedingDetailRows = [];
1✔
582
            const precedingGroupRows = [];
1✔
583
            const firstRow = this.grid.dataView[0];
1✔
584
            const hasDetailRows = this.grid.expansionStates.size;
1✔
585
            const hasGroupedRows = this.grid.groupingExpressions.length;
1✔
586
            let precedingSummaryRows = 0;
1✔
587
            const firstRowInd = this.grid.groupingFlatResult.indexOf(firstRow);
1✔
588

589
            // from groupingFlatResult, resolve two other collections:
590
            // precedingGroupedRows -> use it to resolve summaryRow for each group in previous pages
591
            // precedingDetailRows -> ise it to resolve the detail row for each expanded grid row in previous pages
592
            if (hasDetailRows || hasGroupedRows) {
1✔
593
                this.grid.groupingFlatResult.forEach((r, ind) => {
1✔
594
                    const rowID = this.grid.primaryKey ? r[this.grid.primaryKey] : r;
69!
595
                    if (hasGroupedRows && ind < firstRowInd && this.grid.isGroupByRecord(r)) {
69✔
596
                        precedingGroupRows.push(r);
3✔
597
                    }
598
                    if (this.grid.expansionStates.get(rowID) && ind < firstRowInd && !this.grid.isGroupByRecord(r)) {
69!
599
                        precedingDetailRows.push(r);
×
600
                    }
601
                });
602
            }
603

604
            if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) {
1✔
605
                // if firstRow is a child of the last item in precedingGroupRows,
606
                // then summaryRow for this given groupedRecord is rendered after firstRow,
607
                // i.e. need to decrease firstRowInd to account for the above.
608
                precedingSummaryRows = precedingGroupRows.filter(gr => this.grid.isExpandedGroup(gr)).length;
3✔
609
                if (this.grid.summaryPosition === GridSummaryPosition.bottom && precedingGroupRows.length &&
1✔
610
                    precedingGroupRows[precedingGroupRows.length - 1].records.indexOf(firstRow) > -1) {
611
                    precedingSummaryRows += -1;
1✔
612
                }
613
            }
614

615
            return precedingDetailRows.length + precedingSummaryRows + firstRowInd + this.index;
1✔
616
        } else {
617
            return this.index;
1✔
618
        }
619
    }
620

621
    /**
622
     * @hidden
623
     */
624
    constructor(grid: GridType, index: number, private _groupRow?: IGroupByRecord) {
129✔
625
        this.grid = grid;
129✔
626
        this.index = index;
129✔
627
        this.isGroupByRow = true;
129✔
628
    }
629

630
    /**
631
     * Gets whether the row is selected.
632
     * Default value is `false`.
633
     * ```typescript
634
     * row.selected = true;
635
     * ```
636
     */
637
    public get selected(): boolean {
638
        return this.children.every(row => row.selected);
6✔
639
    }
640

641
    /**
642
     * Sets whether the row is selected.
643
     * Default value is `false`.
644
     * ```typescript
645
     * row.selected = !row.selected;
646
     * ```
647
     */
648
    public set selected(val: boolean) {
649
        if (val) {
2✔
650
            this.children.forEach(row => {
1✔
651
                this.grid.selectionService.selectRowsWithNoEvent([row.key]);
1✔
652
            });
653
        } else {
654
            this.children.forEach(row => {
1✔
655
                this.grid.selectionService.deselectRowsWithNoEvent([row.key]);
1✔
656
            });
657
        }
658
        this.grid.cdr.markForCheck();
2✔
659
    }
660

661
    /**
662
     * Gets/sets whether the group row is expanded.
663
     * ```typescript
664
     * const groupRowExpanded = groupRow.expanded;
665
     * ```
666
     */
667
    public get expanded(): boolean {
668
        return this.grid.isExpandedGroup(this.groupRow);
4✔
669
    }
670

671
    public set expanded(value: boolean) {
672
        this.gridAPI.set_grouprow_expansion_state(this.groupRow, value);
2✔
673
    }
674

675
    public isActive(): boolean {
676
        return this.grid.navigation.activeNode ? this.grid.navigation.activeNode.row === this.index : false;
×
677
    }
678

679
    /**
680
     * Toggles the group row expanded/collapsed state.
681
     * ```typescript
682
     * groupRow.toggle()
683
     * ```
684
     */
685
    public toggle(): void {
686
        this.grid.toggleGroup(this.groupRow);
1✔
687
    }
688

689
    private get gridAPI(): GridServiceType {
690
        return this.grid.gridAPI as GridServiceType;
2✔
691
    }
692
}
693

694
export class IgxSummaryRow implements RowType {
695
    /**
696
     * Returns the row index.
697
     */
698
    public index: number;
699

700
    /**
701
     * The grid that contains the row.
702
     */
703
    public grid: GridType;
704

705
    /**
706
     * Returns always true, because this is in instance of an IgxGroupByRow.
707
     */
708
    public isSummaryRow: boolean;
709

710
    /**
711
     * The IGroupByRecord object, representing the group record, if the row is a GroupByRow.
712
     */
713
    public get summaries(): Map<string, IgxSummaryResult[]> {
714
        return this._summaries ? this._summaries : this.grid.dataView[this.index].summaries;
1!
715
    }
716

717
    /**
718
     * Returns the view index calculated per the grid page.
719
     */
720
    public get viewIndex(): number {
721
        if (this.grid.hasSummarizedColumns && this.grid.page > 0) {
7✔
722
            if (this.grid.type === 'flat') {
3✔
723
                if (this.grid.page) {
1!
724
                    const precedingDetailRows = [];
1✔
725
                    const precedingGroupRows = [];
1✔
726
                    const firstRow = this.grid.dataView[0];
1✔
727
                    const hasDetailRows = this.grid.expansionStates.size;
1✔
728
                    const hasGroupedRows = this.grid.groupingExpressions.length;
1✔
729
                    let precedingSummaryRows = 0;
1✔
730
                    const firstRowInd = this.grid.groupingFlatResult.indexOf(firstRow);
1✔
731

732
                    // from groupingFlatResult, resolve two other collections:
733
                    // precedingGroupedRows -> use it to resolve summaryRow for each group in previous pages
734
                    // precedingDetailRows -> ise it to resolve the detail row for each expanded grid row in previous pages
735
                    if (hasDetailRows || hasGroupedRows) {
1✔
736
                        this.grid.groupingFlatResult.forEach((r, ind) => {
1✔
737
                            const rowID = this.grid.primaryKey ? r[this.grid.primaryKey] : r;
69!
738
                            if (hasGroupedRows && ind < firstRowInd && this.grid.isGroupByRecord(r)) {
69✔
739
                                precedingGroupRows.push(r);
3✔
740
                            }
741
                            if (this.grid.expansionStates.get(rowID) && ind < firstRowInd &&
69!
742
                                !this.grid.isGroupByRecord(r)) {
743
                                precedingDetailRows.push(r);
×
744
                            }
745
                        });
746
                    }
747

748
                    if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) {
1✔
749
                        // if firstRow is a child of the last item in precedingGroupRows,
750
                        // then summaryRow for this given groupedRecord is rendered after firstRow,
751
                        // i.e. need to decrease firstRowInd to account for the above.
752
                        precedingSummaryRows = precedingGroupRows.filter(gr => this.grid.isExpandedGroup(gr)).length;
3✔
753
                        if (this.grid.summaryPosition === GridSummaryPosition.bottom && precedingGroupRows.length &&
1✔
754
                            precedingGroupRows[precedingGroupRows.length - 1].records.indexOf(firstRow) > -1) {
755
                            precedingSummaryRows += -1;
1✔
756
                        }
757
                    }
758

759
                    return precedingDetailRows.length + precedingSummaryRows + firstRowInd + this.index;
1✔
760
                } else {
761
                    return this.index;
×
762
                }
763
            } else if (this.grid.type === 'tree') {
2✔
764
                if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) {
2✔
765
                    const firstRowIndex = this.grid.processedExpandedFlatData.indexOf(this.grid.dataView[0].data);
2✔
766
                    const precedingSummaryRows = this.grid.summaryPosition === GridSummaryPosition.bottom ?
2✔
767
                        this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) :
768
                        this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) + 1;
769
                    return firstRowIndex + precedingSummaryRows + this.index;
2✔
770
                }
771
            }
772
        }
773

774
        return this.index + this.grid.page * this.grid.perPage;
4✔
775
    }
776

777
    /**
778
     * @hidden
779
     */
780
    constructor(
781
        grid: GridType,
782
        index: number, private _summaries?: Map<string, IgxSummaryResult[]>,
27✔
783
    ) {
784
        this.grid = grid;
27✔
785
        this.index = index;
27✔
786
        this.isSummaryRow = true;
27✔
787
    }
788

789
    private getRootParent(row: ITreeGridRecord): ITreeGridRecord {
790
        while (row.parent) {
2✔
791
            row = row.parent;
4✔
792
        }
793
        return row;
2✔
794
    }
795
}
796

797
export class IgxPivotGridRow implements RowType {
798

799
    /** The index of the row within the grid */
800
    public index: number;
801

802
    /**
803
     * The grid that contains the row.
804
     */
805
    public grid: IgxPivotGridComponent;
806
    private _data?: any;
807

808
    constructor(grid: IgxPivotGridComponent, index: number, data?: any) {
NEW
809
        this.grid = grid;
×
NEW
810
        this.index = index;
×
NEW
811
        this._data = data && data.addRow && data.recordRef ? data.recordRef : data;
×
812
    }
813

814
    /**
815
     *  The data passed to the row component.
816
     */
817
    public get data(): any {
NEW
818
        return this._data ?? this.grid.dataView[this.index];
×
819
    }
820

821
    /**
822
     * Returns the view index calculated per the grid page.
823
     */
824
    public get viewIndex(): number {
NEW
825
        return this.index + this.grid.page * this.grid.perPage;
×
826
    }
827

828
    /**
829
     * Gets the row key.
830
     * A row in the grid is identified either by:
831
     * - primaryKey data value,
832
     * - the whole rowData, if the primaryKey is omitted.
833
     *
834
     * ```typescript
835
     * let rowKey = row.key;
836
     * ```
837
     */
838
    public get key(): any {
NEW
839
        const dimension = this.grid.visibleRowDimensions[this.grid.visibleRowDimensions.length - 1];
×
NEW
840
        const recordKey =  PivotUtil.getRecordKey(this.data, dimension);
×
NEW
841
        return recordKey ? recordKey : null;
×
842
    }
843

844
    /**
845
     * Gets whether the row is selected.
846
     * Default value is `false`.
847
     * ```typescript
848
     * row.selected = true;
849
     * ```
850
     */
851
    public get selected(): boolean {
NEW
852
        return this.grid.selectionService.isRowSelected(this.key);
×
853
    }
854

855
    public set selected(val: boolean) {
NEW
856
        if (val) {
×
NEW
857
            this.grid.selectionService.selectRowsWithNoEvent([this.key]);
×
858
        } else {
NEW
859
            this.grid.selectionService.deselectRowsWithNoEvent([this.key]);
×
860
        }
NEW
861
        this.grid.cdr.markForCheck();
×
862
    }
863
}
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