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

IgniteUI / igniteui-angular / 13548857950

26 Feb 2025 04:38PM CUT coverage: 91.546%. First build
13548857950

Pull #15224

github

web-flow
Merge 175e9d0f8 into 4866dfb75
Pull Request #15224: fix(pivot-grid): added createRow method for grid based events - 18.2

12992 of 15242 branches covered (85.24%)

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

26325 of 28756 relevant lines covered (91.55%)

34002.18 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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

772
        return this.index + this.grid.page * this.grid.perPage;
4✔
773
    }
774

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

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

795
export class IgxPivotGridRow implements RowType {
796

797
    /** The index of the row within the grid */
798
    public index: number;
799

800
    /**
801
     * The grid that contains the row.
802
     */
803
    public grid: GridType;
804
    private _data?: any;
805

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

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

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

826
    /**
827
     * Gets the row key.
828
     * A row in the grid is identified either by:
829
     * - primaryKey data value,
830
     * - the whole rowData, if the primaryKey is omitted.
831
     *
832
     * ```typescript
833
     * let rowKey = row.key;
834
     * ```
835
     */
836
    public get key(): any {
NEW
837
        const data = this._data ?? this.grid.dataView[this.index];
×
NEW
838
        const primaryKey = this.grid.primaryKey;
×
NEW
839
        return primaryKey ? data[primaryKey] : data;
×
840
    }
841

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

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