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

IgniteUI / igniteui-angular / 14101962945

27 Mar 2025 08:22AM UTC coverage: 91.596% (-0.07%) from 91.669%
14101962945

push

github

web-flow
fix(circular-progress): make sure that the fill-color-default can be used by the user and flip the gradient for star and end to follow the progressbar progress direction (#15560)

13358 of 15619 branches covered (85.52%)

26920 of 29390 relevant lines covered (91.6%)

33937.04 hits per line

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

97.32
/projects/igniteui-angular/src/lib/grids/columns/column.component.ts
1
import { Subject } from 'rxjs';
2
import { isEqual } from 'lodash-es';
3
import {
4
    AfterContentInit,
5
    ChangeDetectorRef,
6
    ChangeDetectionStrategy,
7
    Component,
8
    ContentChild,
9
    ContentChildren,
10
    Input,
11
    QueryList,
12
    TemplateRef,
13
    Output,
14
    EventEmitter,
15
    OnDestroy,
16
    Inject,
17
    Optional,
18
    Self,
19
    booleanAttribute,
20
} from '@angular/core';
21
import { notifyChanges } from '../watch-changes';
22
import { WatchColumnChanges } from '../watch-changes';
23
import { GridColumnDataType } from '../../data-operations/data-util';
24
import {
25
    IgxFilteringOperand,
26
    IgxBooleanFilteringOperand,
27
    IgxNumberFilteringOperand,
28
    IgxDateFilteringOperand,
29
    IgxStringFilteringOperand,
30
    IgxDateTimeFilteringOperand,
31
    IgxTimeFilteringOperand
32
} from '../../data-operations/filtering-condition';
33
import { ISortingStrategy, DefaultSortingStrategy } from '../../data-operations/sorting-strategy';
34
import { IgxRowDirective } from '../row.directive';
35
import { FilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree';
36
import { CellType, ColumnType, GridType, IgxCellTemplateContext, IgxColumnTemplateContext, IgxSummaryTemplateContext, IGX_GRID_BASE } from '../common/grid.interface';
37
import { IgxGridHeaderComponent } from '../headers/grid-header.component';
38
import { IgxGridFilteringCellComponent } from '../filtering/base/grid-filtering-cell.component';
39
import { IgxGridHeaderGroupComponent } from '../headers/grid-header-group.component';
40
import {
41
    IgxSummaryOperand, IgxNumberSummaryOperand, IgxDateSummaryOperand,
42
    IgxSummaryResult, IgxTimeSummaryOperand
43
} from '../summaries/grid-summary';
44
import {
45
    IgxCellTemplateDirective,
46
    IgxCellHeaderTemplateDirective,
47
    IgxCellEditorTemplateDirective,
48
    IgxCollapsibleIndicatorTemplateDirective,
49
    IgxFilterCellTemplateDirective,
50
    IgxSummaryTemplateDirective,
51
    IgxCellValidationErrorDirective
52
} from './templates.directive';
53
import { MRLResizeColumnInfo, MRLColumnSizeInfo, IColumnPipeArgs, IColumnEditorOptions } from './interfaces';
54
import { DropPosition } from '../moving/moving.service';
55
import { IColumnVisibilityChangingEventArgs, IPinColumnCancellableEventArgs, IPinColumnEventArgs } from '../common/events';
56
import { isConstructor, PlatformUtil } from '../../core/utils';
57
import { IgxGridCell } from '../grid-public-cell';
58
import { NG_VALIDATORS, Validator } from '@angular/forms';
59
import { Size } from '../common/enums';
60
import { ExpressionsTreeUtil } from '../../data-operations/expressions-tree-util';
61

62
const DEFAULT_DATE_FORMAT = 'mediumDate';
3✔
63
const DEFAULT_TIME_FORMAT = 'mediumTime';
3✔
64
const DEFAULT_DATE_TIME_FORMAT = 'medium';
3✔
65
const DEFAULT_DIGITS_INFO = '1.0-3';
3✔
66

67
/* blazorElement */
68
/* contentParent: ColumnGroup */
69
/* wcElementTag: igc-column */
70
/* additionalIdentifier: Field */
71
/* blazorIndirectRender */
72
/**
73
 * **Ignite UI for Angular Column** -
74
 * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid#columns-configuration)
75
 *
76
 * The Ignite UI Column is used within an `igx-grid` element to define what data the column will show. Features such as sorting,
77
 * filtering & editing are enabled at the column level.  You can also provide a template containing custom content inside
78
 * the column using `ng-template` which will be used for all cells within the column.
79
 *
80
 * @igxParent IgxGridComponent, IgxTreeGridComponent, IgxHierarchicalGridComponent, IgxPivotGridComponent, IgxRowIslandComponent, IgxColumnGroupComponent, IgxColumnLayoutComponent
81
 */
82
@Component({
83
    changeDetection: ChangeDetectionStrategy.OnPush,
84
    selector: 'igx-column',
85
    template: ``,
86
    standalone: true
87
})
88
export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnType {
3✔
89
    /**
90
     * Sets/gets the `field` value.
91
     * ```typescript
92
     * let columnField = this.column.field;
93
     * ```
94
     * ```html
95
     * <igx-column [field] = "'ID'"></igx-column>
96
     * ```
97
     *
98
     * @memberof IgxColumnComponent
99
     */
100
    @Input()
101
    public set field(value: string) {
102
        this._field = value;
28,131✔
103
        this.hasNestedPath = value?.includes('.');
28,131✔
104
    }
105
    public get field(): string {
106
        return this._field;
20,877,849✔
107
    }
108

109

110
    /**
111
     * @hidden @internal
112
     */
113
    public validators: Validator[] = [];
29,134✔
114

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

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

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

226
        if (this.isPrimaryColumn && (rowEditable || hasTransactions)) {
2,415,432✔
227
            return false;
99,079✔
228
        }
229

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

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

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

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

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

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

407
    /**
408
     * @hidden
409
     */
410
    @Output()
411
    public hiddenChange = new EventEmitter<boolean>();
29,134✔
412

413
    /** @hidden */
414
    @Output()
415
    public expandedChange = new EventEmitter<boolean>();
29,134✔
416

417
    /** @hidden */
418
    @Output()
419
    public collapsibleChange = new EventEmitter<boolean>();
29,134✔
420
    /** @hidden */
421
    @Output()
422
    public visibleWhenCollapsedChange = new EventEmitter<boolean>();
29,134✔
423

424
    /** @hidden */
425
    @Output()
426
    public columnChange = new EventEmitter<void>();
29,134✔
427

428
    /**
429
     * Gets whether the hiding is disabled.
430
     * ```typescript
431
     * let isHidingDisabled =  this.column.disableHiding;
432
     * ```
433
     *
434
     * @memberof IgxColumnComponent
435
     */
436
    @notifyChanges()
437
    @WatchColumnChanges()
438
    @Input({ transform: booleanAttribute })
439
    public disableHiding = false;
29,134✔
440
    /**
441
     * Gets whether the pinning is disabled.
442
     * ```typescript
443
     * let isPinningDisabled =  this.column.disablePinning;
444
     * ```
445
     *
446
     * @memberof IgxColumnComponent
447
     */
448
    @notifyChanges()
449
    @WatchColumnChanges()
450
    @Input({ transform: booleanAttribute })
451
    public disablePinning = false;
29,134✔
452

453
    /**
454
     * Gets the `width` of the column.
455
     * ```typescript
456
     * let columnWidth = this.column.width;
457
     * ```
458
     *
459
     * @memberof IgxColumnComponent
460
     */
461
    @notifyChanges(true)
462
    @WatchColumnChanges()
463
    @Input()
464
    public get width(): string {
465
        const isAutoWidth = this._width && typeof this._width === 'string' && this._width === 'auto';
2,144,562✔
466
        if (isAutoWidth) {
2,144,562✔
467
            if (!this.autoSize) {
22,862✔
468
                return 'fit-content';
12,003✔
469
            } else {
470
                return this.autoSize + 'px';
10,859✔
471
            }
472

473
        }
474
        return this.widthSetByUser ? this._width : this.defaultWidth;
2,121,700✔
475
    }
476

477
    /**
478
     * Sets the `width` of the column.
479
     * ```html
480
     * <igx-column [width] = "'25%'"></igx-column>
481
     * ```
482
     *
483
     * Two-way data binding.
484
     * ```html
485
     * <igx-column [(width)]="model.columns[0].width"></igx-column>
486
     * ```
487
     *
488
     * @memberof IgxColumnComponent
489
     */
490
    public set width(value: string) {
491
        if (value) {
16,018✔
492
            this._calcWidth = null;
13,415✔
493
            this.calcPixelWidth = NaN;
13,415✔
494
            this.widthSetByUser = true;
13,415✔
495
            // width could be passed as number from the template
496
            // host bindings are not px affixed so we need to ensure we affix simple number strings
497
            if (typeof (value) === 'number' || value.match(/^[0-9]*$/)) {
13,415✔
498
                value = value + 'px';
877✔
499
            }
500
            if (value === 'fit-content') {
13,415✔
501
                value = 'auto';
1✔
502
            }
503
            this._width = value;
13,415✔
504
            if (this.grid) {
13,415✔
505
                this.cacheCalcWidth();
13,415✔
506
            }
507
            this.widthChange.emit(this._width);
13,415✔
508
        }
509
    }
510

511
    /** @hidden @internal **/
512
    public autoSize: number;
513

514
    /**
515
     * Sets/gets the maximum `width` of the column.
516
     * ```typescript
517
     * let columnMaxWidth = this.column.width;
518
     * ```
519
     * ```html
520
     * <igx-column [maxWidth] = "'150px'"></igx-column>
521
     * ```
522
     *
523
     * @memberof IgxColumnComponent
524
     */
525
    @WatchColumnChanges()
526
    @Input()
527
    public set maxWidth(value: string) {
528
        this._maxWidth = value;
1,866✔
529

530
        this.grid.notifyChanges(true);
1,866✔
531
    }
532
    public get maxWidth(): string {
533
        return this._maxWidth;
560,533✔
534
    }
535
    /**
536
     * Sets/gets the class selector of the column header.
537
     * ```typescript
538
     * let columnHeaderClass = this.column.headerClasses;
539
     * ```
540
     * ```html
541
     * <igx-column [headerClasses] = "'column-header'"></igx-column>
542
     * ```
543
     *
544
     * @memberof IgxColumnComponent
545
     */
546
    @notifyChanges()
547
    @WatchColumnChanges()
548
    @Input()
549
    public headerClasses = '';
29,134✔
550

551
    /**
552
     * Sets conditional style properties on the column header.
553
     * Similar to `ngStyle` it accepts an object literal where the keys are
554
     * the style properties and the value is the expression to be evaluated.
555
     * ```typescript
556
     * styles = {
557
     *  background: 'royalblue',
558
     *  color: (column) => column.pinned ? 'red': 'inherit'
559
     * }
560
     * ```
561
     * ```html
562
     * <igx-column [headerStyles]="styles"></igx-column>
563
     * ```
564
     *
565
     * @memberof IgxColumnComponent
566
     */
567
    @notifyChanges()
568
    @WatchColumnChanges()
569
    @Input()
570
    public headerStyles = null;
29,134✔
571

572
    /**
573
     * Sets/gets the class selector of the column group header.
574
     * ```typescript
575
     * let columnHeaderClass = this.column.headerGroupClasses;
576
     * ```
577
     * ```html
578
     * <igx-column [headerGroupClasses] = "'column-group-header'"></igx-column>
579
     * ```
580
     *
581
     * @memberof IgxColumnComponent
582
     */
583
    @notifyChanges()
584
    @WatchColumnChanges()
585
    @Input()
586
    public headerGroupClasses = '';
29,134✔
587

588
    /**
589
     * Sets conditional style properties on the column header group wrapper.
590
     * Similar to `ngStyle` it accepts an object literal where the keys are
591
     * the style properties and the value is the expression to be evaluated.
592
     * ```typescript
593
     * styles = {
594
     *  background: 'royalblue',
595
     *  color: (column) => column.pinned ? 'red': 'inherit'
596
     * }
597
     * ```
598
     * ```html
599
     * <igx-column [headerGroupStyles]="styles"></igx-column>
600
     * ```
601
     *
602
     * @memberof IgxColumnComponent
603
     */
604
    @notifyChanges()
605
    @WatchColumnChanges()
606
    @Input()
607
    public headerGroupStyles = null;
29,134✔
608

609
    /* treatAsRef */
610
    /**
611
     * Sets a conditional class selector of the column cells.
612
     * Accepts an object literal, containing key-value pairs,
613
     * where the key is the name of the CSS class, while the
614
     * value is either a callback function that returns a boolean,
615
     * or boolean, like so:
616
     * ```typescript
617
     * callback = (rowData, columnKey, cellValue, rowIndex) => { return rowData[columnKey] > 6; }
618
     * cellClasses = { 'className' : this.callback };
619
     * ```
620
     * ```html
621
     * <igx-column [cellClasses] = "cellClasses"></igx-column>
622
     * <igx-column [cellClasses] = "{'class1' : true }"></igx-column>
623
     * ```
624
     *
625
     * @memberof IgxColumnComponent
626
     */
627
    @notifyChanges()
628
    @WatchColumnChanges()
629
    @Input()
630
    public cellClasses: any;
631

632
    /* treatAsRef */
633
    /**
634
     * Sets conditional style properties on the column cells.
635
     * Similar to `ngStyle` it accepts an object literal where the keys are
636
     * the style properties and the value is the expression to be evaluated.
637
     * As with `cellClasses` it accepts a callback function.
638
     * ```typescript
639
     * styles = {
640
     *  background: 'royalblue',
641
     *  color: (rowData, columnKey, cellValue, rowIndex) => value.startsWith('Important') ? 'red': 'inherit'
642
     * }
643
     * ```
644
     * ```html
645
     * <igx-column [cellStyles]="styles"></igx-column>
646
     * ```
647
     *
648
     * @memberof IgxColumnComponent
649
     */
650
    @notifyChanges()
651
    @WatchColumnChanges()
652
    @Input()
653
    public cellStyles = null;
29,134✔
654

655
    /* blazorAlternateType: CellValueFormatterEventHandler */
656
    /* blazorOnlyScript */
657
    /**
658
     * Applies display format to cell values in the column. Does not modify the underlying data.
659
     *
660
     * @remarks
661
     * Note: As the formatter is used in places like the Excel style filtering dialog, in certain
662
     * scenarios (remote filtering for example), the row data argument can be `undefined`.
663
     *
664
     *
665
     * In this example, we check to see if the column name is Salary, and then provide a method as the column formatter
666
     * to format the value into a currency string.
667
     *
668
     * @example
669
     * ```typescript
670
     * columnInit(column: IgxColumnComponent) {
671
     *   if (column.field == "Salary") {
672
     *     column.formatter = (salary => this.format(salary));
673
     *   }
674
     * }
675
     *
676
     * format(value: number) : string {
677
     *   return formatCurrency(value, "en-us", "$");
678
     * }
679
     * ```
680
     *
681
     * @example
682
     * ```typescript
683
     * const column = this.grid.getColumnByName('Address');
684
     * const addressFormatter = (address: string, rowData: any) => data.privacyEnabled ? 'unknown' : address;
685
     * column.formatter = addressFormatter;
686
     * ```
687
     *
688
     * @memberof IgxColumnComponent
689
     */
690
    @notifyChanges()
691
    @WatchColumnChanges()
692
    @Input()
693
    public formatter: (value: any, rowData?: any) => any;
694

695
    /* blazorAlternateType: SummaryValueFormatterEventHandler */
696
    /* blazorOnlyScript */
697
    /* forceCastDelegate */
698
    /**
699
     * The summaryFormatter is used to format the display of the column summaries.
700
     *
701
     * In this example, we check to see if the column name is OrderDate, and then provide a method as the summaryFormatter
702
     * to change the locale for the dates to 'fr-FR'. The summaries with the count key are skipped so they are displayed as numbers.
703
     *
704
     * ```typescript
705
     * columnInit(column: IgxColumnComponent) {
706
     *   if (column.field == "OrderDate") {
707
     *     column.summaryFormatter = this.summaryFormat;
708
     *   }
709
     * }
710
     *
711
     * summaryFormat(summary: IgxSummaryResult, summaryOperand: IgxSummaryOperand): string {
712
     *   const result = summary.summaryResult;
713
     *   if(summaryResult.key !== 'count' && result !== null && result !== undefined) {
714
     *      const pipe = new DatePipe('fr-FR');
715
     *      return pipe.transform(result,'mediumDate');
716
     *   }
717
     *   return result;
718
     * }
719
     * ```
720
     *
721
     * @memberof IgxColumnComponent
722
     */
723
    @notifyChanges()
724
    @WatchColumnChanges()
725
    @Input()
726
    public summaryFormatter: (summary: IgxSummaryResult, summaryOperand: IgxSummaryOperand) => any;
727

728
    /**
729
     * Sets/gets whether the column filtering should be case sensitive.
730
     * Default value is `true`.
731
     * ```typescript
732
     * let filteringIgnoreCase = this.column.filteringIgnoreCase;
733
     * ```
734
     * ```html
735
     * <igx-column [filteringIgnoreCase] = "false"></igx-column>
736
     * ```
737
     *
738
     * @memberof IgxColumnComponent
739
     */
740
    @WatchColumnChanges()
741
    @Input({ transform: booleanAttribute })
742
    public filteringIgnoreCase = true;
29,134✔
743
    /**
744
     * Sets/gets whether the column sorting should be case sensitive.
745
     * Default value is `true`.
746
     * ```typescript
747
     * let sortingIgnoreCase = this.column.sortingIgnoreCase;
748
     * ```
749
     * ```html
750
     * <igx-column [sortingIgnoreCase] = "false"></igx-column>
751
     * ```
752
     *
753
     * @memberof IgxColumnComponent
754
     */
755
    @WatchColumnChanges()
756
    @Input({ transform: booleanAttribute })
757
    public sortingIgnoreCase = true;
29,134✔
758
    /**
759
     * Sets/gets whether the column is `searchable`.
760
     * Default value is `true`.
761
     * ```typescript
762
     * let isSearchable =  this.column.searchable';
763
     * ```
764
     * ```html
765
     *  <igx-column [searchable] = "false"></igx-column>
766
     * ```
767
     *
768
     * @memberof IgxColumnComponent
769
     */
770
    @notifyChanges()
771
    @WatchColumnChanges()
772
    @Input({ transform: booleanAttribute })
773
    public searchable = true;
29,134✔
774
    /**
775
     * Sets/gets the data type of the column values.
776
     * Default value is `string`.
777
     * ```typescript
778
     * let columnDataType = this.column.dataType;
779
     * ```
780
     * ```html
781
     * <igx-column [dataType] = "'number'"></igx-column>
782
     * ```
783
     *
784
     * @memberof IgxColumnComponent
785
     */
786
    @Input()
787
    public dataType: GridColumnDataType = GridColumnDataType.String;
29,134✔
788

789
    /** @hidden */
790
    @Input()
791
    public collapsibleIndicatorTemplate: TemplateRef<IgxColumnTemplateContext>;
792

793
    /**
794
     * Row index where the current field should end.
795
     * The amount of rows between rowStart and rowEnd will determine the amount of spanning rows to that field
796
     * ```html
797
     * <igx-column-layout>
798
     *   <igx-column [rowEnd]="2" [rowStart]="1" [colStart]="1"></igx-column>
799
     * </igx-column-layout>
800
     * ```
801
     *
802
     * @memberof IgxColumnComponent
803
     */
804
    @Input()
805
    public rowEnd: number;
806

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

821
    /**
822
     * Row index from which the field is starting.
823
     * ```html
824
     * <igx-column-layout>
825
     *   <igx-column [rowStart]="1" [colStart]="1"></igx-column>
826
     * </igx-column-layout>
827
     * ```
828
     *
829
     * @memberof IgxColumnComponent
830
     */
831
    @Input()
832
    public rowStart: number;
833

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

847
    /**
848
     * Sets/gets custom properties provided in additional template context.
849
     *
850
     * ```html
851
     * <igx-column [additionalTemplateContext]="contextObject">
852
     *   <ng-template igxCell let-cell="cell" let-props="additionalTemplateContext">
853
     *      {{ props }}
854
     *   </ng-template>
855
     * </igx-column>
856
     * ```
857
     *
858
     * @memberof IgxColumnComponent
859
     */
860
    @Input()
861
    public additionalTemplateContext: any;
862

863
    /**
864
     * @hidden
865
     */
866
    @Output()
867
    public widthChange = new EventEmitter<string>();
29,134✔
868

869
    /**
870
     * @hidden
871
     */
872
    @Output()
873
    public pinnedChange = new EventEmitter<boolean>();
29,134✔
874
    /**
875
     * @hidden
876
     */
877
    @ContentChild(IgxFilterCellTemplateDirective, { read: IgxFilterCellTemplateDirective })
878
    public filterCellTemplateDirective: IgxFilterCellTemplateDirective;
879
    /**
880
     * @hidden
881
     */
882
    @ContentChild(IgxSummaryTemplateDirective, { read: IgxSummaryTemplateDirective })
883
    protected summaryTemplateDirective: IgxSummaryTemplateDirective;
884
    /**
885
     * @hidden
886
     * @see {@link bodyTemplate}
887
     */
888
    @ContentChild(IgxCellTemplateDirective, { read: IgxCellTemplateDirective })
889
    protected cellTemplate: IgxCellTemplateDirective;
890
    /**
891
     * @hidden
892
     */
893
    @ContentChild(IgxCellValidationErrorDirective, { read: IgxCellValidationErrorDirective })
894
    protected cellValidationErrorTemplate: IgxCellValidationErrorDirective;
895
    /**
896
     * @hidden
897
     */
898
    @ContentChildren(IgxCellHeaderTemplateDirective, { read: IgxCellHeaderTemplateDirective, descendants: false })
899
    protected headTemplate: QueryList<IgxCellHeaderTemplateDirective>;
900
    /**
901
     * @hidden
902
     */
903
    @ContentChild(IgxCellEditorTemplateDirective, { read: IgxCellEditorTemplateDirective })
904
    protected editorTemplate: IgxCellEditorTemplateDirective;
905
    /**
906
     * @hidden
907
     */
908
    @ContentChild(IgxCollapsibleIndicatorTemplateDirective, { read: IgxCollapsibleIndicatorTemplateDirective, static: false })
909
    protected collapseIndicatorTemplate: IgxCollapsibleIndicatorTemplateDirective;
910
    /**
911
     * @hidden
912
     */
913
    public get calcWidth(): any {
914
        return this.getCalcWidth();
237,813✔
915
    }
916

917
    /** @hidden @internal **/
918
    public calcPixelWidth: number;
919

920
    /**
921
     * @hidden
922
     */
923
    public get maxWidthPx() {
924
        const gridAvailableSize = this.grid.calcWidth;
80,999✔
925
        const isPercentageWidth = this.maxWidth && typeof this.maxWidth === 'string' && this.maxWidth.indexOf('%') !== -1;
80,999✔
926
        return isPercentageWidth ? parseFloat(this.maxWidth) / 100 * gridAvailableSize : parseFloat(this.maxWidth);
80,999✔
927
    }
928

929
    /**
930
     * @hidden
931
     */
932
    public get maxWidthPercent() {
933
        const gridAvailableSize = this.grid.calcWidth;
17✔
934
        const isPercentageWidth = this.maxWidth && typeof this.maxWidth === 'string' && this.maxWidth.indexOf('%') !== -1;
17✔
935
        return isPercentageWidth ? parseFloat(this.maxWidth) : parseFloat(this.maxWidth) / gridAvailableSize * 100;
17✔
936
    }
937

938
    /**
939
     * @hidden
940
     */
941
    public get minWidthPx() {
942
        const gridAvailableSize = this.grid.calcWidth;
177✔
943
        const isPercentageWidth = this.minWidth && typeof this.minWidth === 'string' && this.minWidth.indexOf('%') !== -1;
177✔
944
        return isPercentageWidth ? parseFloat(this.minWidth) / 100 * gridAvailableSize : parseFloat(this.minWidth);
177✔
945
    }
946

947
    /**
948
     * @hidden
949
     */
950
    public get userSetMinWidthPx() {
951
        const gridAvailableSize = this.grid.calcWidth;
437,877✔
952
        const isPercentageWidth = this._defaultMinWidth && typeof this._defaultMinWidth === 'string' && this._defaultMinWidth.indexOf('%') !== -1;
437,877✔
953
        return isPercentageWidth ? parseFloat(this._defaultMinWidth) / 100 * gridAvailableSize : parseFloat(this._defaultMinWidth);
437,877✔
954
    }
955

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

965

966
    /**
967
     * Sets/gets the minimum `width` of the column.
968
     * Default value is `88`;
969
     * ```typescript
970
     * let columnMinWidth = this.column.minWidth;
971
     * ```
972
     * ```html
973
     * <igx-column [minWidth] = "'100px'"></igx-column>
974
     * ```
975
     *
976
     * @memberof IgxColumnComponent
977
     */
978
    @notifyChanges()
979
    @WatchColumnChanges()
980
    @Input()
981
    public set minWidth(value: string) {
982
        const minVal = parseFloat(value);
1,486✔
983
        if (Number.isNaN(minVal)) {
1,486✔
984
            return;
45✔
985
        }
986
        this._defaultMinWidth = value;
1,441✔
987
        this.grid.notifyChanges(true);
1,441✔
988
    }
989
    public get minWidth(): string {
990
        return !this._defaultMinWidth ? this.defaultMinWidth : this._defaultMinWidth;
372,180✔
991
    }
992

993
    /** @hidden @internal **/
994
    public get resolvedWidth(): string {
995
        if (this.columnLayoutChild) {
4,116,266!
996
            return '';
×
997
        }
998
        const isAutoWidth = this._width && typeof this._width === 'string' && this._width === 'auto';
4,116,266✔
999
        return isAutoWidth ? this.width : this.calcPixelWidth + 'px';
4,116,266✔
1000
    }
1001

1002
    /**
1003
     * Gets the column index.
1004
     * ```typescript
1005
     * let columnIndex = this.column.index;
1006
     * ```
1007
     *
1008
     * @memberof IgxColumnComponent
1009
     */
1010
    public get index(): number {
1011
        return (this.grid as any)._columns.indexOf(this);
240,438✔
1012
    }
1013

1014
    /**
1015
     * Gets whether the column is `pinned`.
1016
     * ```typescript
1017
     * let isPinned = this.column.pinned;
1018
     * ```
1019
     *
1020
     * @memberof IgxColumnComponent
1021
     */
1022
    @WatchColumnChanges()
1023
    @Input({ transform: booleanAttribute })
1024
    public get pinned(): boolean {
1025
        return this._pinned;
2,269,439✔
1026
    }
1027
    /**
1028
     * Sets whether the column is pinned.
1029
     * Default value is `false`.
1030
     * ```html
1031
     * <igx-column [pinned] = "true"></igx-column>
1032
     * ```
1033
     *
1034
     * Two-way data binding.
1035
     * ```html
1036
     * <igx-column [(pinned)] = "model.columns[0].isPinned"></igx-column>
1037
     * ```
1038
     *
1039
     * @memberof IgxColumnComponent
1040
     */
1041
    public set pinned(value: boolean) {
1042
        if (this._pinned !== value) {
2,823✔
1043
            const isAutoWidth = this.width && typeof this.width === 'string' && this.width === 'fit-content';
564✔
1044
            if (this.grid && this.width && (isAutoWidth || !isNaN(parseInt(this.width, 10)))) {
564✔
1045
                if (value) {
392✔
1046
                    this.pin();
354✔
1047
                } else {
1048
                    this.unpin();
38✔
1049
                }
1050
                return;
392✔
1051
            }
1052
            /* No grid/width available at initialization. `initPinning` in the grid
1053
               will re-init the group (if present)
1054
            */
1055
            this._pinned = value;
172✔
1056
            this.pinnedChange.emit(this._pinned);
172✔
1057
        }
1058
    }
1059

1060
    /* treatAsRef */
1061
    /**
1062
     * Gets the column `summaries`.
1063
     * ```typescript
1064
     * let columnSummaries = this.column.summaries;
1065
     * ```
1066
     *
1067
     * @memberof IgxColumnComponent
1068
     */
1069
    @notifyChanges(true)
1070
    @WatchColumnChanges()
1071
    @Input()
1072
    public get summaries(): any {
1073
        return this._summaries;
64,572✔
1074
    }
1075

1076
    /* treatAsRef */
1077
    /**
1078
     * Sets the column `summaries`.
1079
     * ```typescript
1080
     * this.column.summaries = IgxNumberSummaryOperand;
1081
     * ```
1082
     *
1083
     * @memberof IgxColumnComponent
1084
     */
1085
    public set summaries(classRef: any) {
1086
        if (isConstructor(classRef)) {
24,098✔
1087
            this._summaries = new classRef();
24,092✔
1088
        }
1089

1090
        if (this.grid) {
24,098✔
1091
            this.grid.summaryService.removeSummariesCachePerColumn(this.field);
24,098✔
1092
            this.grid.summaryPipeTrigger++;
24,098✔
1093
            this.grid.summaryService.resetSummaryHeight();
24,098✔
1094
        }
1095
    }
1096

1097
    /**
1098
     * Sets/gets the summary operands to exclude from display.
1099
     * Accepts an array of string keys representing the summary types to disable, such as 'Min', 'Max', 'Count' etc.
1100
     * ```typescript
1101
     * let disabledSummaries = this.column.disabledSummaries;
1102
     * ```
1103
     * ```html
1104
     * <igx-column [disabledSummaries]="['min', 'max', 'average']"></igx-column>
1105
     * ```
1106
     *
1107
     * @memberof IgxColumnComponent
1108
     */
1109
    @WatchColumnChanges()
1110
    @Input()
1111
    public get disabledSummaries(): string[] {
1112
        return this._disabledSummaries;
18,020✔
1113
    }
1114

1115
    public set disabledSummaries(value: string[]) {
1116
        if (isEqual(this._disabledSummaries, value)) {
1,418✔
1117
            return;
1,411✔
1118
        }
1119
        this._disabledSummaries = value;
7✔
1120
        if (this.grid) {
7✔
1121
            this.grid.summaryService.removeSummariesCachePerColumn(this.field);
7✔
1122
            this.grid.summaryPipeTrigger++;
7✔
1123
            this.grid.summaryService.resetSummaryHeight();
7✔
1124
        }
1125
    }
1126

1127
    /**
1128
     * Gets the column `filters`.
1129
     * ```typescript
1130
     * let columnFilters = this.column.filters'
1131
     * ```
1132
     *
1133
     * @memberof IgxColumnComponent
1134
     */
1135
    @Input()
1136
    public get filters(): IgxFilteringOperand {
1137
        return this._filters;
74,617✔
1138
    }
1139
    /**
1140
     * Sets the column `filters`.
1141
     * ```typescript
1142
     * this.column.filters = IgxBooleanFilteringOperand.instance().
1143
     * ```
1144
     *
1145
     * @memberof IgxColumnComponent
1146
     */
1147
    public set filters(instance: IgxFilteringOperand) {
1148
        this._filters = instance;
24,084✔
1149
    }
1150
    /**
1151
     * Gets the column `sortStrategy`.
1152
     * ```typescript
1153
     * let sortStrategy = this.column.sortStrategy
1154
     * ```
1155
     *
1156
     * @memberof IgxColumnComponent
1157
     */
1158
    @Input()
1159
    public get sortStrategy(): ISortingStrategy {
1160
        return this._sortStrategy;
2,852✔
1161
    }
1162
    /**
1163
     * Sets the column `sortStrategy`.
1164
     * ```typescript
1165
     * this.column.sortStrategy = new CustomSortingStrategy().
1166
     * class CustomSortingStrategy extends SortingStrategy {...}
1167
     * ```
1168
     *
1169
     * @memberof IgxColumnComponent
1170
     */
1171
    public set sortStrategy(classRef: ISortingStrategy) {
1172
        this._sortStrategy = classRef;
1,414✔
1173
    }
1174

1175
    /* blazorSuppress */
1176
    /**
1177
     * Gets the function that compares values for grouping.
1178
     * ```typescript
1179
     * let groupingComparer = this.column.groupingComparer'
1180
     * ```
1181
     *
1182
     * @memberof IgxColumnComponent
1183
     */
1184
    @Input()
1185
    public get groupingComparer(): (a: any, b: any, currRec?: any, groupRec?: any) => number {
1186
        return this._groupingComparer;
3,283✔
1187
    }
1188

1189
    /* blazorSuppress */
1190
    /**
1191
     * Sets a custom function to compare values for grouping.
1192
     * Subsequent values in the sorted data that the function returns 0 for are grouped.
1193
     * ```typescript
1194
     * this.column.groupingComparer = (a: any, b: any, currRec?: any, groupRec?: any) => { return a === b ? 0 : -1; }
1195
     * ```
1196
     *
1197
     * @memberof IgxColumnComponent
1198
     */
1199
    public set groupingComparer(funcRef: (a: any, b: any, currRec?: any, groupRec?: any) => number) {
1200
        this._groupingComparer = funcRef;
1,414✔
1201
    }
1202
    /**
1203
     * @hidden @internal
1204
     */
1205
    public get defaultMinWidth(): string {
1206
        if (!this.grid) {
353,317!
1207
            return '80';
×
1208
        }
1209
        switch (this.grid.gridSize) {
353,317✔
1210
            case Size.Medium:
1211
                return '64';
16,776✔
1212
            case Size.Small:
1213
                return '56';
4,184✔
1214
            default:
1215
                return '80';
332,357✔
1216
        }
1217
    }
1218
    /**
1219
     * Returns a reference to the `summaryTemplate`.
1220
     * ```typescript
1221
     * let summaryTemplate = this.column.summaryTemplate;
1222
     * ```
1223
     *
1224
     * @memberof IgxColumnComponent
1225
     */
1226
    @notifyChanges()
1227
    @WatchColumnChanges()
1228
    @Input()
1229
    public get summaryTemplate(): TemplateRef<IgxSummaryTemplateContext> {
1230
        return this._summaryTemplate;
79,862✔
1231
    }
1232
    /**
1233
     * Sets the summary template.
1234
     * ```html
1235
     * <ng-template #summaryTemplate igxSummary let-summaryResults>
1236
     *    <p>{{ summaryResults[0].label }}: {{ summaryResults[0].summaryResult }}</p>
1237
     *    <p>{{ summaryResults[1].label }}: {{ summaryResults[1].summaryResult }}</p>
1238
     * </ng-template>
1239
     * ```
1240
     * ```typescript
1241
     * @ViewChild("'summaryTemplate'", {read: TemplateRef })
1242
     * public summaryTemplate: TemplateRef<any>;
1243
     * this.column.summaryTemplate = this.summaryTemplate;
1244
     * ```
1245
     *
1246
     * @memberof IgxColumnComponent
1247
     */
1248
    public set summaryTemplate(template: TemplateRef<IgxSummaryTemplateContext>) {
1249
        this._summaryTemplate = template;
1,417✔
1250
    }
1251

1252
    /**
1253
     * Returns a reference to the `bodyTemplate`.
1254
     * ```typescript
1255
     * let bodyTemplate = this.column.bodyTemplate;
1256
     * ```
1257
     *
1258
     * @memberof IgxColumnComponent
1259
     */
1260
    @notifyChanges()
1261
    @WatchColumnChanges()
1262
    @Input('cellTemplate')
1263
    public get bodyTemplate(): TemplateRef<IgxCellTemplateContext> {
1264
        return this._bodyTemplate;
1,207,128✔
1265
    }
1266
    /**
1267
     * Sets the body template.
1268
     * ```html
1269
     * <ng-template #bodyTemplate igxCell let-val>
1270
     *    <div style = "background-color: yellowgreen" (click) = "changeColor(val)">
1271
     *       <span> {{val}} </span>
1272
     *    </div>
1273
     * </ng-template>
1274
     * ```
1275
     * ```typescript
1276
     * @ViewChild("'bodyTemplate'", {read: TemplateRef })
1277
     * public bodyTemplate: TemplateRef<any>;
1278
     * this.column.bodyTemplate = this.bodyTemplate;
1279
     * ```
1280
     *
1281
     * @memberof IgxColumnComponent
1282
     */
1283
    public set bodyTemplate(template: TemplateRef<IgxCellTemplateContext>) {
1284
        this._bodyTemplate = template;
1,381✔
1285
    }
1286
    /**
1287
     * Returns a reference to the header template.
1288
     * ```typescript
1289
     * let headerTemplate = this.column.headerTemplate;
1290
     * ```
1291
     *
1292
     * @memberof IgxColumnComponent
1293
     */
1294
    @notifyChanges()
1295
    @WatchColumnChanges()
1296
    @Input()
1297
    public get headerTemplate(): TemplateRef<IgxColumnTemplateContext> {
1298
        return this._headerTemplate;
260,562✔
1299
    }
1300
    /**
1301
     * Sets the header template.
1302
     * Note that the column header height is fixed and any content bigger than it will be cut off.
1303
     * ```html
1304
     * <ng-template #headerTemplate>
1305
     *   <div style = "background-color:black" (click) = "changeColor(val)">
1306
     *       <span style="color:red" >{{column.field}}</span>
1307
     *   </div>
1308
     * </ng-template>
1309
     * ```
1310
     * ```typescript
1311
     * @ViewChild("'headerTemplate'", {read: TemplateRef })
1312
     * public headerTemplate: TemplateRef<any>;
1313
     * this.column.headerTemplate = this.headerTemplate;
1314
     * ```
1315
     *
1316
     * @memberof IgxColumnComponent
1317
     */
1318
    public set headerTemplate(template: TemplateRef<IgxColumnTemplateContext>) {
1319
        this._headerTemplate = template;
5,127✔
1320
    }
1321
    /**
1322
     * Returns a reference to the inline editor template.
1323
     * ```typescript
1324
     * let inlineEditorTemplate = this.column.inlineEditorTemplate;
1325
     * ```
1326
     *
1327
     * @memberof IgxColumnComponent
1328
     */
1329
    @notifyChanges()
1330
    @WatchColumnChanges()
1331
    @Input('cellEditorTemplate')
1332
    public get inlineEditorTemplate(): TemplateRef<IgxCellTemplateContext> {
1333
        return this._inlineEditorTemplate;
5,473✔
1334
    }
1335
    /**
1336
     * Sets the inline editor template.
1337
     * ```html
1338
     * <ng-template #inlineEditorTemplate igxCellEditor let-cell="cell">
1339
     *     <input type="string" [(ngModel)]="cell.value"/>
1340
     * </ng-template>
1341
     * ```
1342
     * ```typescript
1343
     * @ViewChild("'inlineEditorTemplate'", {read: TemplateRef })
1344
     * public inlineEditorTemplate: TemplateRef<any>;
1345
     * this.column.inlineEditorTemplate = this.inlineEditorTemplate;
1346
     * ```
1347
     *
1348
     * @memberof IgxColumnComponent
1349
     */
1350
    public set inlineEditorTemplate(template: TemplateRef<IgxCellTemplateContext>) {
1351
        this._inlineEditorTemplate = template;
1,378✔
1352
    }
1353

1354
    /**
1355
     * Returns a reference to the validation error template.
1356
     * ```typescript
1357
     * let errorTemplate = this.column.errorTemplate;
1358
     * ```
1359
     */
1360
    @notifyChanges()
1361
    @WatchColumnChanges()
1362
    @Input('errorTemplate')
1363
    public get errorTemplate(): TemplateRef<IgxCellTemplateContext> {
1364
        return this._errorTemplate;
1,151,677✔
1365
    }
1366
    /**
1367
     * Sets the error template.
1368
     * ```html
1369
     * <ng-template igxCellValidationError let-cell="cell" #errorTemplate >
1370
     *     <div *ngIf="cell.validation.errors?.['forbiddenName']">
1371
     *      This name is forbidden.
1372
     *     </div>
1373
     * </ng-template>
1374
     * ```
1375
     * ```typescript
1376
     * @ViewChild("'errorTemplate'", {read: TemplateRef })
1377
     * public errorTemplate: TemplateRef<any>;
1378
     * this.column.errorTemplate = this.errorTemplate;
1379
     * ```
1380
     */
1381
    public set errorTemplate(template: TemplateRef<IgxCellTemplateContext>) {
1382
        this._errorTemplate = template;
1,411✔
1383
    }
1384

1385
    /**
1386
     * Returns a reference to the `filterCellTemplate`.
1387
     * ```typescript
1388
     * let filterCellTemplate = this.column.filterCellTemplate;
1389
     * ```
1390
     *
1391
     * @memberof IgxColumnComponent
1392
     */
1393
    @notifyChanges()
1394
    @WatchColumnChanges()
1395
    @Input('filterCellTemplate')
1396
    public get filterCellTemplate(): TemplateRef<IgxColumnTemplateContext> {
1397
        return this._filterCellTemplate;
41,797✔
1398
    }
1399
    /**
1400
     * Sets the quick filter template.
1401
     * ```html
1402
     * <ng-template #filterCellTemplate IgxFilterCellTemplate let-column="column">
1403
     *    <input (input)="onInput()">
1404
     * </ng-template>
1405
     * ```
1406
     * ```typescript
1407
     * @ViewChild("'filterCellTemplate'", {read: TemplateRef })
1408
     * public filterCellTemplate: TemplateRef<any>;
1409
     * this.column.filterCellTemplate = this.filterCellTemplate;
1410
     * ```
1411
     *
1412
     * @memberof IgxColumnComponent
1413
     */
1414
    public set filterCellTemplate(template: TemplateRef<IgxColumnTemplateContext>) {
1415
        this._filterCellTemplate = template;
1,427✔
1416
    }
1417

1418
    /**
1419
     * @hidden @internal
1420
     */
1421
    public get cells(): CellType[] {
1422
        return this.grid.dataView
23✔
1423
            .map((rec, index) => {
1424
                if (!this.grid.isGroupByRecord(rec) && !this.grid.isSummaryRow(rec)) {
1,273✔
1425
                    this.grid.pagingMode === 1 && this.grid.page !== 0 ? index = index + this.grid.perPage * this.grid.page : index = this.grid.dataRowList.first.index + index;
1,273!
1426
                    const cell = new IgxGridCell(this.grid as any, index, this);
1,273✔
1427
                    return cell;
1,273✔
1428
                }
1429
            }).filter(cell => cell);
1,273✔
1430
    }
1431

1432

1433
    /**
1434
     * @hidden @internal
1435
     */
1436
    public get _cells(): CellType[] {
1437
        return this.grid.rowList.filter((row) => row instanceof IgxRowDirective)
2,905✔
1438
            .map((row) => {
1439
                if (row._cells) {
2,905✔
1440
                    return row._cells.filter((cell) => cell.columnIndex === this.index);
17,373✔
1441
                }
1442
            }).reduce((a, b) => a.concat(b), []);
2,905✔
1443
    }
1444

1445
    /**
1446
     * Gets the column visible index.
1447
     * If the column is not visible, returns `-1`.
1448
     * ```typescript
1449
     * let visibleColumnIndex =  this.column.visibleIndex;
1450
     * ```
1451
     *
1452
     * @memberof IgxColumnComponent
1453
     */
1454
    public get visibleIndex(): number {
1455
        if (!isNaN(this._vIndex)) {
5,429,234✔
1456
            return this._vIndex;
4,984,107✔
1457
        }
1458
        const unpinnedColumns = this.grid.unpinnedColumns.filter(c => !c.columnGroup);
4,402,284✔
1459
        const pinnedColumns = this.grid.pinnedColumns.filter(c => !c.columnGroup);
445,127✔
1460

1461
        let col = this;
445,127✔
1462
        let vIndex = -1;
445,127✔
1463

1464
        if (this.columnGroup) {
445,127✔
1465
            col = this.allChildren.filter(c => !c.columnGroup && !c.hidden)[0] as any;
24,338✔
1466
        }
1467
        if (this.columnLayoutChild) {
445,127✔
1468
            return this.parent.childrenVisibleIndexes.find(x => x.column === this).index;
861,915✔
1469
        }
1470

1471
        if (!this.pinned) {
111,940✔
1472
            const indexInCollection = unpinnedColumns.indexOf(col);
109,751✔
1473
            vIndex = indexInCollection === -1 ?
109,751✔
1474
                -1 :
1475
                (this.grid.isPinningToStart ?
109,135✔
1476
                    pinnedColumns.length + indexInCollection :
1477
                    indexInCollection);
1478
        } else {
1479
            const indexInCollection = pinnedColumns.indexOf(col);
2,189✔
1480
            vIndex = this.grid.isPinningToStart ?
2,189✔
1481
                indexInCollection :
1482
                unpinnedColumns.length + indexInCollection;
1483
        }
1484
        this._vIndex = vIndex;
111,940✔
1485
        return vIndex;
111,940✔
1486
    }
1487

1488
    /* blazorCSSuppress - Blazor doesn't carry over the ColumnType interface + should translate as static bool value */
1489
    /**
1490
     * Returns a boolean indicating if the column is a `ColumnGroup`.
1491
     * ```typescript
1492
     * let columnGroup =  this.column.columnGroup;
1493
     * ```
1494
     *
1495
     * @memberof IgxColumnComponent
1496
     */
1497
    public get columnGroup() {
1498
        return false;
8,072,062✔
1499
    }
1500

1501
    /* blazorCSSuppress - Blazor doesn't carry over the ColumnType interface + should translate as static bool value */
1502
    /**
1503
     * Returns a boolean indicating if the column is a `ColumnLayout` for multi-row layout.
1504
     * ```typescript
1505
     * let columnGroup =  this.column.columnGroup;
1506
     * ```
1507
     *
1508
     * @memberof IgxColumnComponent
1509
     */
1510
    public get columnLayout() {
1511
        return false;
20,257,406✔
1512
    }
1513

1514
    /**
1515
     * Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
1516
     * ```typescript
1517
     * let columnLayoutChild =  this.column.columnLayoutChild;
1518
     * ```
1519
     *
1520
     * @memberof IgxColumnComponent
1521
     */
1522
    public get columnLayoutChild(): boolean {
1523
        return this.parent && this.parent.columnLayout;
16,979,519✔
1524
    }
1525

1526
    /**
1527
     * A list containing all the child columns under this column (if any).
1528
     * Empty without children or if this column is not Group or Layout.
1529
     */
1530
    public get childColumns(): ColumnType[] {
1531
        return [];
×
1532
    }
1533

1534
    /** @hidden @internal **/
1535
    public get allChildren(): IgxColumnComponent[] {
1536
        return [];
310✔
1537
    }
1538
    /**
1539
     * Returns the level of the column in a column group.
1540
     * Returns `0` if the column doesn't have a `parent`.
1541
     * ```typescript
1542
     * let columnLevel =  this.column.level;
1543
     * ```
1544
     *
1545
     * @memberof IgxColumnComponent
1546
     */
1547
    public get level() {
1548
        let ptr = this.parent;
473,664✔
1549
        let lvl = 0;
473,664✔
1550

1551
        while (ptr) {
473,664✔
1552
            lvl++;
144,857✔
1553
            ptr = ptr.parent;
144,857✔
1554
        }
1555
        return lvl;
473,664✔
1556
    }
1557

1558
    /** @hidden @internal **/
1559
    public get isLastPinned(): boolean {
1560
        return this.grid.isPinningToStart &&
1,095,720✔
1561
            this.grid.pinnedColumns[this.grid.pinnedColumns.length - 1] === this;
1562
    }
1563

1564
    /** @hidden @internal **/
1565
    public get isFirstPinned(): boolean {
1566
        const pinnedCols = this.grid.pinnedColumns.filter(x => !x.columnGroup);
1,011,375✔
1567
        return !this.grid.isPinningToStart && pinnedCols[0] === this;
1,011,375✔
1568
    }
1569

1570
    /** @hidden @internal **/
1571
    public get rightPinnedOffset(): string {
1572
        return this.pinned && !this.grid.isPinningToStart ?
729,751✔
1573
            - this.grid.pinnedWidth - this.grid.headerFeaturesWidth + 'px' :
1574
            null;
1575
    }
1576

1577
    /** @hidden @internal **/
1578
    public get gridRowSpan(): number {
1579
        return this.rowEnd && this.rowStart ? this.rowEnd - this.rowStart : 1;
1,274✔
1580
    }
1581
    /** @hidden @internal **/
1582
    public get gridColumnSpan(): number {
1583
        return this.colEnd && this.colStart ? this.colEnd - this.colStart : 1;
691,077✔
1584
    }
1585

1586
    /**
1587
     * Indicates whether the column will be visible when its parent is collapsed.
1588
     * ```html
1589
     * <igx-column-group>
1590
     *   <igx-column [visibleWhenCollapsed]="true"></igx-column>
1591
     * </igx-column-group>
1592
     * ```
1593
     *
1594
     * @memberof IgxColumnComponent
1595
     */
1596
    @notifyChanges(true)
1597
    @Input({ transform: booleanAttribute })
1598
    public set visibleWhenCollapsed(value: boolean) {
1599
        this._visibleWhenCollapsed = value;
1,760✔
1600
        this.visibleWhenCollapsedChange.emit(this._visibleWhenCollapsed);
1,760✔
1601
        if (this.parent) {
1,760✔
1602
            this.parent?.setExpandCollapseState?.();
26✔
1603
        }
1604
    }
1605

1606
    public get visibleWhenCollapsed(): boolean {
1607
        return this._visibleWhenCollapsed;
9,479✔
1608
    }
1609

1610
    /* mustSetInCodePlatforms: WebComponents;Blazor;React */
1611
    /**
1612
     * @remarks
1613
     * Pass optional parameters for DatePipe and/or DecimalPipe to format the display value for date and numeric columns.
1614
     * Accepts an `IColumnPipeArgs` object with any of the `format`, `timezone` and `digitsInfo` properties.
1615
     * For more details see https://angular.io/api/common/DatePipe and https://angular.io/api/common/DecimalPipe
1616
     * @example
1617
     * ```typescript
1618
     * const pipeArgs: IColumnPipeArgs = {
1619
     *      format: 'longDate',
1620
     *      timezone: 'UTC',
1621
     *      digitsInfo: '1.1-2'
1622
     * }
1623
     * ```
1624
     * ```html
1625
     * <igx-column dataType="date" [pipeArgs]="pipeArgs"></igx-column>
1626
     * <igx-column dataType="number" [pipeArgs]="pipeArgs"></igx-column>
1627
     * ```
1628
     * @memberof IgxColumnComponent
1629
     */
1630
    @notifyChanges()
1631
    @WatchColumnChanges()
1632
    @Input()
1633
    public set pipeArgs(value: IColumnPipeArgs) {
1634
        this._columnPipeArgs = Object.assign(this._columnPipeArgs, value);
1,450✔
1635
        this.grid.summaryService.clearSummaryCache();
1,450✔
1636
        this.grid.pipeTrigger++;
1,450✔
1637
    }
1638
    /* mustSetInCodePlatforms: WebComponents;Blazor */
1639
    public get pipeArgs(): IColumnPipeArgs {
1640
        return this._columnPipeArgs;
1,662,240✔
1641
    }
1642

1643
    /**
1644
     * Pass optional properties for the default column editors.
1645
     * @remarks
1646
     * Options may be applicable only to specific column type editors.
1647
     * @example
1648
     * ```typescript
1649
     * const editorOptions: IColumnEditorOptions = {
1650
     *      dateTimeFormat: 'MM/dd/YYYY',
1651
     * }
1652
     * ```
1653
     * ```html
1654
     * <igx-column dataType="date" [editorOptions]="editorOptions"></igx-column>
1655
     * ```
1656
     * @memberof IgxColumnComponent
1657
     */
1658
    @notifyChanges()
1659
    @WatchColumnChanges()
1660
    @Input()
1661
    public set editorOptions(value: IColumnEditorOptions) {
1662
        this._editorOptions = value;
1,421✔
1663
    }
1664
    public get editorOptions(): IColumnEditorOptions {
1665
        return this._editorOptions;
4,571✔
1666
    }
1667

1668
    /**
1669
     * @hidden
1670
     * @internal
1671
     */
1672
    public get collapsible() {
1673
        return false;
×
1674
    }
1675
    public set collapsible(_value: boolean) { }
1676

1677
    /**
1678
     * @hidden
1679
     * @internal
1680
     */
1681
    public get expanded() {
1682
        return true;
×
1683
    }
1684
    public set expanded(_value: boolean) { }
1685

1686
    /**
1687
     * @hidden
1688
     */
1689
    public defaultWidth: string;
1690

1691
    /**
1692
     * @hidden
1693
     */
1694
    public widthSetByUser: boolean;
1695

1696
    /**
1697
     * @hidden
1698
     */
1699
    public hasNestedPath: boolean;
1700

1701
    /**
1702
     * @hidden
1703
     * @internal
1704
     */
1705
    public defaultTimeFormat = 'hh:mm:ss a';
29,134✔
1706

1707
    /**
1708
     * @hidden
1709
     * @internal
1710
     */
1711
    public defaultDateTimeFormat = 'dd/MM/yyyy HH:mm:ss a';
29,134✔
1712

1713

1714
    /**
1715
     * Returns the filteringExpressionsTree of the column.
1716
     * ```typescript
1717
     * let tree =  this.column.filteringExpressionsTree;
1718
     * ```
1719
     *
1720
     * @memberof IgxColumnComponent
1721
     */
1722
    public get filteringExpressionsTree(): FilteringExpressionsTree {
1723
        return ExpressionsTreeUtil.find(this.grid.filteringExpressionsTree, this.field) as FilteringExpressionsTree;
64,203✔
1724
    }
1725

1726
    /* alternateName: parentColumn */
1727
    /**
1728
     * Sets/gets the parent column.
1729
     * ```typescript
1730
     * let parentColumn = this.column.parent;
1731
     * ```
1732
     * ```typescript
1733
     * this.column.parent = higherLevelColumn;
1734
     * ```
1735
     *
1736
     * @memberof IgxColumnComponent
1737
     */
1738
    public parent = null;
29,134✔
1739

1740
    /* blazorSuppress */
1741
    /**
1742
     * Sets/gets the children columns.
1743
     * ```typescript
1744
     * let columnChildren = this.column.children;
1745
     * ```
1746
     *
1747
     * @deprecated in version 18.1.0. Use the `childColumns` property instead.
1748
     */
1749
    public children: QueryList<IgxColumnComponent>;
1750
    /**
1751
     * @hidden
1752
     */
1753
    public destroy$ = new Subject<any>();
29,134✔
1754

1755
    /**
1756
     * @hidden
1757
     */
1758
    public widthConstrained = false;
29,134✔
1759

1760
    /**
1761
     * @hidden
1762
     */
1763
    protected _applySelectableClass = false;
29,134✔
1764

1765
    protected _vIndex = NaN;
29,134✔
1766
    /**
1767
     * @hidden
1768
     */
1769
    protected _pinned = false;
29,134✔
1770
    /**
1771
     * @hidden
1772
     */
1773
    protected _bodyTemplate: TemplateRef<IgxCellTemplateContext>;
1774
    /**
1775
     * @hidden
1776
     */
1777
    protected _errorTemplate: TemplateRef<IgxCellTemplateContext>;
1778
    /**
1779
     * @hidden
1780
     */
1781
    protected _headerTemplate: TemplateRef<IgxColumnTemplateContext>;
1782
    /**
1783
     * @hidden
1784
     */
1785
    protected _summaryTemplate: TemplateRef<IgxSummaryTemplateContext>;
1786
    /**
1787
     * @hidden
1788
     */
1789
    protected _inlineEditorTemplate: TemplateRef<IgxCellTemplateContext>;
1790
    /**
1791
     * @hidden
1792
     */
1793
    protected _filterCellTemplate: TemplateRef<IgxColumnTemplateContext>;
1794
    /**
1795
     * @hidden
1796
     */
1797
    protected _summaries = null;
29,134✔
1798
    /**
1799
     * @hidden
1800
     */
1801
    private _disabledSummaries: string[] = [];
29,134✔
1802
    /**
1803
     * @hidden
1804
     */
1805
    protected _filters = null;
29,134✔
1806
    /**
1807
     * @hidden
1808
     */
1809
    protected _sortStrategy: ISortingStrategy = DefaultSortingStrategy.instance();
29,134✔
1810
    /**
1811
     * @hidden
1812
     */
1813
    protected _groupingComparer: (a: any, b: any, currRec?: any, groupRec?: any) => number;
1814
    /**
1815
     * @hidden
1816
     */
1817
    protected _hidden = false;
29,134✔
1818
    /**
1819
     * @hidden
1820
     */
1821
    protected _index: number;
1822
    /**
1823
     * @hidden
1824
     */
1825
    protected _disablePinning = false;
29,134✔
1826
    /**
1827
     * @hidden
1828
     */
1829
    protected _width: string;
1830
    /**
1831
     * @hidden
1832
     */
1833
    protected _defaultMinWidth = '';
29,134✔
1834
    /**
1835
     * @hidden
1836
     */
1837
    protected _maxWidth;
1838
    /**
1839
     * @hidden
1840
     */
1841
    protected _hasSummary = false;
29,134✔
1842
    /**
1843
     * @hidden
1844
     */
1845
    protected _editable: boolean;
1846
    /**
1847
     * @hidden
1848
     */
1849
    protected _groupable = false;
29,134✔
1850
    /**
1851
     *  @hidden
1852
     */
1853
    protected _visibleWhenCollapsed;
1854
    /**
1855
     * @hidden
1856
     */
1857
    protected _collapsible = false;
29,134✔
1858
    /**
1859
     * @hidden
1860
     */
1861
    protected _expanded = true;
29,134✔
1862
    /**
1863
     * @hidden
1864
     */
1865
    protected _selectable = true;
29,134✔
1866
    /**
1867
     * @hidden
1868
     */
1869
    protected get isPrimaryColumn(): boolean {
1870
        return this.field !== undefined && this.grid !== undefined && this.field === this.grid.primaryKey;
2,415,432✔
1871
    }
1872

1873
    private _field: string;
1874
    private _calcWidth = null;
29,134✔
1875
    private _columnPipeArgs: IColumnPipeArgs = { digitsInfo: DEFAULT_DIGITS_INFO };
29,134✔
1876
    private _editorOptions: IColumnEditorOptions = { };
29,134✔
1877

1878
    constructor(
1879
        @Inject(IGX_GRID_BASE) public grid: GridType,
29,134✔
1880
        @Optional() @Self() @Inject(NG_VALIDATORS) private _validators: Validator[],
29,134✔
1881
        /** @hidden @internal **/
1882
        public cdr: ChangeDetectorRef,
29,134✔
1883
        protected platform: PlatformUtil,
29,134✔
1884
    ) {
1885
        this.validators = _validators;
29,134✔
1886
    }
1887

1888
    /**
1889
     * @hidden
1890
     * @internal
1891
     */
1892
    public resetCaches() {
1893
        this._vIndex = NaN;
286,183✔
1894
        if (this.grid) {
286,183✔
1895
            this.cacheCalcWidth();
286,183✔
1896
        }
1897
    }
1898

1899
    /**
1900
     * @hidden
1901
     */
1902
    public ngOnDestroy() {
1903
        this.destroy$.next(true);
20,318✔
1904
        this.destroy$.complete();
20,318✔
1905
    }
1906
    /**
1907
     * @hidden
1908
     */
1909
    public ngAfterContentInit(): void {
1910
        if (this.summaryTemplateDirective) {
23,997✔
1911
            this._summaryTemplate = this.summaryTemplateDirective.template;
6✔
1912
        }
1913
        if (this.cellTemplate) {
23,997✔
1914
            this._bodyTemplate = this.cellTemplate.template;
44✔
1915
        }
1916
        if (this.cellValidationErrorTemplate) {
23,997✔
1917
            this._errorTemplate = this.cellValidationErrorTemplate.template;
16✔
1918
        }
1919
        if (this.headTemplate && this.headTemplate.length) {
23,997✔
1920
            this._headerTemplate = this.headTemplate.toArray()[0].template;
81✔
1921
        }
1922
        if (this.editorTemplate) {
23,997✔
1923
            this._inlineEditorTemplate = this.editorTemplate.template;
4✔
1924
        }
1925
        if (this.filterCellTemplateDirective) {
23,997!
1926
            this._filterCellTemplate = this.filterCellTemplateDirective.template;
×
1927
        }
1928
        if (!this._columnPipeArgs.format) {
23,997✔
1929
            this._columnPipeArgs.format = this.dataType === GridColumnDataType.Time ?
22,713✔
1930
                DEFAULT_TIME_FORMAT : this.dataType === GridColumnDataType.DateTime ?
22,442✔
1931
                    DEFAULT_DATE_TIME_FORMAT : DEFAULT_DATE_FORMAT;
1932
        }
1933
        if (!this.summaries) {
23,997✔
1934
            switch (this.dataType) {
22,660✔
1935
                case GridColumnDataType.Number:
1936
                case GridColumnDataType.Currency:
1937
                case GridColumnDataType.Percent:
1938
                    this.summaries = IgxNumberSummaryOperand;
6,922✔
1939
                    break;
6,922✔
1940
                case GridColumnDataType.Date:
1941
                case GridColumnDataType.DateTime:
1942
                    this.summaries = IgxDateSummaryOperand;
1,768✔
1943
                    break;
1,768✔
1944
                case GridColumnDataType.Time:
1945
                    this.summaries = IgxTimeSummaryOperand;
271✔
1946
                    break;
271✔
1947

1948
                case GridColumnDataType.String:
1949
                case GridColumnDataType.Boolean:
1950
                default:
1951
                    this.summaries = IgxSummaryOperand;
13,699✔
1952
                    break;
13,699✔
1953
            }
1954
        }
1955
        if (!this.filters) {
23,997✔
1956
            switch (this.dataType) {
22,419✔
1957
                case GridColumnDataType.Boolean:
1958
                    this.filters = IgxBooleanFilteringOperand.instance();
1,160✔
1959
                    break;
1,160✔
1960
                case GridColumnDataType.Number:
1961
                case GridColumnDataType.Currency:
1962
                case GridColumnDataType.Percent:
1963
                    this.filters = IgxNumberFilteringOperand.instance();
6,965✔
1964
                    break;
6,965✔
1965
                case GridColumnDataType.Date:
1966
                    this.filters = IgxDateFilteringOperand.instance();
1,508✔
1967
                    break;
1,508✔
1968
                case GridColumnDataType.Time:
1969
                    this.filters = IgxTimeFilteringOperand.instance();
271✔
1970
                    break;
271✔
1971
                case GridColumnDataType.DateTime:
1972
                    this.filters = IgxDateTimeFilteringOperand.instance();
266✔
1973
                    break;
266✔
1974
                case GridColumnDataType.Image:
1975
                    this.filterable = false;
1✔
1976
                    break;
1✔
1977
                case GridColumnDataType.String:
1978
                default:
1979
                    this.filters = IgxStringFilteringOperand.instance();
12,248✔
1980
                    break;
12,248✔
1981
            }
1982
        }
1983
    }
1984

1985
    /**
1986
     * @hidden
1987
     */
1988
    public getGridTemplate(isRow: boolean): string {
1989
        if (isRow) {
26,946✔
1990
            const rowsCount = this.grid.type !== 'pivot' ? this.grid.multiRowLayoutRowSize : this.children.length - 1;
13,474!
1991
            return `repeat(${rowsCount},1fr)`;
13,474✔
1992
        } else {
1993
            return this.getColumnSizesString(this.children);
13,472✔
1994
        }
1995
    }
1996

1997
    /** @hidden @internal **/
1998
    public getInitialChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<MRLColumnSizeInfo> {
1999
        const columnSizes: MRLColumnSizeInfo[] = [];
148,779✔
2000
        // find the smallest col spans
2001
        children.forEach(col => {
148,779✔
2002
            if (!col.colStart) {
464,068✔
2003
                return;
106,159✔
2004
            }
2005
            const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
357,909✔
2006
            const newSpanSmaller = columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].colSpan > col.gridColumnSpan;
357,909✔
2007
            const bothWidthsSet = col.widthSetByUser && columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].widthSetByUser;
357,909✔
2008
            const bothWidthsNotSet = !col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
357,909✔
2009

2010
            if (columnSizes[col.colStart - 1] === undefined) {
357,909✔
2011
                // If nothing is defined yet take any column at first
2012
                // We use colEnd to know where the column actually ends, because not always it starts where we have it set in columnSizes.
2013
                columnSizes[col.colStart - 1] = {
219,750✔
2014
                    ref: col,
2015
                    width: col.width === 'fit-content' ? col.autoSize :
219,750!
2016
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
642,635✔
2017
                    colSpan: col.gridColumnSpan,
2018
                    colEnd: col.colStart + col.gridColumnSpan,
2019
                    widthSetByUser: col.widthSetByUser
2020
                };
2021
            } else if (newWidthSet || (newSpanSmaller && ((bothWidthsSet) || (bothWidthsNotSet)))) {
138,159✔
2022
                // If a column is set already it should either not have width defined or have width with bigger span than the new one.
2023

2024
                /**
2025
                 *  If replaced column has bigger span, we want to fill the remaining columns
2026
                 *  that the replacing column does not fill with the old one.
2027
                 */
2028
                if (bothWidthsSet && newSpanSmaller) {
49,598✔
2029
                    // Start from where the new column set would end and apply the old column to the rest depending on how much it spans.
2030
                    // We have not yet replaced it so we can use it directly from the columnSizes collection.
2031
                    // This is where colEnd is used because the colStart of the old column is not actually i + 1.
2032
                    for (let i = col.colStart - 1 + col.gridColumnSpan; i < columnSizes[col.colStart - 1].colEnd - 1; i++) {
4,784✔
2033
                        if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
2,737✔
2034
                            columnSizes[i] = columnSizes[col.colStart - 1];
2,687✔
2035
                        } else {
2036
                            break;
50✔
2037
                        }
2038
                    }
2039
                }
2040

2041
                // Replace the old column with the new one.
2042
                columnSizes[col.colStart - 1] = {
49,598✔
2043
                    ref: col,
2044
                    width: col.width === 'fit-content' ? col.autoSize :
49,598!
2045
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
140,372✔
2046
                    colSpan: col.gridColumnSpan,
2047
                    colEnd: col.colStart + col.gridColumnSpan,
2048
                    widthSetByUser: col.widthSetByUser
2049
                };
2050
            } else if (bothWidthsSet && columnSizes[col.colStart - 1].colSpan < col.gridColumnSpan) {
88,561✔
2051
                // If the column already in the columnSizes has smaller span, we still need to fill any empty places with the current col.
2052
                // Start from where the smaller column set would end and apply the bigger column to the rest depending on how much it spans.
2053
                // Since here we do not have it in columnSizes we set it as a new column keeping the same colSpan.
2054
                for (let i = col.colStart - 1 + columnSizes[col.colStart - 1].colSpan; i < col.colStart - 1 + col.gridColumnSpan; i++) {
3,481✔
2055
                    if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
3,481✔
2056
                        columnSizes[i] = {
47✔
2057
                            ref: col,
2058
                            width: col.width === 'fit-content' ? col.autoSize :
47!
2059
                                col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
94!
2060
                            colSpan: col.gridColumnSpan,
2061
                            colEnd: col.colStart + col.gridColumnSpan,
2062
                            widthSetByUser: col.widthSetByUser
2063
                        };
2064
                    } else {
2065
                        break;
3,434✔
2066
                    }
2067
                }
2068
            }
2069
        });
2070

2071
        // Flatten columnSizes so there are not columns with colSpan > 1
2072
        for (let i = 0; i < columnSizes.length; i++) {
148,779✔
2073
            if (columnSizes[i] && columnSizes[i].colSpan > 1) {
217,890✔
2074
                let j = 1;
10,805✔
2075

2076
                // Replace all empty places depending on how much the current column spans starting from next col.
2077
                for (; j < columnSizes[i].colSpan && i + j + 1 < columnSizes[i].colEnd; j++) {
10,805✔
2078
                    if (columnSizes[i + j] &&
10,414✔
2079
                        ((!columnSizes[i].width && columnSizes[i + j].width) ||
2080
                            (!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
2081
                            (!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
2082
                        // If we reach an already defined column that has width and the current doesn't have or
2083
                        // if the reached column has bigger colSpan we stop.
2084
                        break;
4,393✔
2085
                    } else {
2086
                        const width = columnSizes[i].widthSetByUser ?
6,021✔
2087
                            columnSizes[i].width / columnSizes[i].colSpan :
2088
                            columnSizes[i].width;
2089
                        columnSizes[i + j] = {
6,021✔
2090
                            ref: columnSizes[i].ref,
2091
                            width,
2092
                            colSpan: 1,
2093
                            colEnd: columnSizes[i].colEnd,
2094
                            widthSetByUser: columnSizes[i].widthSetByUser
2095
                        };
2096
                    }
2097
                }
2098

2099
                // Update the current column width so it is divided between all columns it spans and set it to 1.
2100
                columnSizes[i].width = columnSizes[i].widthSetByUser ?
10,805✔
2101
                    columnSizes[i].width / columnSizes[i].colSpan :
2102
                    columnSizes[i].width;
2103
                columnSizes[i].colSpan = 1;
10,805✔
2104

2105
                // Update the index based on how much we have replaced. Subtract 1 because we started from 1.
2106
                i += j - 1;
10,805✔
2107
            }
2108
        }
2109

2110
        return columnSizes;
148,779✔
2111
    }
2112

2113
    /** @hidden @internal **/
2114
    public getFilledChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<string> {
2115
        const columnSizes = this.getInitialChildColumnSizes(children);
25,976✔
2116

2117
        // fill the gaps if there are any
2118
        const result: string[] = [];
25,976✔
2119
        for (const size of columnSizes) {
25,976✔
2120
            if (size && !!size.width) {
57,852✔
2121
                result.push(size.width + 'px');
22,563✔
2122
            } else {
2123
                const currentWidth = parseFloat(this.grid.getPossibleColumnWidth());
35,289✔
2124
                result.push((this.getConstrainedSizePx(currentWidth)) + 'px');
35,289✔
2125
            }
2126
        }
2127
        return result;
25,976✔
2128
    }
2129

2130
    /** @hidden @internal **/
2131
    public getResizableColUnderEnd(): MRLResizeColumnInfo[] {
2132
        if (this.columnLayout || !this.columnLayoutChild || this.columnGroup) {
6!
2133
            return [{ target: this, spanUsed: 1 }];
×
2134
        }
2135

2136
        const columnSized = this.getInitialChildColumnSizes(this.parent.children);
6✔
2137
        const targets: MRLResizeColumnInfo[] = [];
6✔
2138
        const colEnd = this.colEnd ? this.colEnd : this.colStart + 1;
6!
2139

2140
        for (let i = 0; i < columnSized.length; i++) {
6✔
2141
            if (this.colStart <= i + 1 && i + 1 < colEnd) {
36✔
2142
                targets.push({ target: columnSized[i].ref, spanUsed: 1 });
10✔
2143
            }
2144
        }
2145

2146
        const targetsSquashed: MRLResizeColumnInfo[] = [];
6✔
2147
        for (const target of targets) {
6✔
2148
            if (targetsSquashed.length && targetsSquashed[targetsSquashed.length - 1].target.field === target.target.field) {
10!
2149
                targetsSquashed[targetsSquashed.length - 1].spanUsed++;
×
2150
            } else {
2151
                targetsSquashed.push(target);
10✔
2152
            }
2153
        }
2154

2155
        return targetsSquashed;
6✔
2156
    }
2157

2158
    /**
2159
     * Pins the column at the provided index in the pinned area.
2160
     * Defaults to index `0` if not provided, or to the initial index in the pinned area.
2161
     * Returns `true` if the column is successfully pinned. Returns `false` if the column cannot be pinned.
2162
     * Column cannot be pinned if:
2163
     * - Is already pinned
2164
     * - index argument is out of range
2165
     * - The pinned area exceeds 80% of the grid width
2166
     * ```typescript
2167
     * let success = this.column.pin();
2168
     * ```
2169
     *
2170
     * @memberof IgxColumnComponent
2171
     */
2172
    public pin(index?: number): boolean {
2173
        // TODO: Probably should the return type of the old functions
2174
        // should be moved as a event parameter.
2175
        const grid = (this.grid as any);
613✔
2176
        if (this._pinned) {
613✔
2177
            return false;
56✔
2178
        }
2179

2180
        if (this.parent && !this.parent.pinned) {
557✔
2181
            return this.topLevelParent.pin(index);
10✔
2182
        }
2183

2184
        const hasIndex = index !== undefined;
547✔
2185
        if (hasIndex && (index < 0 || index > grid.pinnedColumns.length)) {
547✔
2186
            return false;
2✔
2187
        }
2188

2189
        if (!this.parent && !this.pinnable) {
545!
2190
            return false;
×
2191
        }
2192

2193
        const rootPinnedCols = grid._pinnedColumns.filter((c) => c.level === 0);
1,050✔
2194
        index = hasIndex ? index : rootPinnedCols.length;
545✔
2195
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: false, cancel: false };
545✔
2196
        this.grid.columnPin.emit(args);
545✔
2197

2198
        if (args.cancel) {
545!
2199
            return;
×
2200
        }
2201

2202
        this.grid.crudService.endEdit(false);
545✔
2203

2204
        this._pinned = true;
545✔
2205
        this.pinnedChange.emit(this._pinned);
545✔
2206
        // it is possible that index is the last position, so will need to find target column by [index-1]
2207
        const targetColumn = args.insertAtIndex === grid._pinnedColumns.length ?
545✔
2208
            grid._pinnedColumns[args.insertAtIndex - 1] : grid._pinnedColumns[args.insertAtIndex];
2209

2210
        if (grid._pinnedColumns.indexOf(this) === -1) {
545✔
2211
            if (!grid.hasColumnGroups) {
420✔
2212
                grid._pinnedColumns.splice(args.insertAtIndex, 0, this);
371✔
2213
            } else {
2214
                // insert based only on root collection
2215
                if (this.level === 0) {
49✔
2216
                    rootPinnedCols.splice(args.insertAtIndex, 0, this);
42✔
2217
                }
2218
                let allPinned = [];
49✔
2219
                // FIX: this is duplicated on every step in the hierarchy....
2220
                // re-create hierarchy
2221
                rootPinnedCols.forEach(group => {
49✔
2222
                    allPinned.push(group);
79✔
2223
                    allPinned = allPinned.concat(group.allChildren);
79✔
2224
                });
2225
                grid._pinnedColumns = allPinned;
49✔
2226
            }
2227

2228
            if (grid._unpinnedColumns.indexOf(this) !== -1) {
420✔
2229
                const childrenCount = this.allChildren.length;
189✔
2230
                grid._unpinnedColumns.splice(grid._unpinnedColumns.indexOf(this), 1 + childrenCount);
189✔
2231
            }
2232
        }
2233

2234
        if (hasIndex) {
545✔
2235
            index === grid._pinnedColumns.length - 1 ?
10✔
2236
                grid._moveColumns(this, targetColumn, DropPosition.AfterDropTarget) : grid._moveColumns(this, targetColumn, DropPosition.BeforeDropTarget);
2237
        }
2238

2239
        if (this.columnGroup) {
545✔
2240
            this.allChildren.forEach(child => child.pin());
186✔
2241
            grid.reinitPinStates();
59✔
2242
        }
2243

2244
        grid.resetCaches();
545✔
2245
        grid.notifyChanges();
545✔
2246
        if (this.columnLayoutChild) {
545✔
2247
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
407✔
2248
        }
2249
        this.grid.filteringService.refreshExpressions();
545✔
2250
        const eventArgs: IPinColumnEventArgs = { column: this, insertAtIndex: index, isPinned: true };
545✔
2251
        this.grid.columnPinned.emit(eventArgs);
545✔
2252
        return true;
545✔
2253
    }
2254
    /**
2255
     * Unpins the column and place it at the provided index in the unpinned area.
2256
     * Defaults to index `0` if not provided, or to the initial index in the unpinned area.
2257
     * Returns `true` if the column is successfully unpinned. Returns `false` if the column cannot be unpinned.
2258
     * Column cannot be unpinned if:
2259
     * - Is already unpinned
2260
     * - index argument is out of range
2261
     * ```typescript
2262
     * let success = this.column.unpin();
2263
     * ```
2264
     *
2265
     * @memberof IgxColumnComponent
2266
     */
2267
    public unpin(index?: number): boolean {
2268
        const grid = (this.grid as any);
188✔
2269
        if (!this._pinned) {
188✔
2270
            return false;
32✔
2271
        }
2272

2273
        if (this.parent && this.parent.pinned) {
156✔
2274
            return this.topLevelParent.unpin(index);
7✔
2275
        }
2276
        const hasIndex = index !== undefined;
149✔
2277
        if (hasIndex && (index < 0 || index > grid._unpinnedColumns.length)) {
149✔
2278
            return false;
2✔
2279
        }
2280

2281
        // estimate the exact index at which column will be inserted
2282
        // takes into account initial unpinned index of the column
2283
        if (!hasIndex) {
147✔
2284
            const indices = grid.unpinnedColumns.map(col => col.index);
1,184✔
2285
            indices.push(this.index);
143✔
2286
            indices.sort((a, b) => a - b);
1,560✔
2287
            index = indices.indexOf(this.index);
143✔
2288
        }
2289

2290
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: true, cancel: false };
147✔
2291
        this.grid.columnPin.emit(args);
147✔
2292

2293
        if (args.cancel) {
147!
2294
            return;
×
2295
        }
2296

2297
        this.grid.crudService.endEdit(false);
147✔
2298

2299
        this._pinned = false;
147✔
2300
        this.pinnedChange.emit(this._pinned);
147✔
2301

2302
        // it is possible that index is the last position, so will need to find target column by [index-1]
2303
        const targetColumn = args.insertAtIndex === grid._unpinnedColumns.length ?
147✔
2304
            grid._unpinnedColumns[args.insertAtIndex - 1] : grid._unpinnedColumns[args.insertAtIndex];
2305

2306
        if (!hasIndex) {
147✔
2307
            grid._unpinnedColumns.splice(index, 0, this);
143✔
2308
            if (grid._pinnedColumns.indexOf(this) !== -1) {
143✔
2309
                grid._pinnedColumns.splice(grid._pinnedColumns.indexOf(this), 1);
143✔
2310
            }
2311
        }
2312

2313
        if (hasIndex) {
147✔
2314
            grid.moveColumn(this, targetColumn);
4✔
2315
        }
2316

2317
        if (this.columnGroup) {
147✔
2318
            this.allChildren.forEach(child => child.unpin());
106✔
2319
        }
2320

2321
        grid.reinitPinStates();
147✔
2322
        grid.resetCaches();
147✔
2323

2324
        grid.notifyChanges();
147✔
2325
        if (this.columnLayoutChild) {
147✔
2326
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
356✔
2327
        }
2328
        this.grid.filteringService.refreshExpressions();
147✔
2329

2330
        this.grid.columnPinned.emit({ column: this, insertAtIndex: index, isPinned: false });
147✔
2331

2332
        return true;
147✔
2333
    }
2334

2335
    /**
2336
     * Moves a column to the specified visible index.
2337
     * If passed index is invalid, or if column would receive a different visible index after moving, moving is not performed.
2338
     * If passed index would move the column to a different column group. moving is not performed.
2339
     *
2340
     * @example
2341
     * ```typescript
2342
     * column.move(index);
2343
     * ```
2344
     * @memberof IgxColumnComponent
2345
     */
2346
    public move(index: number) {
2347
        let target;
2348
        let columns = this.grid.columns.filter(c => c.visibleIndex > -1);
349✔
2349
        // grid last visible index
2350
        const li = columns.map(c => c.visibleIndex).reduce((a, b) => Math.max(a, b));
343✔
2351
        const parent = this.parent;
36✔
2352
        const isPreceding = this.visibleIndex < index;
36✔
2353

2354
        if (index === this.visibleIndex || index < 0 || index > li) {
36✔
2355
            return;
3✔
2356
        }
2357

2358
        if (parent) {
33✔
2359
            columns = columns.filter(c => c.level >= this.level && c !== this && c.parent !== this &&
84✔
2360
                c.topLevelParent === this.topLevelParent);
2361
        }
2362

2363
        // 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.
2364
        // 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.
2365

2366
        if (isPreceding) {
33✔
2367
            columns = columns.filter(c => c.visibleIndex > this.visibleIndex);
200✔
2368
            target = columns.find(c => c.level === this.level && c.visibleIndex + (c as any).calcChildren() - this.calcChildren() === index);
80✔
2369
        } else {
2370
            columns = columns.filter(c => c.visibleIndex < this.visibleIndex);
65✔
2371
            target = columns.find(c => c.level === this.level && c.visibleIndex === index);
15✔
2372
        }
2373

2374
        if (!target || (target.pinned && this.disablePinning)) {
33✔
2375
            return;
9✔
2376
        }
2377

2378
        const pos = isPreceding ? DropPosition.AfterDropTarget : DropPosition.BeforeDropTarget;
24✔
2379
        this.grid.moveColumn(this, target as IgxColumnComponent, pos);
24✔
2380
    }
2381

2382
    /**
2383
     * No children for the column, so will returns 1 or 0, if the column is hidden.
2384
     *
2385
     * @hidden
2386
     */
2387
    public calcChildren(): number {
2388
        const children = this.hidden ? 0 : 1;
70✔
2389
        return children;
70✔
2390
    }
2391

2392
    /**
2393
     * Toggles column vibisility and emits the respective event.
2394
     *
2395
     * @hidden
2396
     */
2397
    public toggleVisibility(value?: boolean) {
2398
        const newValue = value ?? !this.hidden;
65✔
2399
        const eventArgs: IColumnVisibilityChangingEventArgs = { column: this, newValue, cancel: false };
65✔
2400
        this.grid.columnVisibilityChanging.emit(eventArgs);
65✔
2401

2402
        if (eventArgs.cancel) {
65!
2403
            return;
×
2404
        }
2405
        this.hidden = newValue;
65✔
2406
        this.grid.columnVisibilityChanged.emit({ column: this, newValue });
65✔
2407
    }
2408

2409
    /**
2410
     * Returns a reference to the top level parent column.
2411
     * ```typescript
2412
     * let topLevelParent =  this.column.topLevelParent;
2413
     * ```
2414
     */
2415
    public get topLevelParent(): ColumnType | undefined {
2416
        let parent = this.parent;
490✔
2417
        while (parent && parent.parent) {
490✔
2418
            parent = parent.parent;
34✔
2419
        }
2420
        return parent ?? undefined;
490✔
2421
    }
2422

2423
    /**
2424
     * @hidden @internal
2425
     */
2426
    public get headerCell(): IgxGridHeaderComponent {
2427
        return this.grid.headerCellList.find((header) => header.column === this);
1,594✔
2428
    }
2429

2430
    /**
2431
     * @hidden @internal
2432
     */
2433
    public get filterCell(): IgxGridFilteringCellComponent {
2434
        return this.grid.filterCellList.find((filterCell) => filterCell.column === this);
6,929✔
2435
    }
2436

2437
    /**
2438
     * @hidden @internal
2439
     */
2440
    public get headerGroup(): IgxGridHeaderGroupComponent {
2441
        return this.grid.headerGroupsList.find(group => group.column === this);
6,309✔
2442
    }
2443

2444
    /**
2445
     * Autosize the column to the longest currently visible cell value, including the header cell.
2446
     * ```typescript
2447
     * @ViewChild('grid') grid: IgxGridComponent;
2448
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2449
     * column.autosize();
2450
     * ```
2451
     *
2452
     * @memberof IgxColumnComponent
2453
     * @param byHeaderOnly Set if column should be autosized based only on the header content.
2454
     */
2455
    public autosize(byHeaderOnly = false) {
17✔
2456
        if (!this.columnGroup) {
18✔
2457
            this.width = this.getAutoSize(byHeaderOnly);
18✔
2458
            this.grid.reflow();
18✔
2459
        }
2460
    }
2461

2462
    /**
2463
     * @hidden
2464
     */
2465
    public getAutoSize(byHeader = false): string {
8✔
2466
        const size = !byHeader ? this.getLargestCellWidth() :
26✔
2467
            (Object.values(this.getHeaderCellWidths()).reduce((a, b) => a + b) + 'px');
1✔
2468
        const isPercentageWidth = this.width && typeof this.width === 'string' && this.width.indexOf('%') !== -1;
26✔
2469

2470
        let newWidth;
2471
        if (isPercentageWidth) {
26✔
2472
            const gridAvailableSize = this.grid.calcWidth;
2✔
2473
            const percentageSize = parseFloat(size) / gridAvailableSize * 100;
2✔
2474
            newWidth = percentageSize + '%';
2✔
2475
        } else {
2476
            newWidth = size;
24✔
2477
        }
2478

2479
        const maxWidth = isPercentageWidth ? this.maxWidthPercent : this.maxWidthPx;
26✔
2480
        const minWidth = isPercentageWidth ? this.minWidthPercent : this.minWidthPx;
26✔
2481
        if (this.maxWidth && (parseFloat(newWidth) > maxWidth)) {
26✔
2482
            newWidth = isPercentageWidth ? maxWidth + '%' : maxWidth + 'px';
1!
2483
        } else if (parseFloat(newWidth) < minWidth) {
25✔
2484
            newWidth = isPercentageWidth ? minWidth + '%' : minWidth + 'px';
1!
2485
        }
2486

2487
        return newWidth;
26✔
2488
    }
2489

2490
    /**
2491
     * @hidden
2492
     */
2493
    public getCalcWidth(): any {
2494
        if (this._calcWidth && !isNaN(this.calcPixelWidth)) {
237,813✔
2495
            return this._calcWidth;
231,454✔
2496
        }
2497
        this.cacheCalcWidth();
6,359✔
2498
        return this._calcWidth;
6,359✔
2499
    }
2500

2501

2502
    /**
2503
     * @hidden
2504
     * Returns the width and padding of a header cell.
2505
     */
2506
    public getHeaderCellWidths() {
2507
        return this.grid.getHeaderCellWidth(this.headerCell.nativeElement);
25✔
2508
    }
2509

2510
    /**
2511
     * @hidden
2512
     * Returns the size (in pixels) of the longest currently visible cell, including the header cell.
2513
     * ```typescript
2514
     * @ViewChild('grid') grid: IgxGridComponent;
2515
     *
2516
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2517
     * let size = column.getLargestCellWidth();
2518
     * ```
2519
     * @memberof IgxColumnComponent
2520
     */
2521
    public getLargestCellWidth(): string {
2522
        const range = this.grid.document.createRange();
25✔
2523
        const largest = new Map<number, number>();
25✔
2524

2525
        if (this._cells.length > 0) {
25✔
2526
            const cellsContentWidths = [];
25✔
2527
            this._cells.forEach((cell) => cellsContentWidths.push(cell.calculateSizeToFit(range)));
270✔
2528

2529
            const index = cellsContentWidths.indexOf(Math.max(...cellsContentWidths));
25✔
2530
            const cellStyle = this.grid.document.defaultView.getComputedStyle(this._cells[index].nativeElement);
25✔
2531
            const cellPadding = parseFloat(cellStyle.paddingLeft) + parseFloat(cellStyle.paddingRight) +
25✔
2532
                parseFloat(cellStyle.borderLeftWidth) + parseFloat(cellStyle.borderRightWidth);
2533

2534
            largest.set(Math.max(...cellsContentWidths), cellPadding);
25✔
2535
        }
2536

2537
        if (this.headerCell && this.autosizeHeader) {
25✔
2538
            const headerCellWidths = this.getHeaderCellWidths();
24✔
2539
            largest.set(headerCellWidths.width, headerCellWidths.padding);
24✔
2540
        }
2541

2542
        const largestCell = Math.max(...Array.from(largest.keys()));
25✔
2543
        const width = Math.ceil(largestCell + largest.get(largestCell));
25✔
2544

2545
        if (Number.isNaN(width)) {
25!
2546
            return this.width;
×
2547
        } else {
2548
            return width + 'px';
25✔
2549
        }
2550
    }
2551

2552
    /**
2553
     * @hidden
2554
     */
2555
    public getCellWidth() {
2556
        const colWidth = this.width;
1,165,482✔
2557
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
1,165,482✔
2558

2559
        if (this.columnLayoutChild) {
1,165,482!
2560
            return '';
×
2561
        }
2562

2563
        if (colWidth && !isPercentageWidth) {
1,165,482✔
2564

2565
            let cellWidth = colWidth;
1,154,221✔
2566
            if (typeof cellWidth !== 'string' || cellWidth.endsWith('px') === false) {
1,154,221✔
2567
                cellWidth += 'px';
2,431✔
2568
            }
2569

2570
            return cellWidth;
1,154,221✔
2571
        } else {
2572
            return colWidth;
11,261✔
2573
        }
2574
    }
2575

2576
    /**
2577
     * @hidden
2578
     */
2579
    public populateVisibleIndexes() { }
2580

2581
    protected getColumnSizesString(children: QueryList<IgxColumnComponent>): string {
2582
        const res = this.getFilledChildColumnSizes(children);
13,472✔
2583
        return res.join(' ');
13,472✔
2584
    }
2585

2586
    /**
2587
     * @hidden
2588
     * @internal
2589
     */
2590
    public getConstrainedSizePx(newSize){
2591
        if (this.maxWidth && newSize > this.maxWidthPx) {
367,149✔
2592
            this.widthConstrained = true;
19✔
2593
            return this.maxWidthPx;
19✔
2594
        } else if (this.minWidth && newSize < this.userSetMinWidthPx) {
367,130✔
2595
            this.widthConstrained = true;
18✔
2596
            return this.userSetMinWidthPx;
18✔
2597
        } else {
2598
            this.widthConstrained = false;
367,112✔
2599
            return newSize;
367,112✔
2600
        }
2601
    }
2602

2603
    /**
2604
     * @hidden
2605
     * @internal
2606
     */
2607
    protected cacheCalcWidth(): any {
2608
        const colWidth = this.width;
305,957✔
2609
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
305,957✔
2610
        const isAutoWidth = colWidth && typeof colWidth === 'string' && colWidth === 'fit-content';
305,957✔
2611
        if (isPercentageWidth && this.grid.isColumnWidthSum) {
305,957✔
2612
            this._calcWidth = this.userSetMinWidthPx ? this.userSetMinWidthPx : this.grid.minColumnWidth;
32!
2613
        } else if (isPercentageWidth) {
305,925✔
2614
            const currentCalcWidth = parseFloat(colWidth) / 100 * this.grid.calcWidth;
893✔
2615
            this._calcWidth = this.grid.calcWidth ? this.getConstrainedSizePx(currentCalcWidth) : 0;
893✔
2616
        } else if (!colWidth || isAutoWidth && !this.autoSize) {
305,032✔
2617
            // no width
2618
            const currentCalcWidth = this.defaultWidth || this.grid.getPossibleColumnWidth();
26,874✔
2619
            this._calcWidth = this.getConstrainedSizePx(currentCalcWidth);
26,874✔
2620
        } else {
2621
            const currentCalcWidth =  parseFloat(this.width);
278,158✔
2622
            this._calcWidth =this.getConstrainedSizePx(currentCalcWidth);
278,158✔
2623
        }
2624
        this.calcPixelWidth = parseFloat(this._calcWidth);
305,957✔
2625
    }
2626

2627
    /**
2628
     * @hidden
2629
     * @internal
2630
     */
2631
    protected setExpandCollapseState() {
2632
        this.children.filter(col => (col.visibleWhenCollapsed !== undefined)).forEach(c => {
295✔
2633
            if (!this.collapsible) {
270✔
2634
                c.hidden = this.hidden; return;
2✔
2635
            }
2636
            c.hidden = this._expanded ? c.visibleWhenCollapsed : !c.visibleWhenCollapsed;
268✔
2637
        });
2638
    }
2639
    /**
2640
     * @hidden
2641
     * @internal
2642
     */
2643
    protected checkCollapsibleState() {
2644
        if (!this.children) {
2,481!
2645
            return false;
×
2646
        }
2647
        const cols = this.children.map(child => child.visibleWhenCollapsed);
6,113✔
2648
        return (cols.some(c => c === true) && cols.some(c => c === false));
3,756✔
2649
    }
2650

2651
    /**
2652
     * @hidden
2653
     */
2654
    public get pinnable() {
2655
        return (this.grid as any)._init || !this.pinned;
401✔
2656
    }
2657

2658
    /**
2659
     * @hidden
2660
     */
2661
    public get applySelectableClass(): boolean {
2662
        return this._applySelectableClass;
10,986✔
2663
    }
2664

2665
    /**
2666
     * @hidden
2667
     */
2668
    public set applySelectableClass(value: boolean) {
2669
        if (this.selectable) {
15✔
2670
            this._applySelectableClass = value;
13✔
2671
        }
2672
    }
2673
}
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