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

IgniteUI / igniteui-angular / 20990200051

14 Jan 2026 10:06AM UTC coverage: 91.536% (+0.04%) from 91.5%
20990200051

push

github

web-flow
fix(csv): export summaries - master (#16746)

14291 of 16840 branches covered (84.86%)

22 of 23 new or added lines in 2 files covered. (95.65%)

332 existing lines in 14 files now uncovered.

28703 of 31357 relevant lines covered (91.54%)

34858.74 hits per line

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

97.65
/projects/igniteui-angular/grids/core/src/columns/column.component.ts
1
import { Subject } from 'rxjs';
2
import { isEqual } from 'lodash-es';
3
import { AfterContentInit, ChangeDetectorRef, ChangeDetectionStrategy, Component, ContentChild, ContentChildren, Input, QueryList, TemplateRef, Output, EventEmitter, OnDestroy, booleanAttribute, inject } from '@angular/core';
4
import { notifyChanges } from '../watch-changes';
5
import { WatchColumnChanges } from '../watch-changes';
6
import { IgxRowDirective } from '../row.directive';
7
import { CellType, GridType, IgxCellTemplateContext, IgxColumnTemplateContext, IgxSummaryTemplateContext, IGX_GRID_BASE } from '../common/grid.interface';
8
import { IgxGridHeaderComponent } from '../headers/grid-header.component';
9
import { IgxGridFilteringCellComponent } from '../filtering/base/grid-filtering-cell.component';
10
import { IgxGridHeaderGroupComponent } from '../headers/grid-header-group.component';
11
import {
12
    IgxSummaryOperand, IgxNumberSummaryOperand, IgxDateSummaryOperand, IgxTimeSummaryOperand
13
} from '../summaries/grid-summary';
14
import {
15
    IgxCellTemplateDirective,
16
    IgxCellHeaderTemplateDirective,
17
    IgxCellEditorTemplateDirective,
18
    IgxCollapsibleIndicatorTemplateDirective,
19
    IgxFilterCellTemplateDirective,
20
    IgxSummaryTemplateDirective,
21
    IgxCellValidationErrorDirective
22
} from './templates.directive';
23
import { DropPosition } from '../moving/moving.service';
24
import { IColumnVisibilityChangingEventArgs, IPinColumnCancellableEventArgs, IPinColumnEventArgs } from '../common/events';
25
import { IgxGridCell } from '../grid-public-cell';
26
import { NG_VALIDATORS, Validator } from '@angular/forms';
27
import { ColumnPinningPosition, ColumnType, DefaultSortingStrategy, ExpressionsTreeUtil, FilteringExpressionsTree, GridColumnDataType, IColumnEditorOptions, IColumnPipeArgs, IgxBooleanFilteringOperand, IgxDateFilteringOperand, IgxDateTimeFilteringOperand, IgxFilteringOperand, IgxNumberFilteringOperand, IgxStringFilteringOperand, IgxSummaryResult, IgxTimeFilteringOperand, isConstructor, ISortingStrategy, MRLColumnSizeInfo, MRLResizeColumnInfo, PlatformUtil, ɵSize } from 'igniteui-angular/core';
28
import type { IgxColumnLayoutComponent } from './column-layout.component';
29

30
const DEFAULT_DATE_FORMAT = 'mediumDate';
3✔
31
const DEFAULT_TIME_FORMAT = 'mediumTime';
3✔
32
const DEFAULT_DATE_TIME_FORMAT = 'medium';
3✔
33
const DEFAULT_DIGITS_INFO = '1.0-3';
3✔
34

35
/* blazorElement */
36
/* contentParent: ColumnGroup */
37
/* wcElementTag: igc-column */
38
/* additionalIdentifier: Field */
39
/* blazorIndirectRender */
40
/**
41
 * **Ignite UI for Angular Column** -
42
 * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid#columns-configuration)
43
 *
44
 * The Ignite UI Column is used within an `igx-grid` element to define what data the column will show. Features such as sorting,
45
 * filtering & editing are enabled at the column level.  You can also provide a template containing custom content inside
46
 * the column using `ng-template` which will be used for all cells within the column.
47
 *
48
 * @igxParent IgxGridComponent, IgxTreeGridComponent, IgxHierarchicalGridComponent, IgxPivotGridComponent, IgxRowIslandComponent, IgxColumnGroupComponent, IgxColumnLayoutComponent
49
 */
50
@Component({
51
    changeDetection: ChangeDetectionStrategy.OnPush,
52
    selector: 'igx-column',
53
    template: ``,
54
    styles: `:host { display: none }`,
55
    standalone: true
56
})
57
export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnType {
3✔
58
    /* blazorSuppress */
59
    public grid = inject<GridType>(IGX_GRID_BASE);
31,581✔
60
    private _validators = inject<Validator[]>(NG_VALIDATORS, { optional: true, self: true });
31,581✔
61

62
    /** @hidden @internal **/
63
    public cdr = inject(ChangeDetectorRef);
31,581✔
64
    protected platform = inject(PlatformUtil);
31,581✔
65

66
    /**
67
     * Sets/gets the `field` value.
68
     * ```typescript
69
     * let columnField = this.column.field;
70
     * ```
71
     * ```html
72
     * <igx-column [field] = "'ID'"></igx-column>
73
     * ```
74
     *
75
     * @memberof IgxColumnComponent
76
     */
77
    @Input()
78
    public set field(value: string) {
79
        this._field = value;
30,491✔
80
        this.hasNestedPath = value?.includes('.');
30,491✔
81
    }
82
    public get field(): string {
83
        return this._field;
21,583,299✔
84
    }
85

86
    /**
87
     * Sets/gets whether to merge cells in this column.
88
     * ```html
89
     * <igx-column [merge]="true"></igx-column>
90
     * ```
91
     *
92
     */
93
    @Input()
94
    public get merge() {
95
        return this._merge;
11,292,848✔
96
    }
97

98
    public set merge(value) {
99
        if (this.grid.hasColumnLayouts) {
1,744✔
100
            console.warn('Merging is not supported with multi-row layouts.');
1✔
101
            return;
1✔
102
        }
103
        if (value !== this._merge) {
1,743✔
104
            this._merge = value;
55✔
105
            if (this.grid) {
55✔
106
                this.grid.resetColumnCollections();
55✔
107
                this.grid.notifyChanges();
55✔
108
            }
109
        }
110
    }
111

112
    /**
113
     * @hidden @internal
114
     */
115
    public validators: Validator[] = this._validators;
31,581✔
116

117
    /**
118
     * Sets/gets the `header` value.
119
     * ```typescript
120
     * let columnHeader = this.column.header;
121
     * ```
122
     * ```html
123
     * <igx-column [header] = "'ID'"></igx-column>
124
     * ```
125
     *
126
     * @memberof IgxColumnComponent
127
     */
128
    @notifyChanges()
129
    @WatchColumnChanges()
130
    @Input()
131
    public header = '';
31,581✔
132
    /**
133
     * Sets/gets the `title` value.
134
     * ```typescript
135
     * let title = this.column.title;
136
     * ```
137
     * ```html
138
     * <igx-column [title] = "'Some column tooltip'"></igx-column>
139
     * ```
140
     *
141
     * @memberof IgxColumnComponent
142
     */
143
    @notifyChanges()
144
    @WatchColumnChanges()
145
    @Input()
146
    public title = '';
31,581✔
147
    /**
148
     * Sets/gets whether the column is sortable.
149
     * Default value is `false`.
150
     * ```typescript
151
     * let isSortable = this.column.sortable;
152
     * ```
153
     * ```html
154
     * <igx-column [sortable] = "true"></igx-column>
155
     * ```
156
     *
157
     * @memberof IgxColumnComponent
158
     */
159
    @WatchColumnChanges()
160
    @Input({ transform: booleanAttribute })
161
    public sortable = false;
31,581✔
162
    /**
163
     * Returns if the column is selectable.
164
     * ```typescript
165
     * let columnSelectable = this.column.selectable;
166
     * ```
167
     *
168
     * @memberof IgxColumnComponent
169
     */
170
    @WatchColumnChanges()
171
    @Input()
172
    public get selectable(): boolean {
173
        return this._selectable;
142,865✔
174
    }
175

176
    /**
177
     * Sets if the column is selectable.
178
     * Default value is `true`.
179
     * ```html
180
     * <igx-column [selectable] = "false"></igx-column>
181
     * ```
182
     *
183
     * @memberof IgxColumnComponent
184
     */
185
    public set selectable(value: boolean) {
186
        this._selectable = value;
1,702✔
187
    }
188

189
    /**
190
     * Sets/gets whether the column is groupable.
191
     * Default value is `false`.
192
     * ```typescript
193
     * let isGroupable = this.column.groupable;
194
     * ```
195
     * ```html
196
     * <igx-column [groupable] = "true"></igx-column>
197
     * ```
198
     *
199
     * @memberof IgxColumnComponent
200
     */
201
    @notifyChanges(true)
202
    @WatchColumnChanges()
203
    @Input({ transform: booleanAttribute })
204
    public get groupable(): boolean {
205
        return this._groupable;
175,966✔
206
    }
207
    public set groupable(value: boolean) {
208
        this._groupable = value;
3,693✔
209
        this.grid.groupablePipeTrigger++;
3,693✔
210
    }
211
    /**
212
     * Gets whether the column is editable.
213
     * Default value is `false`.
214
     * ```typescript
215
     * let isEditable = this.column.editable;
216
     * ```
217
     *
218
     * @memberof IgxColumnComponent
219
     */
220
    @WatchColumnChanges()
221
    @Input({ transform: booleanAttribute })
222
    public get editable(): boolean {
223
        // Updating the primary key when grid has transactions (incl. row edit)
224
        // should not be allowed, as that can corrupt transaction state.
225
        const rowEditable = this.grid && this.grid.rowEditable;
2,536,869✔
226
        const hasTransactions = this.grid && this.grid.transactions.enabled;
2,536,869✔
227

228
        if (this.isPrimaryColumn && (rowEditable || hasTransactions)) {
2,536,869✔
229
            return false;
102,949✔
230
        }
231

232
        if (this._editable !== undefined) {
2,433,920✔
233
            return this._editable;
408,270✔
234
        } else {
235
            return rowEditable;
2,025,650✔
236
        }
237
    }
238
    /**
239
     * Sets whether the column is editable.
240
     * ```typescript
241
     * this.column.editable = true;
242
     * ```
243
     * ```html
244
     * <igx-column [editable] = "true"></igx-column>
245
     * ```
246
     *
247
     * @memberof IgxColumnComponent
248
     */
249
    public set editable(editable: boolean) {
250
        this._editable = editable;
4,659✔
251
    }
252
    /**
253
     * Sets/gets whether the column is filterable.
254
     * Default value is `true`.
255
     * ```typescript
256
     * let isFilterable = this.column.filterable;
257
     * ```
258
     * ```html
259
     * <igx-column [filterable] = "false"></igx-column>
260
     * ```
261
     *
262
     * @memberof IgxColumnComponent
263
     */
264
    @notifyChanges()
265
    @WatchColumnChanges()
266
    @Input({ transform: booleanAttribute })
267
    public filterable = true;
31,581✔
268
    /**
269
     * Sets/gets whether the column is resizable.
270
     * Default value is `false`.
271
     * ```typescript
272
     * let isResizable = this.column.resizable;
273
     * ```
274
     * ```html
275
     * <igx-column [resizable] = "true"></igx-column>
276
     * ```
277
     *
278
     * @memberof IgxColumnComponent
279
     */
280
    @WatchColumnChanges()
281
    @Input({ transform: booleanAttribute })
282
    public resizable = false;
31,581✔
283

284
    /**
285
     * Sets/gets whether the column header is included in autosize logic.
286
     * Useful when template for a column header is sized based on parent, for example a default `div`.
287
     * Default value is `false`.
288
     * ```typescript
289
     * let isResizable = this.column.resizable;
290
     * ```
291
     * ```html
292
     * <igx-column [resizable] = "true"></igx-column>
293
     * ```
294
     *
295
     * @memberof IgxColumnComponent
296
     */
297
    @WatchColumnChanges()
298
    @Input({ transform: booleanAttribute })
299
    public autosizeHeader = true;
31,581✔
300

301
    /**
302
     * Gets a value indicating whether the summary for the column is enabled.
303
     * ```typescript
304
     * let hasSummary = this.column.hasSummary;
305
     * ```
306
     *
307
     * @memberof IgxColumnComponent
308
     */
309
    @notifyChanges(true)
310
    @WatchColumnChanges()
311
    @Input({ transform: booleanAttribute })
312
    public get hasSummary() {
313
        return this._hasSummary;
2,432,118✔
314
    }
315
    /**
316
     * Sets a value indicating whether the summary for the column is enabled.
317
     * Default value is `false`.
318
     * ```html
319
     * <igx-column [hasSummary] = "true"></igx-column>
320
     * ```
321
     *
322
     * @memberof IgxColumnComponent
323
     */
324
    public set hasSummary(value) {
325
        this._hasSummary = value;
3,467✔
326

327
        if (this.grid) {
3,467✔
328
            this.grid.summaryService.resetSummaryHeight();
3,467✔
329
        }
330
    }
331
    /**
332
     * Gets whether the column is hidden.
333
     * ```typescript
334
     * let isHidden = this.column.hidden;
335
     * ```
336
     *
337
     * @memberof IgxColumnComponent
338
     */
339
    @notifyChanges(true)
340
    @WatchColumnChanges()
341
    @Input({ transform: booleanAttribute })
342
    public get hidden(): boolean {
343
        return this._hidden;
2,356,715✔
344
    }
345
    /**
346
     * Sets the column hidden property.
347
     * Default value is `false`.
348
     * ```html
349
     * <igx-column [hidden] = "true"></igx-column>
350
     * ```
351
     *
352
     * Two-way data binding.
353
     * ```html
354
     * <igx-column [(hidden)] = "model.isHidden"></igx-column>
355
     * ```
356
     *
357
     * @memberof IgxColumnComponent
358
     */
359
    public set hidden(value: boolean) {
360
        if (this._hidden !== value) {
6,219✔
361
            this._hidden = value;
1,135✔
362
            this.hiddenChange.emit(this._hidden);
1,135✔
363
            if (this.columnLayoutChild && this.parent.hidden !== value) {
1,135✔
364
                this.parent.hidden = value;
5✔
365
                return;
5✔
366
            }
367
            if (this.grid) {
1,130✔
368
                this.grid.crudService.endEdit(false);
1,130✔
369
                this.grid.summaryService.resetSummaryHeight();
1,130✔
370
                this.grid.filteringService.refreshExpressions();
1,130✔
371
                this.grid.filteringService.hideFilteringRowOnColumnVisibilityChange(this);
1,130✔
372
                this.grid.notifyChanges();
1,130✔
373
            }
374
        }
375
    }
376

377
    /**
378
     * Returns if the column is selected.
379
     * ```typescript
380
     * let isSelected = this.column.selected;
381
     * ```
382
     *
383
     * @memberof IgxColumnComponent
384
     */
385
    public get selected(): boolean {
386
        return this.grid.selectionService.isColumnSelected(this.field);
1,789,731✔
387
    }
388

389
    /**
390
     * Select/deselect a column.
391
     * Default value is `false`.
392
     * ```typescript
393
     * this.column.selected = true;
394
     * ```
395
     *
396
     * @memberof IgxColumnComponent
397
     */
398
    public set selected(value: boolean) {
399
        if (this.selectable && value !== this.selected) {
48✔
400
            if (value) {
44✔
401
                this.grid.selectionService.selectColumnsWithNoEvent([this.field]);
39✔
402
            } else {
403
                this.grid.selectionService.deselectColumnsWithNoEvent([this.field]);
5✔
404
            }
405
            this.grid.notifyChanges();
44✔
406
        }
407
    }
408

409
    /**
410
     * Emitted when the column is hidden or shown.
411
     *
412
     * ```html
413
     * <igx-column (hiddenChange)="hiddenChange($event)">
414
     * </igx-column>
415
     * ```
416
     *
417
     */
418
    @Output()
419
    public hiddenChange = new EventEmitter<boolean>();
31,581✔
420

421
    /**
422
     * Emitted when the column expanded or collapsed.
423
     *
424
     * ```html
425
     * <igx-column (expandedChange)="expandedChange($event)">
426
     * </igx-column>
427
     * ```
428
     *
429
     */
430
    @Output()
431
    public expandedChange = new EventEmitter<boolean>();
31,581✔
432

433
    /** @hidden */
434
    @Output()
435
    public collapsibleChange = new EventEmitter<boolean>();
31,581✔
436

437
    /** @hidden */
438
    @Output()
439
    public visibleWhenCollapsedChange = new EventEmitter<boolean>();
31,581✔
440

441
    /** @hidden @internal */
442
    @Output()
443
    public columnChange = new EventEmitter<void>();
31,581✔
444

445
    /**
446
     * Gets whether the hiding is disabled.
447
     * ```typescript
448
     * let isHidingDisabled =  this.column.disableHiding;
449
     * ```
450
     *
451
     * @memberof IgxColumnComponent
452
     */
453
    @notifyChanges()
454
    @WatchColumnChanges()
455
    @Input({ transform: booleanAttribute })
456
    public disableHiding = false;
31,581✔
457
    /**
458
     * Gets whether the pinning is disabled.
459
     * ```typescript
460
     * let isPinningDisabled =  this.column.disablePinning;
461
     * ```
462
     *
463
     * @memberof IgxColumnComponent
464
     */
465
    @notifyChanges()
466
    @WatchColumnChanges()
467
    @Input({ transform: booleanAttribute })
468
    public disablePinning = false;
31,581✔
469

470
    /**
471
     * Gets the `width` of the column.
472
     * ```typescript
473
     * let columnWidth = this.column.width;
474
     * ```
475
     *
476
     * @memberof IgxColumnComponent
477
     */
478
    @notifyChanges(true)
479
    @WatchColumnChanges()
480
    @Input()
481
    public get width(): string {
482
        const isAutoWidth = this._width && typeof this._width === 'string' && this._width === 'auto';
2,422,095✔
483
        if (isAutoWidth) {
2,422,095✔
484
            if (!this.autoSize) {
23,756✔
485
                return 'fit-content';
13,105✔
486
            } else {
487
                return this.autoSize + 'px';
10,651✔
488
            }
489

490
        }
491
        return this.widthSetByUser ? this._width : this.defaultWidth;
2,398,339✔
492
    }
493

494
    /**
495
     * Sets the `width` of the column.
496
     * ```html
497
     * <igx-column [width] = "'25%'"></igx-column>
498
     * ```
499
     *
500
     * Two-way data binding.
501
     * ```html
502
     * <igx-column [(width)]="model.columns[0].width"></igx-column>
503
     * ```
504
     *
505
     * @memberof IgxColumnComponent
506
     */
507
    public set width(value: string) {
508
        if (value) {
17,218✔
509
            this._calcWidth = null;
14,482✔
510
            this.calcPixelWidth = NaN;
14,482✔
511
            this.widthSetByUser = true;
14,482✔
512
            // width could be passed as number from the template
513
            // host bindings are not px affixed so we need to ensure we affix simple number strings
514
            if (typeof (value) === 'number' || value.match(/^[0-9]*$/)) {
14,482✔
515
                value = value + 'px';
883✔
516
            }
517
            if (value === 'fit-content') {
14,482✔
518
                value = 'auto';
1✔
519
            }
520
            this._width = value;
14,482✔
521
            if (this.grid) {
14,482✔
522
                this.cacheCalcWidth();
14,482✔
523
            }
524
            this.widthChange.emit(this._width);
14,482✔
525
        }
526
    }
527

528
    /** @hidden @internal **/
529
    public autoSize: number;
530

531
    /**
532
     * Sets/gets the maximum `width` of the column.
533
     * ```typescript
534
     * let columnMaxWidth = this.column.width;
535
     * ```
536
     * ```html
537
     * <igx-column [maxWidth] = "'150px'"></igx-column>
538
     * ```
539
     *
540
     * @memberof IgxColumnComponent
541
     */
542
    @WatchColumnChanges()
543
    @Input()
544
    public set maxWidth(value: string) {
545
        this._maxWidth = value;
1,995✔
546

547
        this.grid.notifyChanges(true);
1,995✔
548
    }
549
    public get maxWidth(): string {
550
        return this._maxWidth;
473,453✔
551
    }
552
    /**
553
     * Sets/gets the class selector of the column header.
554
     * ```typescript
555
     * let columnHeaderClass = this.column.headerClasses;
556
     * ```
557
     * ```html
558
     * <igx-column [headerClasses] = "'column-header'"></igx-column>
559
     * ```
560
     *
561
     * @memberof IgxColumnComponent
562
     */
563
    @notifyChanges()
564
    @WatchColumnChanges()
565
    @Input()
566
    public headerClasses = '';
31,581✔
567

568
    /**
569
     * Sets conditional style properties on the column header.
570
     * Similar to `ngStyle` it accepts an object literal where the keys are
571
     * the style properties and the value is the expression to be evaluated.
572
     * ```typescript
573
     * styles = {
574
     *  background: 'royalblue',
575
     *  color: (column) => column.pinned ? 'red': 'inherit'
576
     * }
577
     * ```
578
     * ```html
579
     * <igx-column [headerStyles]="styles"></igx-column>
580
     * ```
581
     *
582
     * @memberof IgxColumnComponent
583
     */
584
    @notifyChanges()
585
    @WatchColumnChanges()
586
    @Input()
587
    public headerStyles = null;
31,581✔
588

589
    /**
590
     * Sets/gets the class selector of the column group header.
591
     * ```typescript
592
     * let columnHeaderClass = this.column.headerGroupClasses;
593
     * ```
594
     * ```html
595
     * <igx-column [headerGroupClasses] = "'column-group-header'"></igx-column>
596
     * ```
597
     *
598
     * @memberof IgxColumnComponent
599
     */
600
    @notifyChanges()
601
    @WatchColumnChanges()
602
    @Input()
603
    public headerGroupClasses = '';
31,581✔
604

605
    /**
606
     * Sets conditional style properties on the column header group wrapper.
607
     * Similar to `ngStyle` it accepts an object literal where the keys are
608
     * the style properties and the value is the expression to be evaluated.
609
     * ```typescript
610
     * styles = {
611
     *  background: 'royalblue',
612
     *  color: (column) => column.pinned ? 'red': 'inherit'
613
     * }
614
     * ```
615
     * ```html
616
     * <igx-column [headerGroupStyles]="styles"></igx-column>
617
     * ```
618
     *
619
     * @memberof IgxColumnComponent
620
     */
621
    @notifyChanges()
622
    @WatchColumnChanges()
623
    @Input()
624
    public headerGroupStyles = null;
31,581✔
625

626
    /* treatAsRef */
627
    /**
628
     * Sets a conditional class selector of the column cells.
629
     * Accepts an object literal, containing key-value pairs,
630
     * where the key is the name of the CSS class, while the
631
     * value is either a callback function that returns a boolean,
632
     * or boolean, like so:
633
     * ```typescript
634
     * callback = (rowData, columnKey, cellValue, rowIndex) => { return rowData[columnKey] > 6; }
635
     * cellClasses = { 'className' : this.callback };
636
     * ```
637
     * ```html
638
     * <igx-column [cellClasses] = "cellClasses"></igx-column>
639
     * <igx-column [cellClasses] = "{'class1' : true }"></igx-column>
640
     * ```
641
     *
642
     * @memberof IgxColumnComponent
643
     */
644
    @notifyChanges()
645
    @WatchColumnChanges()
646
    @Input()
647
    public cellClasses: any;
648

649
    /* treatAsRef */
650
    /**
651
     * Sets conditional style properties on the column cells.
652
     * Similar to `ngStyle` it accepts an object literal where the keys are
653
     * the style properties and the value is the expression to be evaluated.
654
     * As with `cellClasses` it accepts a callback function.
655
     * ```typescript
656
     * styles = {
657
     *  background: 'royalblue',
658
     *  color: (rowData, columnKey, cellValue, rowIndex) => value.startsWith('Important') ? 'red': 'inherit'
659
     * }
660
     * ```
661
     * ```html
662
     * <igx-column [cellStyles]="styles"></igx-column>
663
     * ```
664
     *
665
     * @memberof IgxColumnComponent
666
     */
667
    @notifyChanges()
668
    @WatchColumnChanges()
669
    @Input()
670
    public cellStyles = null;
31,581✔
671

672
    /* blazorAlternateType: CellValueFormatterEventHandler */
673
    /* blazorOnlyScript */
674
    /**
675
     * Applies display format to cell values in the column. Does not modify the underlying data.
676
     *
677
     * @remarks
678
     * Note: As the formatter is used in places like the Excel style filtering dialog, in certain
679
     * scenarios (remote filtering for example), the row data argument can be `undefined`.
680
     *
681
     *
682
     * In this example, we check to see if the column name is Salary, and then provide a method as the column formatter
683
     * to format the value into a currency string.
684
     *
685
     * @example
686
     * ```typescript
687
     * columnInit(column: IgxColumnComponent) {
688
     *   if (column.field == "Salary") {
689
     *     column.formatter = (salary => this.format(salary));
690
     *   }
691
     * }
692
     *
693
     * format(value: number) : string {
694
     *   return formatCurrency(value, "en-us", "$");
695
     * }
696
     * ```
697
     *
698
     * @example
699
     * ```typescript
700
     * const column = this.grid.getColumnByName('Address');
701
     * const addressFormatter = (address: string, rowData: any) => data.privacyEnabled ? 'unknown' : address;
702
     * column.formatter = addressFormatter;
703
     * ```
704
     *
705
     * @memberof IgxColumnComponent
706
     */
707
    @notifyChanges()
708
    @WatchColumnChanges()
709
    @Input()
710
    public formatter: (value: any, rowData?: any) => any;
711

712
    /* blazorAlternateType: SummaryValueFormatterEventHandler */
713
    /* blazorOnlyScript */
714
    /* forceCastDelegate */
715
    /**
716
     * The summaryFormatter is used to format the display of the column summaries.
717
     *
718
     * In this example, we check to see if the column name is OrderDate, and then provide a method as the summaryFormatter
719
     * to change the locale for the dates to 'fr-FR'. The summaries with the count key are skipped so they are displayed as numbers.
720
     *
721
     * ```typescript
722
     * columnInit(column: IgxColumnComponent) {
723
     *   if (column.field == "OrderDate") {
724
     *     column.summaryFormatter = this.summaryFormat;
725
     *   }
726
     * }
727
     *
728
     * summaryFormat(summary: IgxSummaryResult, summaryOperand: IgxSummaryOperand): string {
729
     *   const result = summary.summaryResult;
730
     *   if(summaryResult.key !== 'count' && result !== null && result !== undefined) {
731
     *      const pipe = new DatePipe('fr-FR');
732
     *      return pipe.transform(result,'mediumDate');
733
     *   }
734
     *   return result;
735
     * }
736
     * ```
737
     *
738
     * @memberof IgxColumnComponent
739
     */
740
    @notifyChanges()
741
    @WatchColumnChanges()
742
    @Input()
743
    public summaryFormatter: (summary: IgxSummaryResult, summaryOperand: IgxSummaryOperand) => any;
744

745
    /**
746
     * Sets/gets whether the column filtering should be case sensitive.
747
     * Default value is `true`.
748
     * ```typescript
749
     * let filteringIgnoreCase = this.column.filteringIgnoreCase;
750
     * ```
751
     * ```html
752
     * <igx-column [filteringIgnoreCase] = "false"></igx-column>
753
     * ```
754
     *
755
     * @memberof IgxColumnComponent
756
     */
757
    @WatchColumnChanges()
758
    @Input({ transform: booleanAttribute })
759
    public filteringIgnoreCase = true;
31,581✔
760
    /**
761
     * Sets/gets whether the column sorting should be case sensitive.
762
     * Default value is `true`.
763
     * ```typescript
764
     * let sortingIgnoreCase = this.column.sortingIgnoreCase;
765
     * ```
766
     * ```html
767
     * <igx-column [sortingIgnoreCase] = "false"></igx-column>
768
     * ```
769
     *
770
     * @memberof IgxColumnComponent
771
     */
772
    @WatchColumnChanges()
773
    @Input({ transform: booleanAttribute })
774
    public sortingIgnoreCase = true;
31,581✔
775
    /**
776
     * Sets/gets whether the column is `searchable`.
777
     * Default value is `true`.
778
     * ```typescript
779
     * let isSearchable =  this.column.searchable';
780
     * ```
781
     * ```html
782
     *  <igx-column [searchable] = "false"></igx-column>
783
     * ```
784
     *
785
     * @memberof IgxColumnComponent
786
     */
787
    @notifyChanges()
788
    @WatchColumnChanges()
789
    @Input({ transform: booleanAttribute })
790
    public searchable = true;
31,581✔
791
    /**
792
     * Sets/gets the data type of the column values.
793
     * Default value is `string`.
794
     * ```typescript
795
     * let columnDataType = this.column.dataType;
796
     * ```
797
     * ```html
798
     * <igx-column [dataType] = "'number'"></igx-column>
799
     * ```
800
     *
801
     * @memberof IgxColumnComponent
802
     */
803
    @Input()
804
    public dataType: GridColumnDataType = GridColumnDataType.String;
31,581✔
805

806
    /** @hidden */
807
    @Input()
808
    public collapsibleIndicatorTemplate: TemplateRef<IgxColumnTemplateContext>;
809

810
    /**
811
     * Row index where the current field should end.
812
     * The amount of rows between rowStart and rowEnd will determine the amount of spanning rows to that field
813
     * ```html
814
     * <igx-column-layout>
815
     *   <igx-column [rowEnd]="2" [rowStart]="1" [colStart]="1"></igx-column>
816
     * </igx-column-layout>
817
     * ```
818
     *
819
     * @memberof IgxColumnComponent
820
     */
821
    @Input()
822
    public rowEnd: number;
823

824
    /**
825
     * Column index where the current field should end.
826
     * The amount of columns between colStart and colEnd will determine the amount of spanning columns to that field
827
     * ```html
828
     * <igx-column-layout>
829
     *   <igx-column [colEnd]="3" [rowStart]="1" [colStart]="1"></igx-column>
830
     * </igx-column-layout>
831
     * ```
832
     *
833
     * @memberof IgxColumnComponent
834
     */
835
    @Input()
836
    public colEnd: number;
837

838
    /**
839
     * Row index from which the field is starting.
840
     * ```html
841
     * <igx-column-layout>
842
     *   <igx-column [rowStart]="1" [colStart]="1"></igx-column>
843
     * </igx-column-layout>
844
     * ```
845
     *
846
     * @memberof IgxColumnComponent
847
     */
848
    @Input()
849
    public rowStart: number;
850

851
    /**
852
     * Column index from which the field is starting.
853
     * ```html
854
     * <igx-column-layout>
855
     *   <igx-column [colStart]="1" [rowStart]="1"></igx-column>
856
     * </igx-column-layout>
857
     * ```
858
     *
859
     * @memberof IgxColumnComponent
860
     */
861
    @Input()
862
    public colStart: number;
863

864
    /**
865
     * Sets/gets custom properties provided in additional template context.
866
     *
867
     * ```html
868
     * <igx-column [additionalTemplateContext]="contextObject">
869
     *   <ng-template igxCell let-cell="cell" let-props="additionalTemplateContext">
870
     *      {{ props }}
871
     *   </ng-template>
872
     * </igx-column>
873
     * ```
874
     *
875
     * @memberof IgxColumnComponent
876
     */
877
    @Input()
878
    public additionalTemplateContext: any;
879

880
    /**
881
     * Emitted when the column width changes.
882
     *
883
     * ```html
884
     * <igx-column (widthChange)="widthChange($event)">
885
     * </igx-column>
886
     * ```
887
     *
888
     */
889
    @Output()
890
    public widthChange = new EventEmitter<string>();
31,581✔
891

892
    /**
893
     * Emitted when the column is pinned/unpinned.
894
     *
895
     * ```html
896
     * <igx-column (pinnedChange)="pinnedChange($event)">
897
     * </igx-column>
898
     * ```
899
     *
900
     */
901
    @Output()
902
    public pinnedChange = new EventEmitter<boolean>();
31,581✔
903
    /**
904
     * @hidden
905
     */
906
    @ContentChild(IgxFilterCellTemplateDirective, { read: IgxFilterCellTemplateDirective })
907
    public filterCellTemplateDirective: IgxFilterCellTemplateDirective;
908
    /**
909
     * @hidden
910
     */
911
    @ContentChild(IgxSummaryTemplateDirective, { read: IgxSummaryTemplateDirective })
912
    protected summaryTemplateDirective: IgxSummaryTemplateDirective;
913
    /**
914
     * @hidden
915
     * @see {@link bodyTemplate}
916
     */
917
    @ContentChild(IgxCellTemplateDirective, { read: IgxCellTemplateDirective })
918
    protected cellTemplate: IgxCellTemplateDirective;
919
    /**
920
     * @hidden
921
     */
922
    @ContentChild(IgxCellValidationErrorDirective, { read: IgxCellValidationErrorDirective })
923
    protected cellValidationErrorTemplate: IgxCellValidationErrorDirective;
924
    /**
925
     * @hidden
926
     */
927
    @ContentChildren(IgxCellHeaderTemplateDirective, { read: IgxCellHeaderTemplateDirective, descendants: false })
928
    protected headTemplate: QueryList<IgxCellHeaderTemplateDirective>;
929
    /**
930
     * @hidden
931
     */
932
    @ContentChild(IgxCellEditorTemplateDirective, { read: IgxCellEditorTemplateDirective })
933
    protected editorTemplate: IgxCellEditorTemplateDirective;
934
    /**
935
     * @hidden
936
     */
937
    @ContentChild(IgxCollapsibleIndicatorTemplateDirective, { read: IgxCollapsibleIndicatorTemplateDirective, static: false })
938
    protected collapseIndicatorTemplate: IgxCollapsibleIndicatorTemplateDirective;
939
    /**
940
     * @hidden
941
     */
942
    public get calcWidth(): any {
943
        return this.getCalcWidth();
316,800✔
944
    }
945

946
    /** @hidden @internal **/
947
    public calcPixelWidth: number;
948

949
    /**
950
     * @hidden
951
     */
952
    public get maxWidthPx() {
953
        const gridAvailableSize = this.grid.calcWidth;
11,289✔
954
        const isPercentageWidth = this.maxWidth && typeof this.maxWidth === 'string' && this.maxWidth.indexOf('%') !== -1;
11,289✔
955
        return isPercentageWidth ? parseFloat(this.maxWidth) / 100 * gridAvailableSize : parseFloat(this.maxWidth);
11,289✔
956
    }
957

958
    /**
959
     * @hidden
960
     */
961
    public get maxWidthPercent() {
962
        const gridAvailableSize = this.grid.calcWidth;
7✔
963
        const isPercentageWidth = this.maxWidth && typeof this.maxWidth === 'string' && this.maxWidth.indexOf('%') !== -1;
7✔
964
        return isPercentageWidth ? parseFloat(this.maxWidth) : parseFloat(this.maxWidth) / gridAvailableSize * 100;
7✔
965
    }
966

967
    /**
968
     * @hidden
969
     */
970
    public get minWidthPx() {
971
        const gridAvailableSize = this.grid.calcWidth;
183✔
972
        const minWidth = this.minWidth || this.defaultMinWidth;
183✔
973
        const isPercentageWidth = minWidth && typeof minWidth === 'string' && minWidth.indexOf('%') !== -1;
183✔
974
        return isPercentageWidth ? parseFloat(minWidth) / 100 * gridAvailableSize : parseFloat(minWidth);
183✔
975
    }
976

977
    /**
978
     * @hidden
979
     */
980
    public get userSetMinWidthPx() {
981
        const gridAvailableSize = this.grid.calcWidth;
223,488✔
982
        const isPercentageWidth = this._defaultMinWidth && typeof this._defaultMinWidth === 'string' && this._defaultMinWidth.indexOf('%') !== -1;
223,488✔
983
        return isPercentageWidth ? parseFloat(this._defaultMinWidth) / 100 * gridAvailableSize : parseFloat(this._defaultMinWidth);
223,488✔
984
    }
985

986
    /**
987
     * @hidden
988
     */
989
    public get minWidthPercent() {
990
        const gridAvailableSize = this.grid.calcWidth;
7✔
991
        const minWidth = this.minWidth || this.defaultMinWidth;
7✔
992
        const isPercentageWidth = minWidth && typeof minWidth === 'string' && minWidth.indexOf('%') !== -1;
7✔
993
        return isPercentageWidth ? parseFloat(minWidth) : parseFloat(minWidth) / gridAvailableSize * 100;
7✔
994
    }
995

996

997
    /**
998
     * Sets/gets the minimum `width` of the column.
999
     * Default value is `88`;
1000
     * ```typescript
1001
     * let columnMinWidth = this.column.minWidth;
1002
     * ```
1003
     * ```html
1004
     * <igx-column [minWidth] = "'100px'"></igx-column>
1005
     * ```
1006
     *
1007
     * @memberof IgxColumnComponent
1008
     */
1009
    @notifyChanges()
1010
    @WatchColumnChanges()
1011
    @Input()
1012
    public set minWidth(value: string) {
1013
        const minVal = parseFloat(value);
1,621✔
1014
        if (Number.isNaN(minVal)) {
1,621✔
1015
            return;
1,583✔
1016
        }
1017
        this._defaultMinWidth = value;
38✔
1018
        this.grid.notifyChanges(true);
38✔
1019
    }
1020
    public get minWidth(): string {
1021
        return this._defaultMinWidth;
850,753✔
1022
    }
1023

1024
    /** @hidden @internal **/
1025
    public get resolvedWidth(): string {
1026
        if (this.columnLayoutChild) {
4,191,474✔
1027
            return '';
10,563✔
1028
        }
1029
        const isAutoWidth = this._width && typeof this._width === 'string' && this._width === 'auto';
4,180,911✔
1030
        return isAutoWidth ? this.width : this.calcPixelWidth + 'px';
4,180,911✔
1031
    }
1032

1033
    /**
1034
     * Gets the column index.
1035
     * ```typescript
1036
     * let columnIndex = this.column.index;
1037
     * ```
1038
     *
1039
     * @memberof IgxColumnComponent
1040
     */
1041
    public get index(): number {
1042
        return (this.grid as any)._columns.indexOf(this);
1,796,141✔
1043
    }
1044

1045
    /* mustCoerceToInt */
1046
    /**
1047
     * Gets the pinning position of the column.
1048
     * ```typescript
1049
     * let pinningPosition = this.column.pinningPosition;
1050
     */
1051
    @WatchColumnChanges()
1052
    @Input()
1053
    public get pinningPosition(): ColumnPinningPosition {
1054
        const userSet = this._pinningPosition !== null && this._pinningPosition !== undefined;
2,631,343✔
1055
        return userSet ? this._pinningPosition : this.grid.pinning.columns;
2,631,343✔
1056
    }
1057

1058
    /**
1059
     * Sets the pinning position of the column.
1060
     *```html
1061
     * <igx-column [pinningPosition]="1"></igx-column>
1062
     * ```
1063
     */
1064
    public set pinningPosition(value: ColumnPinningPosition) {
1065
        this._pinningPosition = value;
1,544✔
1066
    }
1067

1068
    /**
1069
     * Gets whether the column is `pinned`.
1070
     * ```typescript
1071
     * let isPinned = this.column.pinned;
1072
     * ```
1073
     *
1074
     * @memberof IgxColumnComponent
1075
     */
1076
    @WatchColumnChanges()
1077
    @Input({ transform: booleanAttribute })
1078
    public get pinned(): boolean {
1079
        return this._pinned;
2,184,861✔
1080
    }
1081
    /**
1082
     * Sets whether the column is pinned.
1083
     * Default value is `false`.
1084
     * ```html
1085
     * <igx-column [pinned] = "true"></igx-column>
1086
     * ```
1087
     *
1088
     * Two-way data binding.
1089
     * ```html
1090
     * <igx-column [(pinned)] = "model.columns[0].isPinned"></igx-column>
1091
     * ```
1092
     *
1093
     * @memberof IgxColumnComponent
1094
     */
1095
    public set pinned(value: boolean) {
1096
        if (this._pinned !== value) {
2,997✔
1097
            const isAutoWidth = this.width && typeof this.width === 'string' && this.width === 'fit-content';
577✔
1098
            if (this.grid && this.width && (isAutoWidth || !isNaN(parseInt(this.width, 10)))) {
577✔
1099
                if (value) {
393✔
1100
                    this.pin();
355✔
1101
                } else {
1102
                    this.unpin();
38✔
1103
                }
1104
                return;
393✔
1105
            }
1106
            /* No grid/width available at initialization. `initPinning` in the grid
1107
               will re-init the group (if present)
1108
            */
1109
            this._pinned = value;
184✔
1110
            this.pinnedChange.emit(this._pinned);
184✔
1111
        }
1112
    }
1113

1114
    /* treatAsRef */
1115
    /**
1116
     * Gets the column `summaries`.
1117
     * ```typescript
1118
     * let columnSummaries = this.column.summaries;
1119
     * ```
1120
     *
1121
     * @memberof IgxColumnComponent
1122
     */
1123
    @notifyChanges(true)
1124
    @WatchColumnChanges()
1125
    @Input()
1126
    public get summaries(): any {
1127
        return this._summaries;
69,161✔
1128
    }
1129

1130
    /* treatAsRef */
1131
    /**
1132
     * Sets the column `summaries`.
1133
     * ```typescript
1134
     * this.column.summaries = IgxNumberSummaryOperand;
1135
     * ```
1136
     *
1137
     * @memberof IgxColumnComponent
1138
     */
1139
    public set summaries(classRef: any) {
1140
        if (isConstructor(classRef)) {
25,995✔
1141
            this._summaries = new classRef();
25,989✔
1142
        }
1143

1144
        if (this.grid) {
25,995✔
1145
            this.grid.summaryService.removeSummariesCachePerColumn(this.field);
25,995✔
1146
            this.grid.summaryPipeTrigger++;
25,995✔
1147
            this.grid.summaryService.resetSummaryHeight();
25,995✔
1148
        }
1149
    }
1150

1151
    /**
1152
     * Sets/gets the summary operands to exclude from display.
1153
     * Accepts an array of string keys representing the summary types to disable, such as 'Min', 'Max', 'Count' etc.
1154
     * ```typescript
1155
     * let disabledSummaries = this.column.disabledSummaries;
1156
     * ```
1157
     * ```html
1158
     * <igx-column [disabledSummaries]="['min', 'max', 'average']"></igx-column>
1159
     * ```
1160
     *
1161
     * @memberof IgxColumnComponent
1162
     */
1163
    @WatchColumnChanges()
1164
    @Input()
1165
    public get disabledSummaries(): string[] {
1166
        return this._disabledSummaries;
19,032✔
1167
    }
1168

1169
    public set disabledSummaries(value: string[]) {
1170
        if (isEqual(this._disabledSummaries, value)) {
1,545✔
1171
            return;
1,538✔
1172
        }
1173
        this._disabledSummaries = value;
7✔
1174
        if (this.grid) {
7✔
1175
            this.grid.summaryService.removeSummariesCachePerColumn(this.field);
7✔
1176
            this.grid.summaryPipeTrigger++;
7✔
1177
            this.grid.summaryService.resetSummaryHeight();
7✔
1178
        }
1179
    }
1180

1181
    /**
1182
     * Gets the column `filters`.
1183
     * ```typescript
1184
     * let columnFilters = this.column.filters'
1185
     * ```
1186
     *
1187
     * @memberof IgxColumnComponent
1188
     */
1189
    @Input()
1190
    public get filters(): IgxFilteringOperand {
1191
        return this._filters;
76,459✔
1192
    }
1193
    /**
1194
     * Sets the column `filters`.
1195
     * ```typescript
1196
     * this.column.filters = IgxBooleanFilteringOperand.instance().
1197
     * ```
1198
     *
1199
     * @memberof IgxColumnComponent
1200
     */
1201
    public set filters(instance: IgxFilteringOperand) {
1202
        this._filters = instance;
25,981✔
1203
    }
1204
    /**
1205
     * Gets the column `sortStrategy`.
1206
     * ```typescript
1207
     * let sortStrategy = this.column.sortStrategy
1208
     * ```
1209
     *
1210
     * @memberof IgxColumnComponent
1211
     */
1212
    @Input()
1213
    public get sortStrategy(): ISortingStrategy {
1214
        return this._sortStrategy;
3,074✔
1215
    }
1216
    /**
1217
     * Sets the column `sortStrategy`.
1218
     * ```typescript
1219
     * this.column.sortStrategy = new CustomSortingStrategy().
1220
     * class CustomSortingStrategy extends SortingStrategy {...}
1221
     * ```
1222
     *
1223
     * @memberof IgxColumnComponent
1224
     */
1225
    public set sortStrategy(classRef: ISortingStrategy) {
1226
        this._sortStrategy = classRef;
1,541✔
1227
    }
1228

1229
    /* blazorSuppress */
1230
    /**
1231
     * Gets the function that compares values for merging.
1232
     * ```typescript
1233
     * let mergingComparer = this.column.mergingComparer'
1234
     * ```
1235
     */
1236
    @Input()
1237
    public get mergingComparer(): (prevRecord: any, record: any, field: string) => boolean {
1238
        return this._mergingComparer;
3,119✔
1239
    }
1240

1241
    /* blazorSuppress */
1242
    /**
1243
     * Sets a custom function to compare values for merging.
1244
     * ```typescript
1245
     * this.column.mergingComparer = (prevRecord: any, record: any, field: string) => { return prevRecord[field] === record[field]; }
1246
     * ```
1247
     */
1248
    public set mergingComparer(funcRef: (prevRecord: any, record: any, field: string) => boolean) {
1249
        this._mergingComparer = funcRef;
1,539✔
1250
    }
1251

1252

1253
    /* blazorSuppress */
1254
    /**
1255
     * Gets the function that compares values for grouping.
1256
     * ```typescript
1257
     * let groupingComparer = this.column.groupingComparer'
1258
     * ```
1259
     *
1260
     * @memberof IgxColumnComponent
1261
     */
1262
    @Input()
1263
    public get groupingComparer(): (a: any, b: any, currRec?: any, groupRec?: any) => number {
1264
        return this._groupingComparer;
16,171✔
1265
    }
1266

1267
    /* blazorSuppress */
1268
    /**
1269
     * Sets a custom function to compare values for grouping.
1270
     * Subsequent values in the sorted data that the function returns 0 for are grouped.
1271
     * ```typescript
1272
     * this.column.groupingComparer = (a: any, b: any, currRec?: any, groupRec?: any) => { return a === b ? 0 : -1; }
1273
     * ```
1274
     *
1275
     * @memberof IgxColumnComponent
1276
     */
1277
    public set groupingComparer(funcRef: (a: any, b: any, currRec?: any, groupRec?: any) => number) {
1278
        this._groupingComparer = funcRef;
1,541✔
1279
    }
1280
    /**
1281
     * @hidden @internal
1282
     */
1283
    public get defaultMinWidth(): string {
1284
        if (!this.grid) {
163!
UNCOV
1285
            return '80';
×
1286
        }
1287
        switch (this.grid.gridSize) {
163✔
1288
            case ɵSize.Medium:
1289
                return '64';
4✔
1290
            case ɵSize.Small:
1291
                return '56';
5✔
1292
            default:
1293
                return '80';
154✔
1294
        }
1295
    }
1296
    /**
1297
     * Returns a reference to the `summaryTemplate`.
1298
     * ```typescript
1299
     * let summaryTemplate = this.column.summaryTemplate;
1300
     * ```
1301
     *
1302
     * @memberof IgxColumnComponent
1303
     */
1304
    @notifyChanges()
1305
    @WatchColumnChanges()
1306
    @Input()
1307
    public get summaryTemplate(): TemplateRef<IgxSummaryTemplateContext> {
1308
        return this._summaryTemplate;
82,975✔
1309
    }
1310
    /**
1311
     * Sets the summary template.
1312
     * ```html
1313
     * <ng-template #summaryTemplate igxSummary let-summaryResults>
1314
     *    <p>{{ summaryResults[0].label }}: {{ summaryResults[0].summaryResult }}</p>
1315
     *    <p>{{ summaryResults[1].label }}: {{ summaryResults[1].summaryResult }}</p>
1316
     * </ng-template>
1317
     * ```
1318
     * ```typescript
1319
     * @ViewChild("'summaryTemplate'", {read: TemplateRef })
1320
     * public summaryTemplate: TemplateRef<any>;
1321
     * this.column.summaryTemplate = this.summaryTemplate;
1322
     * ```
1323
     *
1324
     * @memberof IgxColumnComponent
1325
     */
1326
    public set summaryTemplate(template: TemplateRef<IgxSummaryTemplateContext>) {
1327
        this._summaryTemplate = template;
1,544✔
1328
    }
1329

1330
    /**
1331
     * Returns a reference to the `bodyTemplate`.
1332
     * ```typescript
1333
     * let bodyTemplate = this.column.bodyTemplate;
1334
     * ```
1335
     *
1336
     * @memberof IgxColumnComponent
1337
     */
1338
    @notifyChanges()
1339
    @WatchColumnChanges()
1340
    @Input('cellTemplate')
1341
    public get bodyTemplate(): TemplateRef<IgxCellTemplateContext> {
1342
        return this._bodyTemplate;
1,267,900✔
1343
    }
1344
    /**
1345
     * Sets the body template.
1346
     * ```html
1347
     * <ng-template #bodyTemplate igxCell let-val>
1348
     *    <div style = "background-color: yellowgreen" (click) = "changeColor(val)">
1349
     *       <span> {{val}} </span>
1350
     *    </div>
1351
     * </ng-template>
1352
     * ```
1353
     * ```typescript
1354
     * @ViewChild("'bodyTemplate'", {read: TemplateRef })
1355
     * public bodyTemplate: TemplateRef<any>;
1356
     * this.column.bodyTemplate = this.bodyTemplate;
1357
     * ```
1358
     *
1359
     * @memberof IgxColumnComponent
1360
     */
1361
    public set bodyTemplate(template: TemplateRef<IgxCellTemplateContext>) {
1362
        this._bodyTemplate = template;
1,482✔
1363
    }
1364
    /**
1365
     * Returns a reference to the header template.
1366
     * ```typescript
1367
     * let headerTemplate = this.column.headerTemplate;
1368
     * ```
1369
     *
1370
     * @memberof IgxColumnComponent
1371
     */
1372
    @notifyChanges()
1373
    @WatchColumnChanges()
1374
    @Input()
1375
    public get headerTemplate(): TemplateRef<IgxColumnTemplateContext> {
1376
        return this._headerTemplate;
276,878✔
1377
    }
1378
    /**
1379
     * Sets the header template.
1380
     * Note that the column header height is fixed and any content bigger than it will be cut off.
1381
     * ```html
1382
     * <ng-template #headerTemplate>
1383
     *   <div style = "background-color:black" (click) = "changeColor(val)">
1384
     *       <span style="color:red" >{{column.field}}</span>
1385
     *   </div>
1386
     * </ng-template>
1387
     * ```
1388
     * ```typescript
1389
     * @ViewChild("'headerTemplate'", {read: TemplateRef })
1390
     * public headerTemplate: TemplateRef<any>;
1391
     * this.column.headerTemplate = this.headerTemplate;
1392
     * ```
1393
     *
1394
     * @memberof IgxColumnComponent
1395
     */
1396
    public set headerTemplate(template: TemplateRef<IgxColumnTemplateContext>) {
1397
        this._headerTemplate = template;
5,644✔
1398
    }
1399
    /**
1400
     * Returns a reference to the inline editor template.
1401
     * ```typescript
1402
     * let inlineEditorTemplate = this.column.inlineEditorTemplate;
1403
     * ```
1404
     *
1405
     * @memberof IgxColumnComponent
1406
     */
1407
    @notifyChanges()
1408
    @WatchColumnChanges()
1409
    @Input('cellEditorTemplate')
1410
    public get inlineEditorTemplate(): TemplateRef<IgxCellTemplateContext> {
1411
        return this._inlineEditorTemplate;
5,745✔
1412
    }
1413
    /**
1414
     * Sets the inline editor template.
1415
     * ```html
1416
     * <ng-template #inlineEditorTemplate igxCellEditor let-cell="cell">
1417
     *     <input type="string" [(ngModel)]="cell.value"/>
1418
     * </ng-template>
1419
     * ```
1420
     * ```typescript
1421
     * @ViewChild("'inlineEditorTemplate'", {read: TemplateRef })
1422
     * public inlineEditorTemplate: TemplateRef<any>;
1423
     * this.column.inlineEditorTemplate = this.inlineEditorTemplate;
1424
     * ```
1425
     *
1426
     * @memberof IgxColumnComponent
1427
     */
1428
    public set inlineEditorTemplate(template: TemplateRef<IgxCellTemplateContext>) {
1429
        this._inlineEditorTemplate = template;
1,475✔
1430
    }
1431

1432
    /**
1433
     * Returns a reference to the validation error template.
1434
     * ```typescript
1435
     * let errorTemplate = this.column.errorTemplate;
1436
     * ```
1437
     */
1438
    @notifyChanges()
1439
    @WatchColumnChanges()
1440
    @Input('errorTemplate')
1441
    public get errorTemplate(): TemplateRef<IgxCellTemplateContext> {
1442
        return this._errorTemplate;
1,208,009✔
1443
    }
1444
    /**
1445
     * Sets the error template.
1446
     * ```html
1447
     * <ng-template igxCellValidationError let-cell="cell" #errorTemplate >
1448
     *     <div *ngIf="cell.validation.errors?.['forbiddenName']">
1449
     *      This name is forbidden.
1450
     *     </div>
1451
     * </ng-template>
1452
     * ```
1453
     * ```typescript
1454
     * @ViewChild("'errorTemplate'", {read: TemplateRef })
1455
     * public errorTemplate: TemplateRef<any>;
1456
     * this.column.errorTemplate = this.errorTemplate;
1457
     * ```
1458
     */
1459
    public set errorTemplate(template: TemplateRef<IgxCellTemplateContext>) {
1460
        this._errorTemplate = template;
1,538✔
1461
    }
1462

1463
    /**
1464
     * Returns a reference to the `filterCellTemplate`.
1465
     * ```typescript
1466
     * let filterCellTemplate = this.column.filterCellTemplate;
1467
     * ```
1468
     *
1469
     * @memberof IgxColumnComponent
1470
     */
1471
    @notifyChanges()
1472
    @WatchColumnChanges()
1473
    @Input('filterCellTemplate')
1474
    public get filterCellTemplate(): TemplateRef<IgxColumnTemplateContext> {
1475
        return this._filterCellTemplate;
43,372✔
1476
    }
1477
    /**
1478
     * Sets the quick filter template.
1479
     * ```html
1480
     * <ng-template #filterCellTemplate IgxFilterCellTemplate let-column="column">
1481
     *    <input (input)="onInput()">
1482
     * </ng-template>
1483
     * ```
1484
     * ```typescript
1485
     * @ViewChild("'filterCellTemplate'", {read: TemplateRef })
1486
     * public filterCellTemplate: TemplateRef<any>;
1487
     * this.column.filterCellTemplate = this.filterCellTemplate;
1488
     * ```
1489
     *
1490
     * @memberof IgxColumnComponent
1491
     */
1492
    public set filterCellTemplate(template: TemplateRef<IgxColumnTemplateContext>) {
1493
        this._filterCellTemplate = template;
1,554✔
1494
    }
1495

1496
    /**
1497
     * @hidden @internal
1498
     */
1499
    public get cells(): CellType[] {
1500
        return this.grid.dataView
23✔
1501
            .map((rec, index) => {
1502
                if (!this.grid.isGroupByRecord(rec) && !this.grid.isSummaryRow(rec)) {
1,273✔
1503
                    this.grid.pagingMode === 'remote' && this.grid.page !== 0 ?
1,273!
1504
                        index = index + this.grid.perPage * this.grid.page : index = this.grid.dataRowList.first.index + index;
1505
                    const cell = new IgxGridCell(this.grid as any, index, this);
1,273✔
1506
                    return cell;
1,273✔
1507
                }
1508
            }).filter(cell => cell);
1,273✔
1509
    }
1510

1511

1512
    /**
1513
     * @hidden @internal
1514
     */
1515
    public get _cells(): CellType[] {
1516
        return this.grid.rowList.filter((row) => row instanceof IgxRowDirective)
2,905✔
1517
            .map((row) => {
1518
                if (row._cells) {
2,905✔
1519
                    return row._cells.filter((cell) => cell.columnIndex === this.index);
17,373✔
1520
                }
1521
            }).reduce((a, b) => a.concat(b), []);
2,905✔
1522
    }
1523

1524
    /**
1525
     * Gets the column visible index.
1526
     * If the column is not visible, returns `-1`.
1527
     * ```typescript
1528
     * let visibleColumnIndex =  this.column.visibleIndex;
1529
     * ```
1530
     */
1531
    public get visibleIndex(): number {
1532
        if (!isNaN(this._vIndex)) {
4,596,250✔
1533
            return this._vIndex;
4,122,370✔
1534
        }
1535
        const unpinnedColumns = this.grid.unpinnedColumns.filter(c => !c.columnGroup);
5,316,298✔
1536
        const pinnedStartColumns = this.grid.pinnedStartColumns.filter(c => !c.columnGroup);
473,880✔
1537
        const pinnedEndColumns = this.grid.pinnedEndColumns.filter(c => !c.columnGroup);
473,880✔
1538

1539
        let col = this;
473,880✔
1540
        let vIndex = -1;
473,880✔
1541

1542
        if (this.columnGroup) {
473,880✔
1543
            col = this.allChildren.filter(c => !c.columnGroup && !c.hidden)[0] as any;
30,516✔
1544
        }
1545
        if (this.columnLayoutChild) {
473,880✔
1546
            // TODO: Refactor/redo/remove this
1547
            return (this.parent as IgxColumnLayoutComponent).childrenVisibleIndexes.find(x => x.column === this).index;
886,628✔
1548
        }
1549

1550
        if (!this.pinned) {
130,862✔
1551
            const indexInCollection = unpinnedColumns.indexOf(col);
128,326✔
1552
            vIndex = indexInCollection === -1 ?
128,326✔
1553
                -1 : pinnedStartColumns.length + indexInCollection;
1554
        } else {
1555
            const indexInCollection = this.pinningPosition === ColumnPinningPosition.Start ?
2,536✔
1556
            pinnedStartColumns.indexOf(col) : pinnedEndColumns.indexOf(col);
1557
            vIndex = this.pinningPosition === ColumnPinningPosition.Start ?
2,536✔
1558
                indexInCollection :
1559
                pinnedStartColumns.length + unpinnedColumns.length + indexInCollection;
1560
        }
1561
        this._vIndex = vIndex;
130,862✔
1562
        return vIndex;
130,862✔
1563
    }
1564

1565
    /* blazorCSSuppress - Blazor doesn't carry over the ColumnType interface + should translate as static bool value */
1566
    /**
1567
     * Returns a boolean indicating if the column is a `ColumnGroup`.
1568
     * ```typescript
1569
     * let columnGroup =  this.column.columnGroup;
1570
     * ```
1571
     *
1572
     * @memberof IgxColumnComponent
1573
     */
1574
    public get columnGroup() {
1575
        return false;
8,961,484✔
1576
    }
1577

1578
    /* blazorCSSuppress - Blazor doesn't carry over the ColumnType interface + should translate as static bool value */
1579
    /**
1580
     * Returns a boolean indicating if the column is a `ColumnLayout` for multi-row layout.
1581
     * ```typescript
1582
     * let columnGroup =  this.column.columnGroup;
1583
     * ```
1584
     *
1585
     * @memberof IgxColumnComponent
1586
     */
1587
    public get columnLayout() {
1588
        return false;
25,011,808✔
1589
    }
1590

1591
    /**
1592
     * Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
1593
     * ```typescript
1594
     * let columnLayoutChild =  this.column.columnLayoutChild;
1595
     * ```
1596
     *
1597
     * @memberof IgxColumnComponent
1598
     */
1599
    public get columnLayoutChild(): boolean {
1600
        return this.parent && this.parent.columnLayout;
17,684,700✔
1601
    }
1602

1603
    /**
1604
     * A list containing all the child columns under this column (if any).
1605
     * Empty without children or if this column is not Group or Layout.
1606
     */
1607
    public get childColumns(): ColumnType[] {
UNCOV
1608
        return [];
×
1609
    }
1610

1611
    /** @hidden @internal **/
1612
    public get allChildren(): IgxColumnComponent[] {
1613
        return [];
317✔
1614
    }
1615
    /**
1616
     * Returns the level of the column in a column group.
1617
     * Returns `0` if the column doesn't have a `parent`.
1618
     * ```typescript
1619
     * let columnLevel =  this.column.level;
1620
     * ```
1621
     *
1622
     * @memberof IgxColumnComponent
1623
     */
1624
    public get level() {
1625
        let ptr = this.parent;
511,266✔
1626
        let lvl = 0;
511,266✔
1627

1628
        while (ptr) {
511,266✔
1629
            lvl++;
169,192✔
1630
            ptr = ptr.parent;
169,192✔
1631
        }
1632
        return lvl;
511,266✔
1633
    }
1634

1635
    /** @hidden @internal **/
1636
    public get isLastPinned(): boolean {
1637
        return this.pinningPosition === ColumnPinningPosition.Start &&
1,374,428✔
1638
            this.grid.pinnedStartColumns[this.grid.pinnedStartColumns.length - 1] === this;
1639
    }
1640

1641
    /** @hidden @internal **/
1642
    public get isFirstPinned(): boolean {
1643
        const pinnedCols = this.grid.pinnedEndColumns.filter(x => !x.columnGroup);
1,243,055✔
1644
        return this.pinningPosition === ColumnPinningPosition.End && pinnedCols[0] === this;
1,243,055✔
1645
    }
1646

1647
    /** @hidden @internal **/
1648
    public get gridRowSpan(): number {
1649
        return this.rowEnd && this.rowStart ? this.rowEnd - this.rowStart : 1;
1,288✔
1650
    }
1651
    /** @hidden @internal **/
1652
    public get gridColumnSpan(): number {
1653
        return this.colEnd && this.colStart ? this.colEnd - this.colStart : 1;
554,310✔
1654
    }
1655

1656
    /**
1657
     * Indicates whether the column will be visible when its parent is collapsed.
1658
     * ```html
1659
     * <igx-column-group>
1660
     *   <igx-column [visibleWhenCollapsed]="true"></igx-column>
1661
     * </igx-column-group>
1662
     * ```
1663
     *
1664
     * @memberof IgxColumnComponent
1665
     */
1666
    @notifyChanges(true)
1667
    @Input({ transform: booleanAttribute })
1668
    public set visibleWhenCollapsed(value: boolean) {
1669
        this._visibleWhenCollapsed = value;
1,887✔
1670
        this.visibleWhenCollapsedChange.emit(this._visibleWhenCollapsed);
1,887✔
1671
        if (this.parent) {
1,887✔
1672
            // TODO: Refactor/redo/remove this
1673
            (this.parent as IgxColumnLayoutComponent)?.setExpandCollapseState?.();
26✔
1674
        }
1675
    }
1676

1677
    public get visibleWhenCollapsed(): boolean {
1678
        return this._visibleWhenCollapsed;
9,703✔
1679
    }
1680

1681
    /* mustSetInCodePlatforms: WebComponents;Blazor;React */
1682
    /**
1683
     * @remarks
1684
     * Pass optional parameters for DatePipe and/or DecimalPipe to format the display value for date and numeric columns.
1685
     * Accepts an `IColumnPipeArgs` object with any of the `format`, `timezone` and `digitsInfo` properties.
1686
     * For more details see https://angular.io/api/common/DatePipe and https://angular.io/api/common/DecimalPipe
1687
     * @example
1688
     * ```typescript
1689
     * const pipeArgs: IColumnPipeArgs = {
1690
     *      format: 'longDate',
1691
     *      timezone: 'UTC',
1692
     *      digitsInfo: '1.1-2'
1693
     * }
1694
     * ```
1695
     * ```html
1696
     * <igx-column dataType="date" [pipeArgs]="pipeArgs"></igx-column>
1697
     * <igx-column dataType="number" [pipeArgs]="pipeArgs"></igx-column>
1698
     * ```
1699
     * @memberof IgxColumnComponent
1700
     */
1701
    @notifyChanges()
1702
    @WatchColumnChanges()
1703
    @Input()
1704
    public set pipeArgs(value: IColumnPipeArgs) {
1705
        this._columnPipeArgs = Object.assign(this._columnPipeArgs, value);
1,578✔
1706
        this.grid.summaryService.clearSummaryCache();
1,578✔
1707
        this.grid.pipeTrigger++;
1,578✔
1708
    }
1709
    /* mustSetInCodePlatforms: WebComponents;Blazor */
1710
    public get pipeArgs(): IColumnPipeArgs {
1711
        return this._columnPipeArgs;
1,737,860✔
1712
    }
1713

1714
    /**
1715
     * Pass optional properties for the default column editors.
1716
     * @remarks
1717
     * Options may be applicable only to specific column type editors.
1718
     * @example
1719
     * ```typescript
1720
     * const editorOptions: IColumnEditorOptions = {
1721
     *      dateTimeFormat: 'MM/dd/YYYY',
1722
     * }
1723
     * ```
1724
     * ```html
1725
     * <igx-column dataType="date" [editorOptions]="editorOptions"></igx-column>
1726
     * ```
1727
     * @memberof IgxColumnComponent
1728
     */
1729
    @notifyChanges()
1730
    @WatchColumnChanges()
1731
    @Input()
1732
    public set editorOptions(value: IColumnEditorOptions) {
1733
        this._editorOptions = value;
1,548✔
1734
    }
1735
    public get editorOptions(): IColumnEditorOptions {
1736
        return this._editorOptions;
5,203✔
1737
    }
1738

1739
    /**
1740
     * @hidden
1741
     * @internal
1742
     */
1743
    public get collapsible() {
UNCOV
1744
        return false;
×
1745
    }
1746
    public set collapsible(_value: boolean) { }
1747

1748
    /**
1749
     * @hidden
1750
     * @internal
1751
     */
1752
    public get expanded() {
UNCOV
1753
        return true;
×
1754
    }
1755
    public set expanded(_value: boolean) { }
1756

1757
    /**
1758
     * @hidden
1759
     */
1760
    public defaultWidth: string;
1761

1762
    /**
1763
     * @hidden
1764
     */
1765
    public widthSetByUser: boolean;
1766

1767
    /**
1768
     * @hidden
1769
     */
1770
    public hasNestedPath: boolean;
1771

1772
    /**
1773
     * @hidden
1774
     * @internal
1775
     */
1776
    public defaultTimeFormat = 'hh:mm:ss a';
31,581✔
1777

1778
    /**
1779
     * @hidden
1780
     * @internal
1781
     */
1782
    public defaultDateTimeFormat = 'dd/MM/yyyy HH:mm:ss a';
31,581✔
1783

1784

1785
    /**
1786
     * Returns the filteringExpressionsTree of the column.
1787
     * ```typescript
1788
     * let tree =  this.column.filteringExpressionsTree;
1789
     * ```
1790
     *
1791
     * @memberof IgxColumnComponent
1792
     */
1793
    public get filteringExpressionsTree(): FilteringExpressionsTree {
1794
        return ExpressionsTreeUtil.find(this.grid.filteringExpressionsTree, this.field) as FilteringExpressionsTree;
66,026✔
1795
    }
1796

1797
    /* alternateName: parentColumn */
1798
    /**
1799
     * Sets/gets the parent column.
1800
     * ```typescript
1801
     * let parentColumn = this.column.parent;
1802
     * ```
1803
     * ```typescript
1804
     * this.column.parent = higherLevelColumn;
1805
     * ```
1806
     */
1807
    public parent: ColumnType | null = null;
31,581✔
1808

1809
    /* blazorSuppress */
1810
    /**
1811
     * Sets/gets the children columns.
1812
     * ```typescript
1813
     * let columnChildren = this.column.children;
1814
     * ```
1815
     *
1816
     * @deprecated in version 18.1.0. Use the `childColumns` property instead.
1817
     */
1818
    public children: QueryList<IgxColumnComponent>;
1819
    /**
1820
     * @hidden
1821
     */
1822
    public destroy$ = new Subject<any>();
31,581✔
1823

1824
    /**
1825
     * @hidden
1826
     */
1827
    public widthConstrained = false;
31,581✔
1828

1829
    /**
1830
     * @hidden
1831
     */
1832
    protected _applySelectableClass = false;
31,581✔
1833

1834
    protected _vIndex = NaN;
31,581✔
1835
    protected _pinningPosition = null;
31,581✔
1836
    /**
1837
     * @hidden
1838
     */
1839
    protected _pinned = false;
31,581✔
1840
    /**
1841
     * @hidden
1842
     */
1843
    protected _bodyTemplate: TemplateRef<IgxCellTemplateContext>;
1844
    /**
1845
     * @hidden
1846
     */
1847
    protected _errorTemplate: TemplateRef<IgxCellTemplateContext>;
1848
    /**
1849
     * @hidden
1850
     */
1851
    protected _headerTemplate: TemplateRef<IgxColumnTemplateContext>;
1852
    /**
1853
     * @hidden
1854
     */
1855
    protected _summaryTemplate: TemplateRef<IgxSummaryTemplateContext>;
1856
    /**
1857
     * @hidden
1858
     */
1859
    protected _inlineEditorTemplate: TemplateRef<IgxCellTemplateContext>;
1860
    /**
1861
     * @hidden
1862
     */
1863
    protected _filterCellTemplate: TemplateRef<IgxColumnTemplateContext>;
1864
    /**
1865
     * @hidden
1866
     */
1867
    protected _summaries = null;
31,581✔
1868
    /**
1869
     * @hidden
1870
     */
1871
    private _disabledSummaries: string[] = [];
31,581✔
1872
    /**
1873
     * @hidden
1874
     */
1875
    protected _filters = null;
31,581✔
1876
    /**
1877
     * @hidden
1878
     */
1879
    protected _sortStrategy: ISortingStrategy = DefaultSortingStrategy.instance();
31,581✔
1880
    /**
1881
     * @hidden
1882
     */
1883
    protected _groupingComparer: (a: any, b: any, currRec?: any, groupRec?: any) => number;
1884

1885
    protected _mergingComparer: (prevRecord: any, record: any, field: string) => boolean;
1886
    /**
1887
     * @hidden
1888
     */
1889
    protected _hidden = false;
31,581✔
1890
    /**
1891
     * @hidden
1892
     */
1893
    protected _index: number;
1894
    /**
1895
     * @hidden
1896
     */
1897
    protected _disablePinning = false;
31,581✔
1898
    /**
1899
     * @hidden
1900
     */
1901
    protected _width: string;
1902
    /**
1903
     * @hidden
1904
     */
1905
    protected _defaultMinWidth = '';
31,581✔
1906
    /**
1907
     * @hidden
1908
     */
1909
    protected _maxWidth;
1910
    /**
1911
     * @hidden
1912
     */
1913
    protected _hasSummary = false;
31,581✔
1914
    /**
1915
     * @hidden
1916
     */
1917
    protected _editable: boolean;
1918
    /**
1919
     * @hidden
1920
     */
1921
    protected _groupable = false;
31,581✔
1922
    /**
1923
     * @hidden
1924
     */
1925
    protected _merge = false;
31,581✔
1926
    /**
1927
     *  @hidden
1928
     */
1929
    protected _visibleWhenCollapsed;
1930
    /**
1931
     * @hidden
1932
     */
1933
    protected _collapsible = false;
31,581✔
1934
    /**
1935
     * @hidden
1936
     */
1937
    protected _expanded = true;
31,581✔
1938
    /**
1939
     * @hidden
1940
     */
1941
    protected _selectable = true;
31,581✔
1942
    /**
1943
     * @hidden
1944
     */
1945
    protected get isPrimaryColumn(): boolean {
1946
        return this.field !== undefined && this.grid !== undefined && this.field === this.grid.primaryKey;
2,536,869✔
1947
    }
1948

1949
    private _field: string;
1950
    private _calcWidth = null;
31,581✔
1951
    private _columnPipeArgs: IColumnPipeArgs = { digitsInfo: DEFAULT_DIGITS_INFO };
31,581✔
1952
    private _editorOptions: IColumnEditorOptions = { };
31,581✔
1953

1954
    /**
1955
     * @hidden
1956
     * @internal
1957
     */
1958
    public resetCaches() {
1959
        this._vIndex = NaN;
349,175✔
1960
        if (this.grid) {
349,175✔
1961
            this.cacheCalcWidth();
349,175✔
1962
        }
1963
    }
1964

1965
    /**
1966
     * @hidden
1967
     */
1968
    public ngOnDestroy() {
1969
        this.destroy$.next(true);
21,814✔
1970
        this.destroy$.complete();
21,814✔
1971
    }
1972
    /**
1973
     * @hidden
1974
     */
1975
    public ngAfterContentInit(): void {
1976
        if (this.summaryTemplateDirective) {
25,834✔
1977
            this._summaryTemplate = this.summaryTemplateDirective.template;
6✔
1978
        }
1979
        if (this.cellTemplate) {
25,834✔
1980
            this._bodyTemplate = this.cellTemplate.template;
46✔
1981
        }
1982
        if (this.cellValidationErrorTemplate) {
25,834✔
1983
            this._errorTemplate = this.cellValidationErrorTemplate.template;
16✔
1984
        }
1985
        if (this.headTemplate && this.headTemplate.length) {
25,834✔
1986
            this._headerTemplate = this.headTemplate.toArray()[0].template;
94✔
1987
        }
1988
        if (this.editorTemplate) {
25,834✔
1989
            this._inlineEditorTemplate = this.editorTemplate.template;
4✔
1990
        }
1991
        if (this.filterCellTemplateDirective) {
25,834!
UNCOV
1992
            this._filterCellTemplate = this.filterCellTemplateDirective.template;
×
1993
        }
1994
        if (!this._columnPipeArgs.format) {
25,834✔
1995
            this._columnPipeArgs.format = this.dataType === GridColumnDataType.Time ?
24,513✔
1996
                DEFAULT_TIME_FORMAT : this.dataType === GridColumnDataType.DateTime ?
24,239✔
1997
                    DEFAULT_DATE_TIME_FORMAT : DEFAULT_DATE_FORMAT;
1998
        }
1999
        if (!this.summaries) {
25,834✔
2000
            switch (this.dataType) {
24,455✔
2001
                case GridColumnDataType.Number:
2002
                case GridColumnDataType.Currency:
2003
                case GridColumnDataType.Percent:
2004
                    this.summaries = IgxNumberSummaryOperand;
7,280✔
2005
                    break;
7,280✔
2006
                case GridColumnDataType.Date:
2007
                case GridColumnDataType.DateTime:
2008
                    this.summaries = IgxDateSummaryOperand;
1,840✔
2009
                    break;
1,840✔
2010
                case GridColumnDataType.Time:
2011
                    this.summaries = IgxTimeSummaryOperand;
274✔
2012
                    break;
274✔
2013

2014
                case GridColumnDataType.String:
2015
                case GridColumnDataType.Boolean:
2016
                default:
2017
                    this.summaries = IgxSummaryOperand;
15,061✔
2018
                    break;
15,061✔
2019
            }
2020
        }
2021
        if (!this.filters) {
25,834✔
2022
            switch (this.dataType) {
24,216✔
2023
                case GridColumnDataType.Boolean:
2024
                    this.filters = IgxBooleanFilteringOperand.instance();
1,216✔
2025
                    break;
1,216✔
2026
                case GridColumnDataType.Number:
2027
                case GridColumnDataType.Currency:
2028
                case GridColumnDataType.Percent:
2029
                    this.filters = IgxNumberFilteringOperand.instance();
7,326✔
2030
                    break;
7,326✔
2031
                case GridColumnDataType.Date:
2032
                    this.filters = IgxDateFilteringOperand.instance();
1,578✔
2033
                    break;
1,578✔
2034
                case GridColumnDataType.Time:
2035
                    this.filters = IgxTimeFilteringOperand.instance();
274✔
2036
                    break;
274✔
2037
                case GridColumnDataType.DateTime:
2038
                    this.filters = IgxDateTimeFilteringOperand.instance();
269✔
2039
                    break;
269✔
2040
                case GridColumnDataType.Image:
2041
                    this.filterable = false;
1✔
2042
                    break;
1✔
2043
                case GridColumnDataType.String:
2044
                default:
2045
                    this.filters = IgxStringFilteringOperand.instance();
13,552✔
2046
                    break;
13,552✔
2047
            }
2048
        }
2049
    }
2050

2051
    /**
2052
     * @hidden
2053
     */
2054
    public getGridTemplate(isRow: boolean): string {
2055
        if (isRow) {
26,336✔
2056
            const rowsCount = this.grid.type !== 'pivot' ? this.grid.multiRowLayoutRowSize : this.children.length - 1;
13,169!
2057
            return `repeat(${rowsCount},1fr)`;
13,169✔
2058
        } else {
2059
            return this.getColumnSizesString(this.children);
13,167✔
2060
        }
2061
    }
2062

2063
    /** @hidden @internal **/
2064
    public getInitialChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<MRLColumnSizeInfo> {
2065
        const columnSizes: MRLColumnSizeInfo[] = [];
121,930✔
2066
        // find the smallest col spans
2067
        children.forEach(col => {
121,930✔
2068
            if (!col.colStart) {
373,251✔
2069
                return;
87,658✔
2070
            }
2071
            const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
285,593✔
2072
            const newSpanSmaller = columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].colSpan > col.gridColumnSpan;
285,593✔
2073
            const bothWidthsSet = col.widthSetByUser && columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].widthSetByUser;
285,593✔
2074
            const bothWidthsNotSet = !col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
285,593✔
2075

2076
            if (columnSizes[col.colStart - 1] === undefined) {
285,593✔
2077
                // If nothing is defined yet take any column at first
2078
                // We use colEnd to know where the column actually ends, because not always it starts where we have it set in columnSizes.
2079
                columnSizes[col.colStart - 1] = {
176,605✔
2080
                    ref: col,
2081
                    width: col.width === 'fit-content' ? col.autoSize :
176,605!
2082
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
515,040✔
2083
                    colSpan: col.gridColumnSpan,
2084
                    colEnd: col.colStart + col.gridColumnSpan,
2085
                    widthSetByUser: col.widthSetByUser
2086
                };
2087
            } else if (newWidthSet || (newSpanSmaller && ((bothWidthsSet) || (bothWidthsNotSet)))) {
108,988✔
2088
                // If a column is set already it should either not have width defined or have width with bigger span than the new one.
2089

2090
                /**
2091
                 *  If replaced column has bigger span, we want to fill the remaining columns
2092
                 *  that the replacing column does not fill with the old one.
2093
                 */
2094
                if (bothWidthsSet && newSpanSmaller) {
39,316✔
2095
                    // Start from where the new column set would end and apply the old column to the rest depending on how much it spans.
2096
                    // We have not yet replaced it so we can use it directly from the columnSizes collection.
2097
                    // This is where colEnd is used because the colStart of the old column is not actually i + 1.
2098
                    for (let i = col.colStart - 1 + col.gridColumnSpan; i < columnSizes[col.colStart - 1].colEnd - 1; i++) {
4,136✔
2099
                        if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
2,346✔
2100
                            columnSizes[i] = columnSizes[col.colStart - 1];
2,308✔
2101
                        } else {
2102
                            break;
38✔
2103
                        }
2104
                    }
2105
                }
2106

2107
                // Replace the old column with the new one.
2108
                columnSizes[col.colStart - 1] = {
39,316✔
2109
                    ref: col,
2110
                    width: col.width === 'fit-content' ? col.autoSize :
39,316!
2111
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
110,205✔
2112
                    colSpan: col.gridColumnSpan,
2113
                    colEnd: col.colStart + col.gridColumnSpan,
2114
                    widthSetByUser: col.widthSetByUser
2115
                };
2116
            } else if (bothWidthsSet && columnSizes[col.colStart - 1].colSpan < col.gridColumnSpan) {
69,672✔
2117
                // If the column already in the columnSizes has smaller span, we still need to fill any empty places with the current col.
2118
                // Start from where the smaller column set would end and apply the bigger column to the rest depending on how much it spans.
2119
                // Since here we do not have it in columnSizes we set it as a new column keeping the same colSpan.
2120
                for (let i = col.colStart - 1 + columnSizes[col.colStart - 1].colSpan; i < col.colStart - 1 + col.gridColumnSpan; i++) {
3,558✔
2121
                    if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
3,558✔
2122
                        columnSizes[i] = {
35✔
2123
                            ref: col,
2124
                            width: col.width === 'fit-content' ? col.autoSize :
35!
2125
                                col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
70!
2126
                            colSpan: col.gridColumnSpan,
2127
                            colEnd: col.colStart + col.gridColumnSpan,
2128
                            widthSetByUser: col.widthSetByUser
2129
                        };
2130
                    } else {
2131
                        break;
3,523✔
2132
                    }
2133
                }
2134
            }
2135
        });
2136

2137
        // Flatten columnSizes so there are not columns with colSpan > 1
2138
        for (let i = 0; i < columnSizes.length; i++) {
121,930✔
2139
            if (columnSizes[i] && columnSizes[i].colSpan > 1) {
174,856✔
2140
                let j = 1;
9,369✔
2141

2142
                // Replace all empty places depending on how much the current column spans starting from next col.
2143
                for (; j < columnSizes[i].colSpan && i + j + 1 < columnSizes[i].colEnd; j++) {
9,369✔
2144
                    if (columnSizes[i + j] &&
9,037✔
2145
                        ((!columnSizes[i].width && columnSizes[i + j].width) ||
2146
                            (!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
2147
                            (!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
2148
                        // If we reach an already defined column that has width and the current doesn't have or
2149
                        // if the reached column has bigger colSpan we stop.
2150
                        break;
3,672✔
2151
                    } else {
2152
                        const width = columnSizes[i].widthSetByUser ?
5,365✔
2153
                            columnSizes[i].width / columnSizes[i].colSpan :
2154
                            columnSizes[i].width;
2155
                        columnSizes[i + j] = {
5,365✔
2156
                            ref: columnSizes[i].ref,
2157
                            width,
2158
                            colSpan: 1,
2159
                            colEnd: columnSizes[i].colEnd,
2160
                            widthSetByUser: columnSizes[i].widthSetByUser
2161
                        };
2162
                    }
2163
                }
2164

2165
                // Update the current column width so it is divided between all columns it spans and set it to 1.
2166
                columnSizes[i].width = columnSizes[i].widthSetByUser ?
9,369✔
2167
                    columnSizes[i].width / columnSizes[i].colSpan :
2168
                    columnSizes[i].width;
2169
                columnSizes[i].colSpan = 1;
9,369✔
2170

2171
                // Update the index based on how much we have replaced. Subtract 1 because we started from 1.
2172
                i += j - 1;
9,369✔
2173
            }
2174
        }
2175

2176
        return columnSizes;
121,930✔
2177
    }
2178

2179
    /** @hidden @internal **/
2180
    public getFilledChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<string> {
2181
        const columnSizes = this.getInitialChildColumnSizes(children);
20,843✔
2182

2183
        // fill the gaps if there are any
2184
        const result: string[] = [];
20,843✔
2185
        for (const size of columnSizes) {
20,843✔
2186
            if (size && !!size.width) {
46,762✔
2187
                result.push(size.width + 'px');
18,668✔
2188
            } else {
2189
                const currentWidth = parseFloat(this.grid.getPossibleColumnWidth());
28,094✔
2190
                result.push((this.getConstrainedSizePx(currentWidth)) + 'px');
28,094✔
2191
            }
2192
        }
2193
        return result;
20,843✔
2194
    }
2195

2196
    /** @hidden @internal **/
2197
    public getResizableColUnderEnd(): MRLResizeColumnInfo[] {
2198
        if (this.columnLayout || !this.columnLayoutChild || this.columnGroup) {
6!
UNCOV
2199
            return [{ target: this, spanUsed: 1 }];
×
2200
        }
2201

2202
        const columnSized = this.getInitialChildColumnSizes(this.parent.children as QueryList<IgxColumnComponent>);
6✔
2203
        const targets: MRLResizeColumnInfo[] = [];
6✔
2204
        const colEnd = this.colEnd ? this.colEnd : this.colStart + 1;
6!
2205

2206
        for (let i = 0; i < columnSized.length; i++) {
6✔
2207
            if (this.colStart <= i + 1 && i + 1 < colEnd) {
36✔
2208
                targets.push({ target: columnSized[i].ref, spanUsed: 1 });
10✔
2209
            }
2210
        }
2211

2212
        const targetsSquashed: MRLResizeColumnInfo[] = [];
6✔
2213
        for (const target of targets) {
6✔
2214
            if (targetsSquashed.length && targetsSquashed[targetsSquashed.length - 1].target.field === target.target.field) {
10!
UNCOV
2215
                targetsSquashed[targetsSquashed.length - 1].spanUsed++;
×
2216
            } else {
2217
                targetsSquashed.push(target);
10✔
2218
            }
2219
        }
2220

2221
        return targetsSquashed;
6✔
2222
    }
2223

2224
    /**
2225
     * Pins the column in the specified position at the provided index in that pinned area.
2226
     * Defaults to index `0` if not provided, or to the initial index in the pinned area.
2227
     * Returns `true` if the column is successfully pinned. Returns `false` if the column cannot be pinned.
2228
     * Column cannot be pinned if:
2229
     * - Is already pinned
2230
     * - index argument is out of range
2231
     * ```typescript
2232
     * let success = this.column.pin();
2233
     * ```
2234
     *
2235
     * @memberof IgxColumnComponent
2236
     */
2237
    public pin(index?: number, pinningPosition?: ColumnPinningPosition): boolean {
2238
        // TODO: Probably should the return type of the old functions
2239
        // should be moved as a event parameter.
2240
        const grid = (this.grid as any);
635✔
2241
        if (this._pinned) {
635✔
2242
            return false;
58✔
2243
        }
2244

2245
        if (this.parent && !this.parent.pinned) {
577✔
2246
            return this.topLevelParent.pin(index, pinningPosition);
10✔
2247
        }
2248
        const targetPinPosition = pinningPosition !== null && pinningPosition !== undefined ?  pinningPosition : this.pinningPosition;
567✔
2249
        const pinningVisibleCollection = targetPinPosition === ColumnPinningPosition.Start ?
567✔
2250
        grid.pinnedStartColumns : grid.pinnedEndColumns;
2251
        const pinningCollection = targetPinPosition === ColumnPinningPosition.Start ?
567✔
2252
        grid._pinnedStartColumns : grid._pinnedEndColumns;
2253
        const hasIndex = index !== undefined && index !== null;
567✔
2254
        if (hasIndex && (index < 0 || index > pinningVisibleCollection.length)) {
567✔
2255
            return false;
2✔
2256
        }
2257

2258
        if (!this.parent && !this.pinnable) {
565!
UNCOV
2259
            return false;
×
2260
        }
2261

2262
        const rootPinnedCols = pinningCollection.filter((c) => c.level === 0);
1,116✔
2263
        index = hasIndex ? index : rootPinnedCols.length;
565✔
2264
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: false, cancel: false };
565✔
2265
        this.grid.columnPin.emit(args);
565✔
2266

2267
        if (args.cancel) {
565!
UNCOV
2268
            return;
×
2269
        }
2270

2271
        this.grid.crudService.endEdit(false);
565✔
2272

2273
        this._pinned = true;
565✔
2274
        if (pinningPosition !== null && pinningPosition !== undefined) {
565✔
2275
            // if user has set some position in the params, overwrite the column's position.
2276
            this._pinningPosition = pinningPosition;
163✔
2277
        }
2278

2279
        this.pinnedChange.emit(this._pinned);
565✔
2280
        // it is possible that index is the last position, so will need to find target column by [index-1]
2281
        const targetColumn = args.insertAtIndex === pinningCollection.length ?
565✔
2282
        pinningCollection[args.insertAtIndex - 1] : pinningCollection[args.insertAtIndex];
2283

2284
        if (pinningCollection.indexOf(this) === -1) {
565✔
2285
            if (!grid.hasColumnGroups) {
425✔
2286
                pinningCollection.splice(args.insertAtIndex, 0, this);
372✔
2287
                grid._pinnedColumns = grid._pinnedStartColumns.concat(grid._pinnedEndColumns);
372✔
2288
            } else {
2289
                // insert based only on root collection
2290
                if (this.level === 0) {
53✔
2291
                    rootPinnedCols.splice(args.insertAtIndex, 0, this);
46✔
2292
                }
2293
                let allPinned = [];
53✔
2294
                // FIX: this is duplicated on every step in the hierarchy....
2295
                // re-create hierarchy
2296
                rootPinnedCols.forEach(group => {
53✔
2297
                    allPinned.push(group);
83✔
2298
                    allPinned = allPinned.concat(group.allChildren);
83✔
2299
                });
2300
                grid._pinnedColumns = allPinned;
53✔
2301
                if (this.pinningPosition === ColumnPinningPosition.Start) {
53✔
2302
                    grid._pinnedStartColumns = allPinned;
51✔
2303
                } else {
2304
                    grid._pinnedEndColumns = allPinned;
2✔
2305
                }
2306
            }
2307

2308
            if (grid._unpinnedColumns.indexOf(this) !== -1) {
425✔
2309
                const childrenCount = this.allChildren.length;
194✔
2310
                grid._unpinnedColumns.splice(grid._unpinnedColumns.indexOf(this), 1 + childrenCount);
194✔
2311
            }
2312
        }
2313

2314
        if (hasIndex) {
565✔
2315
            index === pinningCollection.length - 1 ?
12✔
2316
                grid._moveColumns(this, targetColumn, DropPosition.AfterDropTarget) : grid._moveColumns(this, targetColumn, DropPosition.BeforeDropTarget);
2317
        }
2318

2319
        if (this.columnGroup) {
565✔
2320
            this.allChildren.forEach(child => child.pin(null, targetPinPosition));
203✔
2321
            grid.reinitPinStates();
64✔
2322
        }
2323

2324
        grid.resetCaches();
565✔
2325
        grid.notifyChanges();
565✔
2326
        if (this.columnLayoutChild) {
565✔
2327
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
498✔
2328
        }
2329
        this.grid.filteringService.refreshExpressions();
565✔
2330
        const eventArgs: IPinColumnEventArgs = { column: this, insertAtIndex: index, isPinned: true };
565✔
2331
        this.grid.columnPinned.emit(eventArgs);
565✔
2332
        return true;
565✔
2333
    }
2334
    /**
2335
     * Unpins the column and place it at the provided index in the unpinned area.
2336
     * Defaults to index `0` if not provided, or to the initial index in the unpinned area.
2337
     * Returns `true` if the column is successfully unpinned. Returns `false` if the column cannot be unpinned.
2338
     * Column cannot be unpinned if:
2339
     * - Is already unpinned
2340
     * - index argument is out of range
2341
     * ```typescript
2342
     * let success = this.column.unpin();
2343
     * ```
2344
     *
2345
     * @memberof IgxColumnComponent
2346
     */
2347
    public unpin(index?: number): boolean {
2348
        const grid = (this.grid as any);
187✔
2349
        if (!this._pinned) {
187✔
2350
            return false;
32✔
2351
        }
2352

2353
        if (this.parent && this.parent.pinned) {
155✔
2354
            return this.topLevelParent.unpin(index);
7✔
2355
        }
2356
        const hasIndex = index !== undefined && index !== null;
148✔
2357
        if (hasIndex && (index < 0 || index > grid._unpinnedColumns.length)) {
148✔
2358
            return false;
2✔
2359
        }
2360

2361
        // estimate the exact index at which column will be inserted
2362
        // takes into account initial unpinned index of the column
2363
        if (!hasIndex) {
146✔
2364
            const indices = grid._unpinnedColumns.map(col => col.index);
1,220✔
2365
            indices.push(this.index);
141✔
2366
            indices.sort((a, b) => a - b);
1,633✔
2367
            index = indices.indexOf(this.index);
141✔
2368
        }
2369

2370
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: true, cancel: false };
146✔
2371
        this.grid.columnPin.emit(args);
146✔
2372

2373
        if (args.cancel) {
146!
UNCOV
2374
            return;
×
2375
        }
2376

2377
        this.grid.crudService.endEdit(false);
146✔
2378

2379
        this._pinned = false;
146✔
2380
        this.pinnedChange.emit(this._pinned);
146✔
2381

2382
        // it is possible that index is the last position, so will need to find target column by [index-1]
2383
        const targetColumn = args.insertAtIndex === grid._unpinnedColumns.length ?
146✔
2384
            grid._unpinnedColumns[args.insertAtIndex - 1] : grid._unpinnedColumns[args.insertAtIndex];
2385

2386
        if (!hasIndex) {
146✔
2387
            grid._unpinnedColumns.splice(index, 0, this);
141✔
2388
            if (grid._pinnedColumns.indexOf(this) !== -1) {
141✔
2389
                grid._pinnedColumns.splice(grid._pinnedColumns.indexOf(this), 1);
141✔
2390
            }
2391
            if (this.pinningPosition === ColumnPinningPosition.Start && grid._pinnedStartColumns.indexOf(this) !== -1) {
141✔
2392
                grid._pinnedStartColumns.splice(grid._pinnedStartColumns.indexOf(this), 1);
139✔
2393
            }
2394
            if (this.pinningPosition === ColumnPinningPosition.End && grid._pinnedEndColumns.indexOf(this) !== -1) {
141✔
2395
                grid._pinnedEndColumns.splice(grid._pinnedEndColumns.indexOf(this), 1);
2✔
2396
            }
2397
        }
2398

2399
        if (hasIndex) {
146✔
2400
            grid.moveColumn(this, targetColumn);
5✔
2401
        }
2402

2403
        if (this.columnGroup) {
146✔
2404
            this.allChildren.forEach(child => child.unpin());
106✔
2405
        }
2406

2407
        grid.reinitPinStates();
146✔
2408
        grid.resetCaches();
146✔
2409

2410
        grid.notifyChanges();
146✔
2411
        if (this.columnLayoutChild) {
146✔
2412
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
356✔
2413
        }
2414
        this.grid.filteringService.refreshExpressions();
146✔
2415

2416
        this.grid.columnPinned.emit({ column: this, insertAtIndex: index, isPinned: false });
146✔
2417

2418
        return true;
146✔
2419
    }
2420

2421
    /**
2422
     * Moves a column to the specified visible index.
2423
     * If passed index is invalid, or if column would receive a different visible index after moving, moving is not performed.
2424
     * If passed index would move the column to a different column group. moving is not performed.
2425
     *
2426
     * @example
2427
     * ```typescript
2428
     * column.move(index);
2429
     * ```
2430
     * @memberof IgxColumnComponent
2431
     */
2432
    public move(index: number) {
2433
        let target;
2434
        let columns = this.grid.columns.filter(c => c.visibleIndex > -1);
349✔
2435
        // grid last visible index
2436
        const li = columns.map(c => c.visibleIndex).reduce((a, b) => Math.max(a, b));
343✔
2437
        const parent = this.parent;
36✔
2438
        const isPreceding = this.visibleIndex < index;
36✔
2439

2440
        if (index === this.visibleIndex || index < 0 || index > li) {
36✔
2441
            return;
3✔
2442
        }
2443

2444
        if (parent) {
33✔
2445
            columns = columns.filter(c => c.level >= this.level && c !== this && c.parent !== this &&
84✔
2446
                c.topLevelParent === this.topLevelParent);
2447
        }
2448

2449
        // If isPreceding, find a target such that when the current column is placed after it, current colummn will receive a visibleIndex === index. This takes into account visible children of the columns.
2450
        // If !isPreceding, finds a column of the same level and visible index that equals the passed index agument (c.visibleIndex === index). No need to consider the children here.
2451

2452
        if (isPreceding) {
33✔
2453
            columns = columns.filter(c => c.visibleIndex > this.visibleIndex);
200✔
2454
            target = columns.find(c => c.level === this.level && c.visibleIndex + (c as any).calcChildren() - this.calcChildren() === index);
80✔
2455
        } else {
2456
            columns = columns.filter(c => c.visibleIndex < this.visibleIndex);
65✔
2457
            target = columns.find(c => c.level === this.level && c.visibleIndex === index);
15✔
2458
        }
2459

2460
        if (!target || (target.pinned && this.disablePinning)) {
33✔
2461
            return;
9✔
2462
        }
2463

2464
        const pos = isPreceding ? DropPosition.AfterDropTarget : DropPosition.BeforeDropTarget;
24✔
2465
        this.grid.moveColumn(this, target as IgxColumnComponent, pos);
24✔
2466
    }
2467

2468
    /**
2469
     * No children for the column, so will returns 1 or 0, if the column is hidden.
2470
     *
2471
     * @hidden
2472
     */
2473
    public calcChildren(): number {
2474
        const children = this.hidden ? 0 : 1;
70✔
2475
        return children;
70✔
2476
    }
2477

2478
    /**
2479
     * Toggles column vibisility and emits the respective event.
2480
     *
2481
     * @hidden
2482
     */
2483
    public toggleVisibility(value?: boolean) {
2484
        const newValue = value ?? !this.hidden;
65✔
2485
        const eventArgs: IColumnVisibilityChangingEventArgs = { column: this, newValue, cancel: false };
65✔
2486
        this.grid.columnVisibilityChanging.emit(eventArgs);
65✔
2487

2488
        if (eventArgs.cancel) {
65!
UNCOV
2489
            return;
×
2490
        }
2491
        this.hidden = newValue;
65✔
2492
        this.grid.columnVisibilityChanged.emit({ column: this, newValue });
65✔
2493
    }
2494

2495
    /**
2496
     * Returns a reference to the top level parent column.
2497
     * ```typescript
2498
     * let topLevelParent =  this.column.topLevelParent;
2499
     * ```
2500
     */
2501
    public get topLevelParent(): ColumnType | undefined {
2502
        let parent = this.parent;
498✔
2503
        while (parent && parent.parent) {
498✔
2504
            parent = parent.parent;
34✔
2505
        }
2506
        return parent ?? undefined;
498✔
2507
    }
2508

2509
    /**
2510
     * @hidden @internal
2511
     */
2512
    public get headerCell(): IgxGridHeaderComponent {
2513
        return this.grid.headerCellList.find((header) => header.column === this);
1,613✔
2514
    }
2515

2516
    /**
2517
     * @hidden @internal
2518
     */
2519
    public get filterCell(): IgxGridFilteringCellComponent {
2520
        return this.grid.filterCellList.find((filterCell) => filterCell.column === this);
6,929✔
2521
    }
2522

2523
    /**
2524
     * @hidden @internal
2525
     */
2526
    public get headerGroup(): IgxGridHeaderGroupComponent {
2527
        return this.grid.headerGroupsList.find(group => group.column === this);
6,748✔
2528
    }
2529

2530
    /**
2531
     * Autosize the column to the longest currently visible cell value, including the header cell.
2532
     * ```typescript
2533
     * @ViewChild('grid') grid: IgxGridComponent;
2534
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2535
     * column.autosize();
2536
     * ```
2537
     *
2538
     * @memberof IgxColumnComponent
2539
     * @param byHeaderOnly Set if column should be autosized based only on the header content.
2540
     */
2541
    public autosize(byHeaderOnly = false) {
17✔
2542
        if (!this.columnGroup) {
18✔
2543
            this.width = this.getAutoSize(byHeaderOnly);
18✔
2544
            this.grid.reflow();
18✔
2545
        }
2546
    }
2547

2548
    /**
2549
     * @hidden
2550
     */
2551
    public getAutoSize(byHeader = false): string {
8✔
2552
        const size = !byHeader ? this.getLargestCellWidth() :
26✔
2553
            (Object.values(this.getHeaderCellWidths()).reduce((a, b) => a + b) + 'px');
1✔
2554
        const isPercentageWidth = this.width && typeof this.width === 'string' && this.width.indexOf('%') !== -1;
26✔
2555

2556
        let newWidth;
2557
        if (isPercentageWidth) {
26✔
2558
            const gridAvailableSize = this.grid.calcWidth;
2✔
2559
            const percentageSize = parseFloat(size) / gridAvailableSize * 100;
2✔
2560
            newWidth = percentageSize + '%';
2✔
2561
        } else {
2562
            newWidth = size;
24✔
2563
        }
2564

2565
        const maxWidth = isPercentageWidth ? this.maxWidthPercent : this.maxWidthPx;
26✔
2566
        const minWidth = isPercentageWidth ? this.minWidthPercent : this.minWidthPx;
26✔
2567
        if (this.maxWidth && (parseFloat(newWidth) > maxWidth)) {
26✔
2568
            newWidth = isPercentageWidth ? maxWidth + '%' : maxWidth + 'px';
1!
2569
        } else if (parseFloat(newWidth) < minWidth) {
25✔
2570
            newWidth = isPercentageWidth ? minWidth + '%' : minWidth + 'px';
1!
2571
        }
2572

2573
        return newWidth;
26✔
2574
    }
2575

2576
    /**
2577
     * @hidden
2578
     */
2579
    public getCalcWidth(): any {
2580
        if (this._calcWidth && !isNaN(this.calcPixelWidth)) {
316,800✔
2581
            return this._calcWidth;
311,809✔
2582
        }
2583
        this.cacheCalcWidth();
4,991✔
2584
        return this._calcWidth;
4,991✔
2585
    }
2586

2587

2588
    /**
2589
     * @hidden
2590
     * Returns the width and padding of a header cell.
2591
     */
2592
    public getHeaderCellWidths() {
2593
        return this.grid.getHeaderCellWidth(this.headerCell.nativeElement);
29✔
2594
    }
2595

2596
    /**
2597
     * @hidden
2598
     * Returns the size (in pixels) of the longest currently visible cell, including the header cell.
2599
     * ```typescript
2600
     * @ViewChild('grid') grid: IgxGridComponent;
2601
     *
2602
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2603
     * let size = column.getLargestCellWidth();
2604
     * ```
2605
     * @memberof IgxColumnComponent
2606
     */
2607
    public getLargestCellWidth(): string {
2608
        const range = this.grid.document.createRange();
25✔
2609
        const largest = new Map<number, number>();
25✔
2610

2611
        if (this._cells.length > 0) {
25✔
2612
            const cellsContentWidths = [];
25✔
2613
            this._cells.forEach((cell) => cellsContentWidths.push(cell.calculateSizeToFit(range)));
270✔
2614

2615
            const index = cellsContentWidths.indexOf(Math.max(...cellsContentWidths));
25✔
2616
            const cellStyle = this.grid.document.defaultView.getComputedStyle(this._cells[index].nativeElement);
25✔
2617
            const cellPadding = parseFloat(cellStyle.paddingLeft) + parseFloat(cellStyle.paddingRight) +
25✔
2618
                parseFloat(cellStyle.borderLeftWidth) + parseFloat(cellStyle.borderRightWidth);
2619

2620
            largest.set(Math.max(...cellsContentWidths), cellPadding);
25✔
2621
        }
2622

2623
        if (this.headerCell && this.autosizeHeader) {
25✔
2624
            const headerCellWidths = this.getHeaderCellWidths();
24✔
2625
            largest.set(headerCellWidths.width, headerCellWidths.padding);
24✔
2626
        }
2627

2628
        const largestCell = Math.max(...Array.from(largest.keys()));
25✔
2629
        const width = Math.ceil(largestCell + largest.get(largestCell));
25✔
2630

2631
        if (Number.isNaN(width)) {
25!
UNCOV
2632
            return this.width;
×
2633
        } else {
2634
            return width + 'px';
25✔
2635
        }
2636
    }
2637

2638
    /**
2639
     * @hidden
2640
     */
2641
    public getCellWidth() {
2642
        const colWidth = this.width;
1,226,796✔
2643
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
1,226,796✔
2644

2645
        if (this.columnLayoutChild) {
1,226,796!
UNCOV
2646
            return '';
×
2647
        }
2648

2649
        if (colWidth && !isPercentageWidth) {
1,226,796✔
2650

2651
            let cellWidth = colWidth;
1,214,741✔
2652
            if (typeof cellWidth !== 'string' || cellWidth.endsWith('px') === false) {
1,214,741✔
2653
                cellWidth += 'px';
12,471✔
2654
            }
2655

2656
            return cellWidth;
1,214,741✔
2657
        } else {
2658
            return colWidth;
12,055✔
2659
        }
2660
    }
2661

2662
    /**
2663
     * @hidden
2664
     */
2665
    public populateVisibleIndexes() { }
2666

2667
    protected getColumnSizesString(children: QueryList<IgxColumnComponent>): string {
2668
        const res = this.getFilledChildColumnSizes(children);
13,167✔
2669
        return res.join(' ');
13,167✔
2670
    }
2671

2672
    /**
2673
     * @hidden
2674
     * @internal
2675
     */
2676
    public getConstrainedSizePx(newSize) {
2677
        if (this.maxWidth && newSize >= this.maxWidthPx) {
423,166✔
2678
            this.widthConstrained = true;
113✔
2679
            return this.maxWidthPx;
113✔
2680
        } else if (this.minWidth && newSize <= this.userSetMinWidthPx) {
423,053✔
2681
            this.widthConstrained = true;
173✔
2682
            return this.userSetMinWidthPx;
173✔
2683
        } else if (!this.minWidth && (!this.widthSetByUser || this.width === 'fit-content') && !this.grid.columnWidthSetByUser && (!newSize || newSize <= this.grid.minColumnWidth)) {
422,880✔
2684
            return this.grid.minColumnWidth;
119,283✔
2685
        } else {
2686
            this.widthConstrained = false;
303,597✔
2687
            return newSize;
303,597✔
2688
        }
2689
    }
2690

2691
    /**
2692
     * @hidden
2693
     * @internal
2694
     */
2695
    protected cacheCalcWidth(): any {
2696
        const colWidth = this.width;
368,648✔
2697
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
368,648✔
2698
        const isAutoWidth = colWidth && typeof colWidth === 'string' && colWidth === 'fit-content';
368,648✔
2699
        if (isPercentageWidth && this.grid.isColumnWidthSum) {
368,648✔
2700
            this._calcWidth = this.userSetMinWidthPx ? this.userSetMinWidthPx : this.grid.minColumnWidth;
33!
2701
        } else if (isPercentageWidth) {
368,615✔
2702
            const currentCalcWidth = parseFloat(colWidth) / 100 * this.grid.calcWidth;
982✔
2703
            this._calcWidth = this.grid.calcWidth ? this.getConstrainedSizePx(currentCalcWidth) : 0;
982✔
2704
        } else if (!colWidth || isAutoWidth && !this.autoSize) {
367,633✔
2705
            // no width
2706
            const currentCalcWidth = this.defaultWidth || this.grid.getPossibleColumnWidth();
26,364✔
2707
            this._calcWidth = this.getConstrainedSizePx(parseFloat(currentCalcWidth));
26,364✔
2708
        } else {
2709
            let possibleColumnWidth = '';
341,269✔
2710
            if (!this.widthSetByUser && this.userSetMinWidthPx && this.userSetMinWidthPx < this.grid.minColumnWidth) {
341,269✔
2711
                possibleColumnWidth = this.defaultWidth = this.grid.getPossibleColumnWidth();
59✔
2712
            } else {
2713
                possibleColumnWidth = this.width;
341,210✔
2714
            }
2715

2716
            const currentCalcWidth = parseFloat(possibleColumnWidth);
341,269✔
2717
            this._calcWidth = this.getConstrainedSizePx(currentCalcWidth);
341,269✔
2718
        }
2719
        this.calcPixelWidth = parseFloat(this._calcWidth);
368,648✔
2720
    }
2721

2722
    /**
2723
     * @hidden
2724
     * @internal
2725
     */
2726
    protected setExpandCollapseState() {
2727
        this.children.filter(col => (col.visibleWhenCollapsed !== undefined)).forEach(c => {
295✔
2728
            if (!this.collapsible) {
270✔
2729
                c.hidden = this.hidden; return;
2✔
2730
            }
2731
            c.hidden = this._expanded ? c.visibleWhenCollapsed : !c.visibleWhenCollapsed;
268✔
2732
        });
2733
    }
2734
    /**
2735
     * @hidden
2736
     * @internal
2737
     */
2738
    protected checkCollapsibleState() {
2739
        if (!this.children) {
2,481!
UNCOV
2740
            return false;
×
2741
        }
2742
        const cols = this.children.map(child => child.visibleWhenCollapsed);
6,113✔
2743
        return (cols.some(c => c === true) && cols.some(c => c === false));
3,756✔
2744
    }
2745

2746
    /**
2747
     * @hidden
2748
     */
2749
    public get pinnable() {
2750
        return (this.grid as any)._init || !this.pinned;
406✔
2751
    }
2752

2753
    /**
2754
     * @hidden
2755
     */
2756
    public get applySelectableClass(): boolean {
2757
        return this._applySelectableClass;
11,279✔
2758
    }
2759

2760
    /**
2761
     * @hidden
2762
     */
2763
    public set applySelectableClass(value: boolean) {
2764
        if (this.selectable) {
15✔
2765
            this._applySelectableClass = value;
13✔
2766
        }
2767
    }
2768
}
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