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

IgniteUI / igniteui-angular / 13287444581

12 Feb 2025 02:18PM UTC coverage: 10.56% (-81.0%) from 91.606%
13287444581

Pull #15359

github

web-flow
Merge a24969adb into 32cfe83f6
Pull Request #15359: fix(time-picker): exclude from SSR toggle events #15135

933 of 15233 branches covered (6.12%)

3037 of 28759 relevant lines covered (10.56%)

352.42 hits per line

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

0.7
/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts
1
import {
2
    Component, ChangeDetectionStrategy, Input, Output, EventEmitter, ContentChild, ViewChildren,
3
    QueryList, ViewChild, TemplateRef, DoCheck, AfterContentInit, HostBinding,
4
    OnInit, AfterViewInit, ContentChildren, CUSTOM_ELEMENTS_SCHEMA, booleanAttribute
5
} from '@angular/core';
6
import { NgIf, NgTemplateOutlet, NgClass, NgFor, NgStyle } from '@angular/common';
7

8
import { IgxGridBaseDirective } from '../grid-base.directive';
9
import { IgxGridNavigationService } from '../grid-navigation.service';
10
import { IgxGridAPIService } from './grid-api.service';
11
import { cloneArray, IBaseEventArgs } from '../../core/utils';
12
import { IGroupByRecord } from '../../data-operations/groupby-record.interface';
13
import { IgxGroupByRowTemplateDirective, IgxGridDetailTemplateDirective } from '../grid.directives';
14
import { IgxGridGroupByRowComponent } from './groupby-row.component';
15
import { IGroupByExpandState } from '../../data-operations/groupby-expand-state.interface';
16
import { IForOfState, IgxGridForOfDirective } from '../../directives/for-of/for_of.directive';
17
import { IgxColumnComponent } from '../columns/column.component';
18
import { take, takeUntil } from 'rxjs/operators';
19
import { IgxFilteringService } from '../filtering/grid-filtering.service';
20
import { IGroupingExpression } from '../../data-operations/grouping-expression.interface';
21
import { IgxColumnResizingService } from '../resizing/resizing.service';
22
import { IgxGridSummaryService } from '../summaries/grid-summary.service';
23
import { IgxGridSelectionService } from '../selection/selection.service';
24
import { IgxForOfSyncService, IgxForOfScrollSyncService } from '../../directives/for-of/for_of.sync.service';
25
import { IgxGridMRLNavigationService } from '../grid-mrl-navigation.service';
26
import { FilterMode } from '../common/enums';
27
import { CellType, GridType, IgxGridMasterDetailContext, IgxGroupByRowSelectorTemplateContext, IgxGroupByRowTemplateContext, IGX_GRID_BASE, IGX_GRID_SERVICE_BASE, RowType } from '../common/grid.interface';
28
import { IgxGroupByRowSelectorDirective } from '../selection/row-selectors';
29
import { IgxGridCRUDService } from '../common/crud.service';
30
import { IgxGridRow, IgxGroupByRow, IgxSummaryRow } from '../grid-public-row';
31
import { IgxGridCell } from '../grid-public-cell';
32
import { ISortingExpression } from '../../data-operations/sorting-strategy';
33
import { IGridGroupingStrategy } from '../common/strategy';
34
import { IgxGridValidationService } from './grid-validation.service';
35
import { IgxGridDetailsPipe } from './grid.details.pipe';
36
import { IgxGridSummaryPipe } from './grid.summary.pipe';
37
import { IgxGridGroupingPipe, IgxGridPagingPipe, IgxGridSortingPipe, IgxGridFilteringPipe } from './grid.pipes';
38
import { IgxSummaryDataPipe } from '../summaries/grid-root-summary.pipe';
39
import { IgxGridTransactionPipe, IgxHasVisibleColumnsPipe, IgxGridRowPinningPipe, IgxGridAddRowPipe, IgxGridRowClassesPipe, IgxGridRowStylesPipe, IgxStringReplacePipe } from '../common/pipes';
40
import { IgxGridColumnResizerComponent } from '../resizing/resizer.component';
41
import { IgxRowEditTabStopDirective } from '../grid.rowEdit.directive';
42
import { IgxIconComponent } from '../../icon/icon.component';
43
import { IgxRippleDirective } from '../../directives/ripple/ripple.directive';
44
import { IgxButtonDirective } from '../../directives/button/button.directive';
45
import { IgxSnackbarComponent } from '../../snackbar/snackbar.component';
46
import { IgxCircularProgressBarComponent } from '../../progressbar/progressbar.component';
47
import { IgxOverlayOutletDirective, IgxToggleDirective } from '../../directives/toggle/toggle.directive';
48
import { IgxSummaryRowComponent } from '../summaries/summary-row.component';
49
import { IgxGridRowComponent } from './grid-row.component';
50
import { IgxTemplateOutletDirective } from '../../directives/template-outlet/template_outlet.directive';
51
import { IgxColumnMovingDropDirective } from '../moving/moving.drop.directive';
52
import { IgxGridDragSelectDirective } from '../selection/drag-select.directive';
53
import { IgxGridBodyDirective } from '../grid.common';
54
import { IgxGridHeaderRowComponent } from '../headers/grid-header-row.component';
55
import { IgxGridGroupByAreaComponent } from '../grouping/grid-group-by-area.component';
56
import { Observable, Subject } from 'rxjs';
57

58
let NEXT_ID = 0;
2✔
59

60
export interface IGroupingDoneEventArgs extends IBaseEventArgs {
61
    expressions: Array<ISortingExpression> | ISortingExpression;
62
    groupedColumns: Array<IgxColumnComponent> | IgxColumnComponent;
63
    ungroupedColumns: Array<IgxColumnComponent> | IgxColumnComponent;
64
}
65

66
/* blazorAdditionalDependency: Column */
67
/* blazorAdditionalDependency: ColumnGroup */
68
/* blazorAdditionalDependency: ColumnLayout */
69
/* blazorAdditionalDependency: GridToolbar */
70
/* blazorAdditionalDependency: GridToolbarActions */
71
/* blazorAdditionalDependency: GridToolbarTitle */
72
/* blazorAdditionalDependency: GridToolbarAdvancedFiltering */
73
/* blazorAdditionalDependency: GridToolbarExporter */
74
/* blazorAdditionalDependency: GridToolbarHiding */
75
/* blazorAdditionalDependency: GridToolbarPinning */
76
/* blazorAdditionalDependency: ActionStrip */
77
/* blazorAdditionalDependency: GridActionsBaseDirective */
78
/* blazorAdditionalDependency: GridEditingActions */
79
/* blazorAdditionalDependency: GridPinningActions */
80
/* blazorIndirectRender */
81
/**
82
 * Grid provides a way to present and manipulate tabular data.
83
 *
84
 * @igxModule IgxGridModule
85
 * @igxGroup Grids & Lists
86
 * @igxKeywords grid, table
87
 * @igxTheme igx-grid-theme
88
 * @remarks
89
 * The Ignite UI Grid is used for presenting and manipulating tabular data in the simplest way possible.  Once data
90
 * has been bound, it can be manipulated through filtering, sorting & editing operations.
91
 * @example
92
 * ```html
93
 * <igx-grid [data]="employeeData" [autoGenerate]="false">
94
 *   <igx-column field="first" header="First Name"></igx-column>
95
 *   <igx-column field="last" header="Last Name"></igx-column>
96
 *   <igx-column field="role" header="Role"></igx-column>
97
 * </igx-grid>
98
 * ```
99
 */
100
@Component({
101
    changeDetection: ChangeDetectionStrategy.OnPush,
102
    preserveWhitespaces: false,
103
    providers: [
104
        IgxGridCRUDService,
105
        IgxGridNavigationService,
106
        IgxGridSummaryService,
107
        IgxGridSelectionService,
108
        IgxGridValidationService,
109
        { provide: IGX_GRID_SERVICE_BASE, useClass: IgxGridAPIService },
110
        { provide: IGX_GRID_BASE, useExisting: IgxGridComponent },
111
        IgxFilteringService,
112
        IgxColumnResizingService,
113
        IgxForOfSyncService,
114
        IgxForOfScrollSyncService,
115
    ],
116
    selector: 'igx-grid',
117
    templateUrl: './grid.component.html',
118
    imports: [
119
        NgIf,
120
        NgClass,
121
        NgFor,
122
        NgStyle,
123
        NgTemplateOutlet,
124
        IgxGridGroupByAreaComponent,
125
        IgxGridHeaderRowComponent,
126
        IgxGridBodyDirective,
127
        IgxGridDragSelectDirective,
128
        IgxColumnMovingDropDirective,
129
        IgxGridForOfDirective,
130
        IgxTemplateOutletDirective,
131
        IgxGridRowComponent,
132
        IgxGridGroupByRowComponent,
133
        IgxSummaryRowComponent,
134
        IgxOverlayOutletDirective,
135
        IgxToggleDirective,
136
        IgxCircularProgressBarComponent,
137
        IgxSnackbarComponent,
138
        IgxButtonDirective,
139
        IgxRippleDirective,
140
        IgxIconComponent,
141
        IgxRowEditTabStopDirective,
142
        IgxGridColumnResizerComponent,
143
        IgxGridTransactionPipe,
144
        IgxHasVisibleColumnsPipe,
145
        IgxGridRowPinningPipe,
146
        IgxGridAddRowPipe,
147
        IgxGridRowClassesPipe,
148
        IgxGridRowStylesPipe,
149
        IgxSummaryDataPipe,
150
        IgxGridGroupingPipe,
151
        IgxGridPagingPipe,
152
        IgxGridSortingPipe,
153
        IgxGridFilteringPipe,
154
        IgxGridSummaryPipe,
155
        IgxGridDetailsPipe,
156
        IgxStringReplacePipe
157
    ],
158
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
159
})
160
export class IgxGridComponent extends IgxGridBaseDirective implements GridType, OnInit, DoCheck, AfterContentInit, AfterViewInit {
2✔
161
    /**
162
     * Emitted when a new chunk of data is loaded from virtualization.
163
     *
164
     * @example
165
     * ```typescript
166
     *  <igx-grid #grid [data]="localData" [autoGenerate]="true" (dataPreLoad)='handleDataPreloadEvent()'></igx-grid>
167
     * ```
168
     */
169
    @Output()
170
    public dataPreLoad = new EventEmitter<IForOfState>();
×
171

172
    /**
173
     * @hidden
174
     */
175
    @Output()
176
    public groupingExpressionsChange = new EventEmitter<IGroupingExpression[]>();
×
177

178
    /**
179
     * @hidden @internal
180
     */
181
    @Output()
182
    public groupingExpansionStateChange = new EventEmitter<IGroupByExpandState[]>();
×
183

184
    /**
185
     * Emitted when columns are grouped/ungrouped.
186
     *
187
     * @remarks
188
     * The `groupingDone` event would be raised only once if several columns get grouped at once by calling
189
     * the `groupBy()` or `clearGrouping()` API methods and passing an array as an argument.
190
     * The event arguments provide the `expressions`, `groupedColumns` and `ungroupedColumns` properties, which contain
191
     * the `ISortingExpression` and the `IgxColumnComponent` related to the grouping/ungrouping operation.
192
     * Please note that `groupedColumns` and `ungroupedColumns` show only the **newly** changed columns (affected by the **last**
193
     * grouping/ungrouping operation), not all columns which are currently grouped/ungrouped.
194
     * columns.
195
     * @example
196
     * ```html
197
     * <igx-grid #grid [data]="localData" (groupingDone)="groupingDone($event)" [autoGenerate]="true"></igx-grid>
198
     * ```
199
     */
200
    @Output()
201
    public groupingDone = new EventEmitter<IGroupingDoneEventArgs>();
×
202

203
    /**
204
     * Gets/Sets whether created groups are rendered expanded or collapsed.
205
     *
206
     * @remarks
207
     * The default rendered state is expanded.
208
     * @example
209
     * ```html
210
     * <igx-grid #grid [data]="Data" [groupsExpanded]="false" [autoGenerate]="true"></igx-grid>
211
     * ```
212
     */
213
    @Input({ transform: booleanAttribute })
214
    public groupsExpanded = true;
×
215

216
    /**
217
     * Gets/Sets the template that will be rendered as a GroupBy drop area.
218
     *
219
     * @remarks
220
     * The grid needs to have at least one groupable column in order the GroupBy area to be displayed.
221
     * @example
222
     * ```html
223
     * <igx-grid [dropAreaTemplate]="dropAreaRef">
224
     * </igx-grid>
225
     * <ng-template #myDropArea>
226
     *      <span> Custom drop area! </span>
227
     * </ng-template>
228
     * ```
229
     */
230
    @Input()
231
    public dropAreaTemplate: TemplateRef<void>;
232

233
    /**
234
     * @hidden @internal
235
     */
236
    @ContentChild(IgxGridDetailTemplateDirective, { read: TemplateRef })
237
    public detailTemplateDirective: TemplateRef<IgxGridMasterDetailContext>;
238

239

240
    /**
241
     * Returns a reference to the master-detail template.
242
     * ```typescript
243
     * let detailTemplate = this.grid.detailTemplate;
244
     * ```
245
     *
246
     * @memberof IgxColumnComponent
247
     */
248
    @Input('detailTemplate')
249
    public get detailTemplate(): TemplateRef<IgxGridMasterDetailContext> {
250
        return this._detailTemplate;
×
251
    }
252
    /**
253
     * Sets the master-detail template.
254
     * ```html
255
     * <ng-template #detailTemplate igxGridDetail let-dataItem>
256
     *    <div>
257
     *       <div><span class='categoryStyle'>City:</span> {{dataItem.City}}</div>
258
     *       <div><span class='categoryStyle'>Address:</span> {{dataItem.Address}}</div>
259
     *    </div>
260
     * </ng-template>
261
     * ```
262
     * ```typescript
263
     * @ViewChild("'detailTemplate'", {read: TemplateRef })
264
     * public detailTemplate: TemplateRef<any>;
265
     * this.grid.detailTemplate = this.detailTemplate;
266
     * ```
267
     *
268
     * @memberof IgxColumnComponent
269
     */
270
    public set detailTemplate(template: TemplateRef<IgxGridMasterDetailContext>) {
271
        this._detailTemplate = template;
×
272
    }
273

274
    /**
275
     * @hidden @internal
276
     */
277
    @HostBinding('attr.role')
278
    public role = 'grid';
×
279

280
    /**
281
     * Gets/Sets the value of the `id` attribute.
282
     *
283
     * @remarks
284
     * If not provided it will be automatically generated.
285
     * @example
286
     * ```html
287
     * <igx-grid [id]="'igx-grid-1'" [data]="Data" [autoGenerate]="true"></igx-grid>
288
     * ```
289
     */
290
    @HostBinding('attr.id')
291
    @Input()
292
    public id = `igx-grid-${NEXT_ID++}`;
×
293

294
    /**
295
     * @hidden @internal
296
     */
297
    @ViewChild('record_template', { read: TemplateRef, static: true })
298
    protected recordTemplate: TemplateRef<any>;
299

300
    @ViewChild('detail_template_container', { read: TemplateRef, static: true })
301
    protected detailTemplateContainer: TemplateRef<any>;
302

303
    @ViewChild('group_template', { read: TemplateRef, static: true })
304
    protected defaultGroupTemplate: TemplateRef<any>;
305

306
    @ViewChild('summary_template', { read: TemplateRef, static: true })
307
    protected summaryTemplate: TemplateRef<any>;
308

309
    /**
310
     * @hidden @internal
311
     */
312
    @ContentChild(IgxGroupByRowTemplateDirective, { read: IgxGroupByRowTemplateDirective })
313
    protected groupTemplate: IgxGroupByRowTemplateDirective;
314

315
    /**
316
     * @hidden
317
     * @internal
318
     */
319
    @ContentChildren(IgxGroupByRowSelectorDirective, { read: TemplateRef, descendants: false })
320
    protected groupByRowSelectorsTemplates: QueryList<TemplateRef<IgxGroupByRowSelectorTemplateContext>>;
321

322
    @ViewChildren(IgxGridGroupByRowComponent, { read: IgxGridGroupByRowComponent })
323
    private _groupsRowList: QueryList<IgxGridGroupByRowComponent>;
324

325
    private _groupsRecords: IGroupByRecord[] = [];
×
326
    /**
327
     * Gets the hierarchical representation of the group by records.
328
     *
329
     * @example
330
     * ```typescript
331
     * let groupRecords = this.grid.groupsRecords;
332
     * ```
333
     */
334
    public get groupsRecords(): IGroupByRecord[] {
335
        return this._groupsRecords;
×
336
    }
337

338
    /**
339
     * @hidden @internal
340
     * Includes children of collapsed group rows.
341
     */
342
    public groupingResult: any[];
343

344
    /**
345
     * @hidden @internal
346
     */
347
    public groupingMetadata: any[];
348

349
    /**
350
     * @hidden @internal
351
     * Does not include children of collapsed group rows.
352
     */
353
    public groupingFlatResult: any[];
354
    /**
355
     * @hidden
356
     */
357
    protected _groupingExpressions: IGroupingExpression[] = [];
×
358
    /**
359
     * @hidden
360
     */
361
    protected _groupingExpandState: IGroupByExpandState[] = [];
×
362
    /**
363
     * @hidden
364
     */
365
    protected _groupRowTemplate: TemplateRef<IgxGroupByRowTemplateContext>;
366

367
    /**
368
     * @hidden
369
     */
370
    protected _groupStrategy: IGridGroupingStrategy;
371
    /**
372
     * @hidden
373
     */
374
    protected groupingDiffer;
375
    private _data?: any[] | null;
376
    private _hideGroupedColumns = false;
×
377
    private _dropAreaMessage = null;
×
378
    private _showGroupArea = true;
×
379

380
    private _groupByRowSelectorTemplate: TemplateRef<IgxGroupByRowSelectorTemplateContext>;
381
    private _detailTemplate;
382

383

384
    /**
385
     * Gets/Sets the array of data that populates the component.
386
     *
387
     * @example
388
     * ```html
389
     * <igx-grid [data]="Data" [autoGenerate]="true"></igx-grid>
390
     * ```
391
     */
392
    /* treatAsRef */
393
    @Input()
394
    public get data(): any[] | null {
395
        return this._data;
×
396
    }
397

398
    public set data(value: any[] | null) {
399
        const dataLoaded = (!this._data || this._data.length === 0) && value && value.length > 0;
×
400
        const oldData = this._data;
×
401
        this._data = value || [];
×
402
        this.summaryService.clearSummaryCache();
×
403
        if (!this._init) {
×
404
            this.validation.updateAll(this._data);
×
405
        }
406

407
        if (this.autoGenerate && this._data.length > 0 && this.shouldRecreateColumns(oldData, this._data)) {
×
408
            this.setupColumns();
×
409
        }
410

411
        this.cdr.markForCheck();
×
412
        if (this.isPercentHeight) {
×
413
            this.notifyChanges(true);
×
414
        }
415
        // check if any columns have width auto and if so recalculate their auto-size on data loaded.
416
        if (dataLoaded && this._columns.some(x => (x as any)._width === 'auto')) {
×
417
            this.recalculateAutoSizes();
×
418
        }
419
        this.checkPrimaryKeyField();
×
420
    }
421

422
    /**
423
     * Gets/Sets the total number of records in the data source.
424
     *
425
     * @remarks
426
     * This property is required for remote grid virtualization to function when it is bound to remote data.
427
     * @example
428
     * ```typescript
429
     * const itemCount = this.grid1.totalItemCount;
430
     * this.grid1.totalItemCount = 55;
431
     * ```
432
     */
433
    @Input()
434
    public set totalItemCount(count) {
435
        this.verticalScrollContainer.totalItemCount = count;
×
436
    }
437

438
    public get totalItemCount() {
439
        return this.verticalScrollContainer.totalItemCount;
×
440
    }
441

442
    private get _gridAPI(): IgxGridAPIService {
443
        return this.gridAPI as IgxGridAPIService;
×
444
    }
445

446
    private childDetailTemplates: Map<any, any> = new Map();
×
447

448
    /**
449
     * @hidden @internal
450
     */
451
    public groupingPerformedSubject = new Subject<void>();
×
452

453
    /**
454
     * @hidden @internal
455
     */
456
    public groupingPerformed$: Observable<void> = this.groupingPerformedSubject.asObservable();
×
457

458
    /* mustSetInCodePlatforms: WebComponents;Blazor;React */
459
    /**
460
     * Gets/Sets the group by state.
461
     *
462
     * @example
463
     * ```typescript
464
     * let groupByState = this.grid.groupingExpressions;
465
     * this.grid.groupingExpressions = [...];
466
     * ```
467
     * @remarks
468
     * Supports two-way data binding.
469
     * @example
470
     * ```html
471
     * <igx-grid #grid [data]="Data" [autoGenerate]="true" [(groupingExpressions)]="model.groupingExpressions"></igx-grid>
472
     * ```
473
     */
474
    @Input()
475
    public get groupingExpressions(): IGroupingExpression[] {
476
        return this._groupingExpressions;
×
477
    }
478

479
    public set groupingExpressions(value: IGroupingExpression[]) {
480
        if (this.groupingExpressions === value) {
×
481
            return;
×
482
        }
483
        if (value && value.length > 10) {
×
484
            throw Error('Maximum amount of grouped columns is 10.');
×
485
        }
486
        const oldExpressions: IGroupingExpression[] = this.groupingExpressions;
×
487
        const newExpressions: IGroupingExpression[] = value;
×
488
        this._groupingExpressions = cloneArray(value);
×
489
        this.groupingExpressionsChange.emit(this._groupingExpressions);
×
490
        if (this._gridAPI.grid) {
×
491
            /* grouping and sorting are working separate from each other */
492
            this._applyGrouping();
×
493
            this.notifyChanges();
×
494
        }
495
        if (!this._init && JSON.stringify(oldExpressions, this.stringifyCallback) !== JSON.stringify(newExpressions, this.stringifyCallback) && this._columns) {
×
496
            const groupedCols: IgxColumnComponent[] = [];
×
497
            const ungroupedCols: IgxColumnComponent[] = [];
×
498
            const groupedColsArr = newExpressions.filter((obj) => !oldExpressions.some((obj2) => obj.fieldName === obj2.fieldName));
×
499
            groupedColsArr.forEach((elem) => {
×
500
                groupedCols.push(this.getColumnByName(elem.fieldName));
×
501
            }, this);
502
            const ungroupedColsArr = oldExpressions.filter((obj) => !newExpressions.some((obj2) => obj.fieldName === obj2.fieldName));
×
503
            ungroupedColsArr.forEach((elem) => {
×
504
                ungroupedCols.push(this.getColumnByName(elem.fieldName));
×
505
            }, this);
506
            this.notifyChanges();
×
507
            const groupingDoneArgs: IGroupingDoneEventArgs = {
×
508
                expressions: newExpressions,
509
                groupedColumns: groupedCols,
510
                ungroupedColumns: ungroupedCols
511
            };
512
            this.groupingPerformed$.pipe(take(1)).subscribe(() => {
×
513
                this.groupingDone.emit(groupingDoneArgs);
×
514
            });
515
        }
516
    }
517

518
    /**
519
     * Gets/Sets a list of expansion states for group rows.
520
     *
521
     * @remarks
522
     * Includes only states that differ from the default one (controlled through groupsExpanded and states that the user has changed.
523
     * Contains the expansion state (expanded: boolean) and the unique identifier for the group row (Array).
524
     * Supports two-way data binding.
525
     * @example
526
     * ```html
527
     * <igx-grid #grid [data]="Data" [autoGenerate]="true" [(groupingExpansionState)]="model.groupingExpansionState"></igx-grid>
528
     * ```
529
     */
530
    @Input()
531
    public get groupingExpansionState() {
532
        return this._groupingExpandState;
×
533
    }
534

535
    public set groupingExpansionState(value) {
536
        if (value !== this._groupingExpandState) {
×
537
            this.groupingExpansionStateChange.emit(value);
×
538
        }
539
        this._groupingExpandState = value;
×
540
        if (this.gridAPI.grid) {
×
541
            this.cdr.detectChanges();
×
542
        }
543
    }
544

545
    /**
546
     * Gets/Sets whether the grouped columns should be hidden.
547
     *
548
     * @remarks
549
     * The default value is "false"
550
     * @example
551
     * ```html
552
     * <igx-grid #grid [data]="localData" [hideGroupedColumns]="true" [autoGenerate]="true"></igx-grid>
553
     * ```
554
     */
555
    @Input({ transform: booleanAttribute })
556
    public get hideGroupedColumns() {
557
        return this._hideGroupedColumns;
×
558
    }
559

560
    public set hideGroupedColumns(value: boolean) {
561
        if (value) {
×
562
            this.groupingDiffer = this.differs.find(this.groupingExpressions).create();
×
563
        } else {
564
            this.groupingDiffer = null;
×
565
        }
566
        if (this._columns && this.groupingExpressions) {
×
567
            this._setGroupColsVisibility(value);
×
568
        }
569

570
        this._hideGroupedColumns = value;
×
571
    }
572

573
    /**
574
     * Gets/Sets the grouping strategy of the grid.
575
     *
576
     * @remarks The default IgxGrouping extends from IgxSorting and a custom one can be used as a `sortStrategy` as well.
577
     *
578
     * @example
579
     * ```html
580
     *  <igx-grid #grid [data]="localData" [groupStrategy]="groupStrategy"></igx-grid>
581
     * ```
582
     */
583
    @Input()
584
    public get groupStrategy(): IGridGroupingStrategy {
585
        return this._groupStrategy;
×
586
    }
587

588
    public set groupStrategy(value: IGridGroupingStrategy) {
589
        this._groupStrategy = value;
×
590
    }
591

592
    /**
593
     * Gets/Sets the message displayed inside the GroupBy drop area where columns can be dragged on.
594
     *
595
     * @remarks
596
     * The grid needs to have at least one groupable column in order the GroupBy area to be displayed.
597
     * @example
598
     * ```html
599
     * <igx-grid dropAreaMessage="Drop here to group!">
600
     *      <igx-column [groupable]="true" field="ID"></igx-column>
601
     * </igx-grid>
602
     * ```
603
     */
604
    @Input()
605
    public set dropAreaMessage(value: string) {
606
        this._dropAreaMessage = value;
×
607
        this.notifyChanges();
×
608
    }
609

610
    public get dropAreaMessage(): string {
611
        return this._dropAreaMessage || this.resourceStrings.igx_grid_groupByArea_message;
×
612
    }
613

614
    /**
615
     * @hidden @internal
616
     */
617
    public get groupsRowList() {
618
        const res = new QueryList<any>();
×
619
        if (!this._groupsRowList) {
×
620
            return res;
×
621
        }
622
        const rList = this._groupsRowList.filter(item => item.element.nativeElement.parentElement !== null)
×
623
            .sort((item1, item2) => item1.index - item2.index);
×
624
        res.reset(rList);
×
625
        return res;
×
626
    }
627

628
    /**
629
     * Gets the group by row selector template.
630
     */
631
    @Input()
632
    public get groupByRowSelectorTemplate(): TemplateRef<IgxGroupByRowSelectorTemplateContext> {
633
        return this._groupByRowSelectorTemplate || this.groupByRowSelectorsTemplates?.first;
×
634
    }
635

636
    /**
637
     * Sets the group by row selector template.
638
     * ```html
639
     * <ng-template #template igxGroupByRowSelector let-groupByRowContext>
640
     * {{ groupByRowContext.selectedCount }} / {{ groupByRowContext.totalCount  }}
641
     * </ng-template>
642
     * ```
643
     * ```typescript
644
     * @ViewChild("'template'", {read: TemplateRef })
645
     * public template: TemplateRef<any>;
646
     * this.grid.groupByRowSelectorTemplate = this.template;
647
     * ```
648
     */
649
    public set groupByRowSelectorTemplate(template: TemplateRef<IgxGroupByRowSelectorTemplateContext>) {
650
        this._groupByRowSelectorTemplate = template;
×
651
    }
652

653
    /**
654
     * @hidden @internal
655
     */
656
    public getDetailsContext(rowData, index): IgxGridDetailTemplateDirective {
657
        return {
×
658
            $implicit: rowData,
659
            index
660
        };
661
    }
662

663
    /**
664
     * @hidden @internal
665
     */
666
    public detailsViewFocused(container, rowIndex) {
667
        this.navigation.setActiveNode({ row: rowIndex });
×
668
    }
669

670
    /**
671
     * @hidden @internal
672
     */
673
    public override get hasDetails() {
674
        return !!this.detailTemplate;
×
675
    }
676

677
    /**
678
     * @hidden @internal
679
     */
680
    public getRowTemplate(rowData) {
681
        if (this.isGroupByRecord(rowData)) {
×
682
            return this.defaultGroupTemplate;
×
683
        } else if (this.isSummaryRow(rowData)) {
×
684
            return this.summaryTemplate;
×
685
        } else if (this.hasDetails && this.isDetailRecord(rowData)) {
×
686
            return this.detailTemplateContainer;
×
687
        } else {
688
            return this.recordTemplate;
×
689
        }
690
    }
691

692
    /**
693
     * @hidden @internal
694
     */
695
    public override isDetailRecord(record) {
696
        return record && record.detailsData !== undefined;
×
697
    }
698

699
    /**
700
     * @hidden @internal
701
     */
702
    public isDetailActive(rowIndex) {
703
        return this.navigation.activeNode ? this.navigation.activeNode.row === rowIndex : false;
×
704
    }
705

706
    /**
707
     * Gets/Sets the template reference for the group row.
708
     *
709
     * @example
710
     * ```
711
     * const groupRowTemplate = this.grid.groupRowTemplate;
712
     * this.grid.groupRowTemplate = myRowTemplate;
713
     * ```
714
     */
715
    @Input()
716
    public get groupRowTemplate(): TemplateRef<IgxGroupByRowTemplateContext> {
717
        return this._groupRowTemplate;
×
718
    }
719

720
    public set groupRowTemplate(template: TemplateRef<IgxGroupByRowTemplateContext>) {
721
        this._groupRowTemplate = template;
×
722
        this.notifyChanges();
×
723
    }
724

725
    /** @hidden @internal */
726
    public trackChanges: (index, rec) => any;
727

728
    /**
729
     * Groups by a new `IgxColumnComponent` based on the provided expression, or modifies an existing one.
730
     *
731
     * @remarks
732
     * Also allows for multiple columns to be grouped at once if an array of `ISortingExpression` is passed.
733
     * The `groupingDone` event would get raised only **once** if this method gets called multiple times with the same arguments.
734
     * @example
735
     * ```typescript
736
     * this.grid.groupBy({ fieldName: name, dir: SortingDirection.Asc, ignoreCase: false });
737
     * this.grid.groupBy([
738
     *     { fieldName: name1, dir: SortingDirection.Asc, ignoreCase: false },
739
     *     { fieldName: name2, dir: SortingDirection.Desc, ignoreCase: true },
740
     *     { fieldName: name3, dir: SortingDirection.Desc, ignoreCase: false }
741
     * ]);
742
     * ```
743
     */
744
    public groupBy(expression: IGroupingExpression | Array<IGroupingExpression>): void {
745
        if (this.checkIfNoColumnField(expression)) {
×
746
            return;
×
747
        }
748
        this.crudService.endEdit(false);
×
749
        if (expression instanceof Array) {
×
750
            this._gridAPI.groupBy_multiple(expression);
×
751
        } else {
752
            this._gridAPI.groupBy(expression);
×
753
        }
754
        this.notifyChanges(true);
×
755
    }
756

757
    /**
758
     * Clears grouping for particular column, array of columns or all columns.
759
     *
760
     * @remarks
761
     * Clears all grouping in the grid, if no parameter is passed.
762
     * If a parameter is provided, clears grouping for a particular column or an array of columns.
763
     * @example
764
     * ```typescript
765
     * this.grid.clearGrouping(); //clears all grouping
766
     * this.grid.clearGrouping("ID"); //ungroups a single column
767
     * this.grid.clearGrouping(["ID", "Column1", "Column2"]); //ungroups multiple columns
768
     * ```
769
     * @param name Name of column or array of column names to be ungrouped.
770
     */
771
    public clearGrouping(name?: string | Array<string>): void {
772
        this._gridAPI.clear_groupby(name);
×
773
        this.calculateGridSizes();
×
774
        this.notifyChanges(true);
×
775
        this.groupingPerformedSubject.next();
×
776
    }
777

778
    /**
779
     * Returns if a group is expanded or not.
780
     *
781
     * @param group The group record.
782
     * @example
783
     * ```typescript
784
     * public groupRow: IGroupByRecord;
785
     * const expandedGroup = this.grid.isExpandedGroup(this.groupRow);
786
     * ```
787
     */
788
    public override isExpandedGroup(group: IGroupByRecord): boolean {
789
        const state: IGroupByExpandState = this._getStateForGroupRow(group);
×
790
        return state ? state.expanded : this.groupsExpanded;
×
791
    }
792

793
    /**
794
     * Toggles the expansion state of a group.
795
     *
796
     * @param groupRow The group record to toggle.
797
     * @example
798
     * ```typescript
799
     * public groupRow: IGroupByRecord;
800
     * const toggleExpGroup = this.grid.toggleGroup(this.groupRow);
801
     * ```
802
     */
803
    public toggleGroup(groupRow: IGroupByRecord) {
804
        this._toggleGroup(groupRow);
×
805
        this.notifyChanges();
×
806
    }
807

808
    /**
809
     * Select all rows within a group.
810
     *
811
     * @param groupRow: The group record which rows would be selected.
812
     * @param clearCurrentSelection if true clears the current selection
813
     * @example
814
     * ```typescript
815
     * this.grid.selectRowsInGroup(this.groupRow, true);
816
     * ```
817
     */
818
    public selectRowsInGroup(groupRow: IGroupByRecord, clearPrevSelection?: boolean) {
819
        this._gridAPI.groupBy_select_all_rows_in_group(groupRow, clearPrevSelection);
×
820
        this.notifyChanges();
×
821
    }
822

823
    /**
824
     * Deselect all rows within a group.
825
     *
826
     * @param groupRow The group record which rows would be deselected.
827
     * @example
828
     * ```typescript
829
     * public groupRow: IGroupByRecord;
830
     * this.grid.deselectRowsInGroup(this.groupRow);
831
     * ```
832
     */
833
    public deselectRowsInGroup(groupRow: IGroupByRecord) {
834
        this._gridAPI.groupBy_deselect_all_rows_in_group(groupRow);
×
835
        this.notifyChanges();
×
836
    }
837

838
    /**
839
     * Expands the specified group and all of its parent groups.
840
     *
841
     * @param groupRow The group record to fully expand.
842
     * @example
843
     * ```typescript
844
     * public groupRow: IGroupByRecord;
845
     * this.grid.fullyExpandGroup(this.groupRow);
846
     * ```
847
     */
848
    public fullyExpandGroup(groupRow: IGroupByRecord) {
849
        this._fullyExpandGroup(groupRow);
×
850
        this.notifyChanges();
×
851
    }
852

853
    /**
854
     * @hidden @internal
855
     */
856
    public override isGroupByRecord(record: any): boolean {
857
        // return record.records instance of GroupedRecords fails under Webpack
858
        return record && record?.records && record.records?.length &&
×
859
            record.expression && record.expression?.fieldName;
860
    }
861

862
    /**
863
     * Toggles the expansion state of all group rows recursively.
864
     *
865
     * @example
866
     * ```typescript
867
     * this.grid.toggleAllGroupRows;
868
     * ```
869
     */
870
    public toggleAllGroupRows() {
871
        this.groupingExpansionState = [];
×
872
        this.groupsExpanded = !this.groupsExpanded;
×
873
        this.notifyChanges();
×
874
    }
875

876
    /** @hidden @internal */
877
    public get hasGroupableColumns(): boolean {
878
        return this._columns.some((col) => col.groupable && !col.columnGroup);
×
879
    }
880

881
    /**
882
     * Returns whether the `IgxGridComponent` has group area.
883
     *
884
     * @example
885
     * ```typescript
886
     * let isGroupAreaVisible = this.grid.showGroupArea;
887
     * ```
888
     *
889
     * @example
890
     * ```html
891
     * <igx-grid #grid [data]="Data" [showGroupArea]="false"></igx-grid>
892
     * ```
893
     */
894
    @Input({ transform: booleanAttribute })
895
    public get showGroupArea(): boolean {
896
        return this._showGroupArea;
×
897
    }
898
    public set showGroupArea(value: boolean) {
899
        this._showGroupArea = value;
×
900
        this.notifyChanges(true);
×
901
    }
902

903
    /**
904
     * @hidden @internal
905
     */
906
    public override isColumnGrouped(fieldName: string): boolean {
907
        return this.groupingExpressions.find(exp => exp.fieldName === fieldName) ? true : false;
×
908
    }
909

910
    /**
911
     * @hidden @internal
912
     */
913
    public getContext(rowData: any, rowIndex: number, pinned?: boolean): any {
914
        if (this.isDetailRecord(rowData)) {
×
915
            const cachedData = this.childDetailTemplates.get(rowData.detailsData);
×
916
            const rowID = this.primaryKey ? rowData.detailsData[this.primaryKey] : rowData.detailsData;
×
917
            if (cachedData) {
×
918
                const view = cachedData.view;
×
919
                const tmlpOutlet = cachedData.owner;
×
920
                return {
×
921
                    $implicit: rowData.detailsData,
922
                    moveView: view,
923
                    owner: tmlpOutlet,
924
                    index: this.dataView.indexOf(rowData),
925
                    templateID: {
926
                        type: 'detailRow',
927
                        id: rowID
928
                    }
929
                };
930
            } else {
931
                // child rows contain unique grids, hence should have unique templates
932
                return {
×
933
                    $implicit: rowData.detailsData,
934
                    templateID: {
935
                        type: 'detailRow',
936
                        id: rowID
937
                    },
938
                    index: this.dataView.indexOf(rowData)
939
                };
940
            }
941
        }
942
        return {
×
943
            $implicit: this.isGhostRecord(rowData) ? rowData.recordRef : rowData,
×
944
            index: this.getDataViewIndex(rowIndex, pinned),
945
            templateID: {
946
                type: this.isGroupByRecord(rowData) ? 'groupRow' : this.isSummaryRow(rowData) ? 'summaryRow' : 'dataRow',
×
947
                id: null
948
            },
949
            disabled: this.isGhostRecord(rowData)
950
        };
951
    }
952

953
    /**
954
     * @hidden @internal
955
     */
956
    public viewCreatedHandler(args) {
957
        if (args.context.templateID.type === 'detailRow') {
×
958
            this.childDetailTemplates.set(args.context.$implicit, args);
×
959
        }
960
    }
961

962
    /**
963
     * @hidden @internal
964
     */
965
    public viewMovedHandler(args) {
966
        if (args.context.templateID.type === 'detailRow') {
×
967
            // view was moved, update owner in cache
968
            const key = args.context.$implicit;
×
969
            const cachedData = this.childDetailTemplates.get(key);
×
970
            cachedData.owner = args.owner;
×
971
        }
972
    }
973

974
    /**
975
     * @hidden @internal
976
     */
977
    public get iconTemplate() {
978
        if (this.groupsExpanded) {
×
979
            return this.headerExpandedIndicatorTemplate || this.defaultExpandedTemplate;
×
980
        } else {
981
            return this.headerCollapsedIndicatorTemplate || this.defaultCollapsedTemplate;
×
982
        }
983
    }
984

985
    /**
986
     * @hidden @internal
987
     */
988
    public override ngAfterContentInit() {
989
        super.ngAfterContentInit();
×
990
        if (this.allowFiltering && this.hasColumnLayouts) {
×
991
            this.filterMode = FilterMode.excelStyleFilter;
×
992
        }
993
        if (this.groupTemplate) {
×
994
            this._groupRowTemplate = this.groupTemplate.template;
×
995
        }
996

997
        if (this.detailTemplateDirective) {
×
998
            this._detailTemplate = this.detailTemplateDirective;
×
999
        }
1000

1001

1002
        if (this.hideGroupedColumns && this._columns && this.groupingExpressions) {
×
1003
            this._setGroupColsVisibility(this.hideGroupedColumns);
×
1004
        }
1005
        this._setupNavigationService();
×
1006
    }
1007

1008
    /**
1009
     * @hidden @internal
1010
     */
1011
    public override ngAfterViewInit() {
1012
        super.ngAfterViewInit();
×
1013
        this.verticalScrollContainer.beforeViewDestroyed.pipe(takeUntil(this.destroy$)).subscribe((view) => {
×
1014
            const rowData = view.context.$implicit;
×
1015
            if (this.isDetailRecord(rowData)) {
×
1016
                const cachedData = this.childDetailTemplates.get(rowData.detailsData);
×
1017
                if (cachedData) {
×
1018
                    const tmlpOutlet = cachedData.owner;
×
1019
                    tmlpOutlet._viewContainerRef.detach(0);
×
1020
                }
1021
            }
1022
        });
1023

1024
        this.sortingExpressionsChange.pipe(takeUntil(this.destroy$)).subscribe((sortingExpressions: ISortingExpression[]) => {
×
1025
            if (!this.groupingExpressions || !this.groupingExpressions.length) {
×
1026
                return;
×
1027
            }
1028

1029
            sortingExpressions.forEach((sortExpr: ISortingExpression) => {
×
1030
                const fieldName = sortExpr.fieldName;
×
1031
                const groupingExpr = this.groupingExpressions.find(ex => ex.fieldName === fieldName);
×
1032
                if (groupingExpr) {
×
1033
                    groupingExpr.dir = sortExpr.dir;
×
1034
                }
1035
            });
1036
        });
1037
    }
1038

1039
    /**
1040
     * @hidden @internal
1041
     */
1042
    public override ngOnInit() {
1043
        super.ngOnInit();
×
1044
        this.trackChanges = (_, rec) => (rec?.detailsData !== undefined ? rec.detailsData : rec);
×
1045
        this.groupingDone.pipe(takeUntil(this.destroy$)).subscribe((args) => {
×
1046
            this.crudService.endEdit(false);
×
1047
            this.summaryService.updateSummaryCache(args);
×
1048
            this._headerFeaturesWidth = NaN;
×
1049
        });
1050
    }
1051

1052
    /**
1053
     * @hidden @internal
1054
     */
1055
    public override ngDoCheck(): void {
1056
        if (this.groupingDiffer && this._columns && !this.hasColumnLayouts) {
×
1057
            const changes = this.groupingDiffer.diff(this.groupingExpressions);
×
1058
            if (changes && this._columns.length > 0) {
×
1059
                changes.forEachAddedItem((rec) => {
×
1060
                    const col = this.getColumnByName(rec.item.fieldName);
×
1061
                    if (col) {
×
1062
                        col.hidden = true;
×
1063
                    }
1064
                });
1065
                changes.forEachRemovedItem((rec) => {
×
1066
                    const col = this.getColumnByName(rec.item.fieldName);
×
1067
                    col.hidden = false;
×
1068
                });
1069
            }
1070
        }
1071
        super.ngDoCheck();
×
1072
    }
1073

1074
    /**
1075
     * @hidden @internal
1076
     */
1077
    public dataLoading(event) {
1078
        this.dataPreLoad.emit(event);
×
1079
    }
1080

1081
    /**
1082
     *
1083
     * Returns an array of the current cell selection in the form of `[{ column.field: cell.value }, ...]`.
1084
     *
1085
     * @remarks
1086
     * If `formatters` is enabled, the cell value will be formatted by its respective column formatter (if any).
1087
     * If `headers` is enabled, it will use the column header (if any) instead of the column field.
1088
     */
1089
    public override getSelectedData(formatters = false, headers = false): any[] {
×
1090
        if (this.groupingExpressions.length || this.hasDetails) {
×
1091
            const source = [];
×
1092

1093
            const process = (record) => {
×
1094
                if (record.expression || record.summaries || this.isDetailRecord(record)) {
×
1095
                    source.push(null);
×
1096
                    return;
×
1097
                }
1098
                source.push(record);
×
1099

1100
            };
1101

1102
            this.dataView.forEach(process);
×
1103
            return this.extractDataFromSelection(source, formatters, headers);
×
1104
        } else {
1105
            return super.getSelectedData(formatters, headers);
×
1106
        }
1107
    }
1108

1109
    /**
1110
     * Returns the `IgxGridRow` by index.
1111
     *
1112
     * @example
1113
     * ```typescript
1114
     * const myRow = grid.getRowByIndex(1);
1115
     * ```
1116
     * @param index
1117
     */
1118
    public getRowByIndex(index: number): RowType {
1119
        let row: RowType;
1120
        if (index < 0) {
×
1121
            return undefined;
×
1122
        }
1123
        if (this.dataView.length >= this.virtualizationState.startIndex + this.virtualizationState.chunkSize) {
×
1124
            row = this.createRow(index);
×
1125
        } else {
1126
            if (!(index < this.virtualizationState.startIndex) && !(index > this.virtualizationState.startIndex + this.virtualizationState.chunkSize)) {
×
1127
                row = this.createRow(index);
×
1128
            }
1129
        }
1130

1131
        if (this.pagingMode === 1 && this.page !== 0) {
×
1132
            row.index = index + this.perPage * this.page;
×
1133
        }
1134
        return row;
×
1135
    }
1136

1137
    /**
1138
     * Returns `IgxGridRow` object by the specified primary key.
1139
     *
1140
     * @remarks
1141
     * Requires that the `primaryKey` property is set.
1142
     * @example
1143
     * ```typescript
1144
     * const myRow = this.grid1.getRowByKey("cell5");
1145
     * ```
1146
     * @param keyValue
1147
     */
1148
    public getRowByKey(key: any): RowType {
1149
        const rec = this.filteredSortedData ? this.primaryKey ?
×
1150
            this.filteredSortedData.find(record => record[this.primaryKey] === key) :
×
1151
            this.filteredSortedData.find(record => record === key) : undefined;
×
1152
        const index = this.dataView.indexOf(rec);
×
1153
        if (index < 0 || index > this.dataView.length) {
×
1154
            return undefined;
×
1155
        }
1156

1157
        return new IgxGridRow(this, index, rec);
×
1158
    }
1159

1160
    /**
1161
     * @hidden @internal
1162
     */
1163
    public allRows(): RowType[] {
1164
        return this.dataView.map((rec, index) => {
×
1165
            this.pagingMode === 1 && this.page !== 0 ? index = index + this.perPage * this.page : index = this.dataRowList.first.index + index;
×
1166
            return this.createRow(index);
×
1167
        });
1168
    }
1169

1170
    /**
1171
     * Returns the collection of `IgxGridRow`s for current page.
1172
     *
1173
     * @hidden @internal
1174
     */
1175
    public dataRows(): RowType[] {
1176
        return this.allRows().filter(row => row instanceof IgxGridRow);
×
1177
    }
1178

1179
    /**
1180
     * Returns an array of the selected `IgxGridCell`s.
1181
     *
1182
     * @example
1183
     * ```typescript
1184
     * const selectedCells = this.grid.selectedCells;
1185
     * ```
1186
     */
1187
    public get selectedCells(): CellType[] {
1188
        return this.dataRows().map((row) => row.cells.filter((cell) => cell.selected))
×
1189
            .reduce((a, b) => a.concat(b), []);
×
1190
    }
1191

1192
    /**
1193
     * Returns a `CellType` object that matches the conditions.
1194
     *
1195
     * @example
1196
     * ```typescript
1197
     * const myCell = this.grid1.getCellByColumn(2, "UnitPrice");
1198
     * ```
1199
     * @param rowIndex
1200
     * @param columnField
1201
     */
1202
    public getCellByColumn(rowIndex: number, columnField: string): CellType {
1203
        const row = this.getRowByIndex(rowIndex);
×
1204
        const column = this._columns.find((col) => col.field === columnField);
×
1205
        if (row && row instanceof IgxGridRow && !row.data?.detailsData && column) {
×
1206
            if (this.pagingMode === 1 && this.page !== 0) {
×
1207
                row.index = rowIndex + this.perPage * this.page;
×
1208
            }
1209
            return new IgxGridCell(this, row.index, column);
×
1210
        }
1211
    }
1212

1213
    /**
1214
     * Returns a `CellType` object that matches the conditions.
1215
     *
1216
     * @remarks
1217
     * Requires that the primaryKey property is set.
1218
     * @example
1219
     * ```typescript
1220
     * grid.getCellByKey(1, 'index');
1221
     * ```
1222
     * @param rowSelector match any rowID
1223
     * @param columnField
1224
     */
1225
    public getCellByKey(rowSelector: any, columnField: string): CellType {
1226
        const row = this.getRowByKey(rowSelector);
×
1227
        const column = this._columns.find((col) => col.field === columnField);
×
1228
        if (row && column) {
×
1229
            return new IgxGridCell(this, row.index, column);
×
1230
        }
1231
    }
1232

1233
    public override pinRow(rowID: any, index?: number): boolean {
1234
        const row = this.getRowByKey(rowID);
×
1235
        return super.pinRow(rowID, index, row);
×
1236
    }
1237

1238
    public override unpinRow(rowID: any): boolean {
1239
        const row = this.getRowByKey(rowID);
×
1240
        return super.unpinRow(rowID, row);
×
1241
    }
1242

1243
    /**
1244
     * @hidden @internal
1245
     */
1246
    public createRow(index: number, data?: any): RowType {
1247
        let row: RowType;
1248

1249
        const dataIndex = this._getDataViewIndex(index);
×
1250
        const rec = data ?? this.dataView[dataIndex];
×
1251

1252
        if (rec && this.isGroupByRecord(rec)) {
×
1253
            row = new IgxGroupByRow(this, index, rec);
×
1254
        }
1255
        if (rec && this.isSummaryRow(rec)) {
×
1256
            row = new IgxSummaryRow(this, index, rec.summaries);
×
1257
        }
1258
        // if found record is a no a groupby or summary row, return IgxGridRow instance
1259
        if (!row && rec) {
×
1260
            row = new IgxGridRow(this, index, rec);
×
1261
        }
1262

1263
        return row;
×
1264
    }
1265

1266
    /**
1267
     * @hidden @internal
1268
     */
1269
    protected override get defaultTargetBodyHeight(): number {
1270
        const allItems = this.totalItemCount || this.dataLength;
×
1271
        return this.renderedActualRowHeight * Math.min(this._defaultTargetRecordNumber,
×
1272
            this.paginator ? Math.min(allItems, this.perPage) : allItems);
×
1273
    }
1274

1275
    /**
1276
     * @hidden @internal
1277
     */
1278
    protected override getGroupAreaHeight(): number {
1279
        return this.groupArea ? this.getComputedHeight(this.groupArea.nativeElement) : 0;
×
1280
    }
1281

1282
    /**
1283
     * @hidden @internal
1284
     */
1285
    protected override onColumnsAddedOrRemoved() {
1286
        // update grouping states
1287
        this.groupablePipeTrigger++;
×
1288
        if (this.groupingExpressions && this.hideGroupedColumns) {
×
1289
            this._setGroupColsVisibility(this.hideGroupedColumns);
×
1290
        }
1291
        super.onColumnsAddedOrRemoved();
×
1292
    }
1293

1294
    /**
1295
     * @hidden @internal
1296
     */
1297
    protected override scrollTo(row: any | number, column: any | number): void {
1298
        if (this.groupingExpressions && this.groupingExpressions.length
×
1299
            && typeof (row) !== 'number') {
1300
            const rowIndex = this.groupingResult.indexOf(row);
×
1301
            const groupByRecord = this.groupingMetadata[rowIndex];
×
1302
            if (groupByRecord) {
×
1303
                this._fullyExpandGroup(groupByRecord);
×
1304
            }
1305
        }
1306

1307
        super.scrollTo(row, column, this.groupingFlatResult);
×
1308
    }
1309

1310
    /**
1311
     * @hidden @internal
1312
     */
1313
    protected _getStateForGroupRow(groupRow: IGroupByRecord): IGroupByExpandState {
1314
        return this._gridAPI.groupBy_get_expanded_for_group(groupRow);
×
1315
    }
1316

1317
    /**
1318
     * @hidden
1319
     */
1320
    protected _toggleGroup(groupRow: IGroupByRecord) {
1321
        this._gridAPI.groupBy_toggle_group(groupRow);
×
1322
    }
1323

1324
    /**
1325
     * @hidden @internal
1326
     */
1327
    protected _fullyExpandGroup(groupRow: IGroupByRecord) {
1328
        this._gridAPI.groupBy_fully_expand_group(groupRow);
×
1329
    }
1330

1331
    /**
1332
     * @hidden @internal
1333
     */
1334
    protected _applyGrouping() {
1335
        this._gridAPI.sort_groupBy_multiple(this._groupingExpressions);
×
1336
    }
1337

1338
    private _setupNavigationService() {
1339
        if (this.hasColumnLayouts) {
×
1340
            this.navigation = new IgxGridMRLNavigationService(this.platform);
×
1341
            this.navigation.grid = this;
×
1342
        }
1343
    }
1344

1345
    private checkIfNoColumnField(expression: IGroupingExpression | Array<IGroupingExpression> | any): boolean {
1346
        if (expression instanceof Array) {
×
1347
            for (const singleExpression of expression) {
×
1348
                if (!singleExpression.fieldName) {
×
1349
                    return true;
×
1350
                }
1351
            }
1352
            return false;
×
1353
        }
1354
        return !expression.fieldName;
×
1355
    }
1356

1357
    private _setGroupColsVisibility(value) {
1358
        if (this._columns.length > 0 && !this.hasColumnLayouts) {
×
1359
            this.groupingExpressions.forEach((expr) => {
×
1360
                const col = this.getColumnByName(expr.fieldName);
×
1361
                col.hidden = value;
×
1362
            });
1363
        }
1364
    }
1365

1366
    private stringifyCallback(key: string, val: any) {
1367
        // Workaround for Blazor, since its wrappers inject this externalObject that cannot serialize.
1368
        if (key === 'externalObject') {
×
1369
            return undefined;
×
1370
        }
1371
        return val;
×
1372
    }
1373
}
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