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

IgniteUI / igniteui-angular / 12705788868

10 Jan 2025 08:18AM UTC coverage: 91.592% (+0.006%) from 91.586%
12705788868

push

github

web-flow
fix(themes): igx-icon gets overridden multiple themes (#15221)

12984 of 15221 branches covered (85.3%)

26308 of 28723 relevant lines covered (91.59%)

33985.48 hits per line

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

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

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

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

108

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

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

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

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

225
        if (this.isPrimaryColumn && (rowEditable || hasTransactions)) {
2,409,415✔
226
            return false;
98,713✔
227
        }
228

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

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

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

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

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

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

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

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

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

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

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

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

472
        }
473
        return this.widthSetByUser ? this._width : this.defaultWidth;
2,123,153✔
474
    }
475

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

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

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

528
    /**
529
     * Sets/gets the class selector of the column header.
530
     * ```typescript
531
     * let columnHeaderClass = this.column.headerClasses;
532
     * ```
533
     * ```html
534
     * <igx-column [headerClasses] = "'column-header'"></igx-column>
535
     * ```
536
     *
537
     * @memberof IgxColumnComponent
538
     */
539
    @notifyChanges()
540
    @WatchColumnChanges()
541
    @Input()
542
    public headerClasses = '';
29,145✔
543

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

565
    /**
566
     * Sets/gets the class selector of the column group header.
567
     * ```typescript
568
     * let columnHeaderClass = this.column.headerGroupClasses;
569
     * ```
570
     * ```html
571
     * <igx-column [headerGroupClasses] = "'column-group-header'"></igx-column>
572
     * ```
573
     *
574
     * @memberof IgxColumnComponent
575
     */
576
    @notifyChanges()
577
    @WatchColumnChanges()
578
    @Input()
579
    public headerGroupClasses = '';
29,145✔
580

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

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

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

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

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

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

782
    /** @hidden */
783
    @Input()
784
    public collapsibleIndicatorTemplate: TemplateRef<IgxColumnTemplateContext>;
785

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

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

814
    /**
815
     * Row index from which the field is starting.
816
     * ```html
817
     * <igx-column-layout>
818
     *   <igx-column [rowStart]="1" [colStart]="1"></igx-column>
819
     * </igx-column-layout>
820
     * ```
821
     *
822
     * @memberof IgxColumnComponent
823
     */
824
    @Input()
825
    public rowStart: number;
826

827
    /**
828
     * Column index from which the field is starting.
829
     * ```html
830
     * <igx-column-layout>
831
     *   <igx-column [colStart]="1" [rowStart]="1"></igx-column>
832
     * </igx-column-layout>
833
     * ```
834
     *
835
     * @memberof IgxColumnComponent
836
     */
837
    @Input()
838
    public colStart: number;
839

840
    /**
841
     * Sets/gets custom properties provided in additional template context.
842
     *
843
     * ```html
844
     * <igx-column [additionalTemplateContext]="contextObject">
845
     *   <ng-template igxCell let-cell="cell" let-props="additionalTemplateContext">
846
     *      {{ props }}
847
     *   </ng-template>
848
     * </igx-column>
849
     * ```
850
     *
851
     * @memberof IgxColumnComponent
852
     */
853
    @Input()
854
    public additionalTemplateContext: any;
855

856
    /**
857
     * @hidden
858
     */
859
    @Output()
860
    public widthChange = new EventEmitter<string>();
29,145✔
861

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

910
    /** @hidden @internal **/
911
    public calcPixelWidth: number;
912

913
    /**
914
     * @hidden
915
     */
916
    public get maxWidthPx() {
917
        const gridAvailableSize = this.grid.calcWidth;
70,968✔
918
        const isPercentageWidth = this.maxWidth && typeof this.maxWidth === 'string' && this.maxWidth.indexOf('%') !== -1;
70,968✔
919
        return isPercentageWidth ? parseFloat(this.maxWidth) / 100 * gridAvailableSize : parseFloat(this.maxWidth);
70,968✔
920
    }
921

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

931
    /**
932
     * @hidden
933
     */
934
    public get minWidthPx() {
935
        const gridAvailableSize = this.grid.calcWidth;
71,081✔
936
        const isPercentageWidth = this.minWidth && typeof this.minWidth === 'string' && this.minWidth.indexOf('%') !== -1;
71,081✔
937
        return isPercentageWidth ? parseFloat(this.minWidth) / 100 * gridAvailableSize : parseFloat(this.minWidth);
71,081✔
938
    }
939

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

949

950
    /**
951
     * Sets/gets the minimum `width` of the column.
952
     * Default value is `88`;
953
     * ```typescript
954
     * let columnMinWidth = this.column.minWidth;
955
     * ```
956
     * ```html
957
     * <igx-column [minWidth] = "'100px'"></igx-column>
958
     * ```
959
     *
960
     * @memberof IgxColumnComponent
961
     */
962
    @notifyChanges()
963
    @WatchColumnChanges()
964
    @Input()
965
    public set minWidth(value: string) {
966
        const minVal = parseFloat(value);
1,460✔
967
        if (Number.isNaN(minVal)) {
1,460✔
968
            return;
45✔
969
        }
970
        this._defaultMinWidth = value;
1,415✔
971

972
    }
973
    public get minWidth(): string {
974
        return !this._defaultMinWidth ? this.defaultMinWidth : this._defaultMinWidth;
288,588✔
975
    }
976

977
    /** @hidden @internal **/
978
    public get resolvedWidth(): string {
979
        if (this.columnLayoutChild) {
4,115,470!
980
            return '';
×
981
        }
982
        const isAutoWidth = this._width && typeof this._width === 'string' && this._width === 'auto';
4,115,470✔
983
        return isAutoWidth ? this.width : this.calcPixelWidth + 'px';
4,115,470✔
984
    }
985

986
    /**
987
     * Gets the column index.
988
     * ```typescript
989
     * let columnIndex = this.column.index;
990
     * ```
991
     *
992
     * @memberof IgxColumnComponent
993
     */
994
    public get index(): number {
995
        return (this.grid as any)._columns.indexOf(this);
239,572✔
996
    }
997

998
    /**
999
     * Gets whether the column is `pinned`.
1000
     * ```typescript
1001
     * let isPinned = this.column.pinned;
1002
     * ```
1003
     *
1004
     * @memberof IgxColumnComponent
1005
     */
1006
    @WatchColumnChanges()
1007
    @Input({ transform: booleanAttribute })
1008
    public get pinned(): boolean {
1009
        return this._pinned;
2,279,398✔
1010
    }
1011
    /**
1012
     * Sets whether the column is pinned.
1013
     * Default value is `false`.
1014
     * ```html
1015
     * <igx-column [pinned] = "true"></igx-column>
1016
     * ```
1017
     *
1018
     * Two-way data binding.
1019
     * ```html
1020
     * <igx-column [(pinned)] = "model.columns[0].isPinned"></igx-column>
1021
     * ```
1022
     *
1023
     * @memberof IgxColumnComponent
1024
     */
1025
    public set pinned(value: boolean) {
1026
        if (this._pinned !== value) {
2,803✔
1027
            const isAutoWidth = this.width && typeof this.width === 'string' && this.width === 'fit-content';
561✔
1028
            if (this.grid && this.width && (isAutoWidth || !isNaN(parseInt(this.width, 10)))) {
561✔
1029
                if (value) {
389✔
1030
                    this.pin();
354✔
1031
                } else {
1032
                    this.unpin();
35✔
1033
                }
1034
                return;
389✔
1035
            }
1036
            /* No grid/width available at initialization. `initPinning` in the grid
1037
               will re-init the group (if present)
1038
            */
1039
            this._pinned = value;
172✔
1040
            this.pinnedChange.emit(this._pinned);
172✔
1041
        }
1042
    }
1043

1044
    /* treatAsRef */
1045
    /**
1046
     * Gets the column `summaries`.
1047
     * ```typescript
1048
     * let columnSummaries = this.column.summaries;
1049
     * ```
1050
     *
1051
     * @memberof IgxColumnComponent
1052
     */
1053
    @notifyChanges(true)
1054
    @WatchColumnChanges()
1055
    @Input()
1056
    public get summaries(): any {
1057
        return this._summaries;
65,147✔
1058
    }
1059

1060
    /* treatAsRef */
1061
    /**
1062
     * Sets the column `summaries`.
1063
     * ```typescript
1064
     * this.column.summaries = IgxNumberSummaryOperand;
1065
     * ```
1066
     *
1067
     * @memberof IgxColumnComponent
1068
     */
1069
    public set summaries(classRef: any) {
1070
        if (isConstructor(classRef)) {
24,088✔
1071
            this._summaries = new classRef();
24,082✔
1072
        }
1073

1074
        if (this.grid) {
24,088✔
1075
            this.grid.summaryService.removeSummariesCachePerColumn(this.field);
24,088✔
1076
            this.grid.summaryPipeTrigger++;
24,088✔
1077
            this.grid.summaryService.resetSummaryHeight();
24,088✔
1078
        }
1079
    }
1080
    /**
1081
     * Gets the column `filters`.
1082
     * ```typescript
1083
     * let columnFilters = this.column.filters'
1084
     * ```
1085
     *
1086
     * @memberof IgxColumnComponent
1087
     */
1088
    @Input()
1089
    public get filters(): IgxFilteringOperand {
1090
        return this._filters;
76,017✔
1091
    }
1092
    /**
1093
     * Sets the column `filters`.
1094
     * ```typescript
1095
     * this.column.filters = IgxBooleanFilteringOperand.instance().
1096
     * ```
1097
     *
1098
     * @memberof IgxColumnComponent
1099
     */
1100
    public set filters(instance: IgxFilteringOperand) {
1101
        this._filters = instance;
24,075✔
1102
    }
1103
    /**
1104
     * Gets the column `sortStrategy`.
1105
     * ```typescript
1106
     * let sortStrategy = this.column.sortStrategy
1107
     * ```
1108
     *
1109
     * @memberof IgxColumnComponent
1110
     */
1111
    @Input()
1112
    public get sortStrategy(): ISortingStrategy {
1113
        return this._sortStrategy;
2,813✔
1114
    }
1115
    /**
1116
     * Sets the column `sortStrategy`.
1117
     * ```typescript
1118
     * this.column.sortStrategy = new CustomSortingStrategy().
1119
     * class CustomSortingStrategy extends SortingStrategy {...}
1120
     * ```
1121
     *
1122
     * @memberof IgxColumnComponent
1123
     */
1124
    public set sortStrategy(classRef: ISortingStrategy) {
1125
        this._sortStrategy = classRef;
1,394✔
1126
    }
1127

1128
    /* blazorSuppress */
1129
    /**
1130
     * Gets the function that compares values for grouping.
1131
     * ```typescript
1132
     * let groupingComparer = this.column.groupingComparer'
1133
     * ```
1134
     *
1135
     * @memberof IgxColumnComponent
1136
     */
1137
    @Input()
1138
    public get groupingComparer(): (a: any, b: any, currRec?: any, groupRec?: any) => number {
1139
        return this._groupingComparer;
3,244✔
1140
    }
1141

1142
    /* blazorSuppress */
1143
    /**
1144
     * Sets a custom function to compare values for grouping.
1145
     * Subsequent values in the sorted data that the function returns 0 for are grouped.
1146
     * ```typescript
1147
     * this.column.groupingComparer = (a: any, b: any, currRec?: any, groupRec?: any) => { return a === b ? 0 : -1; }
1148
     * ```
1149
     *
1150
     * @memberof IgxColumnComponent
1151
     */
1152
    public set groupingComparer(funcRef: (a: any, b: any, currRec?: any, groupRec?: any) => number) {
1153
        this._groupingComparer = funcRef;
1,394✔
1154
    }
1155
    /**
1156
     * @hidden @internal
1157
     */
1158
    public get defaultMinWidth(): string {
1159
        if (!this.grid) {
268,128!
1160
            return '80';
×
1161
        }
1162
        switch (this.grid.gridSize) {
268,128✔
1163
            case Size.Medium:
1164
                return '64';
12,321✔
1165
            case Size.Small:
1166
                return '56';
693✔
1167
            default:
1168
                return '80';
255,114✔
1169
        }
1170
    }
1171
    /**
1172
     * Returns a reference to the `summaryTemplate`.
1173
     * ```typescript
1174
     * let summaryTemplate = this.column.summaryTemplate;
1175
     * ```
1176
     *
1177
     * @memberof IgxColumnComponent
1178
     */
1179
    @notifyChanges()
1180
    @WatchColumnChanges()
1181
    @Input()
1182
    public get summaryTemplate(): TemplateRef<IgxSummaryTemplateContext> {
1183
        return this._summaryTemplate;
82,921✔
1184
    }
1185
    /**
1186
     * Sets the summary template.
1187
     * ```html
1188
     * <ng-template #summaryTemplate igxSummary let-summaryResults>
1189
     *    <p>{{ summaryResults[0].label }}: {{ summaryResults[0].summaryResult }}</p>
1190
     *    <p>{{ summaryResults[1].label }}: {{ summaryResults[1].summaryResult }}</p>
1191
     * </ng-template>
1192
     * ```
1193
     * ```typescript
1194
     * @ViewChild("'summaryTemplate'", {read: TemplateRef })
1195
     * public summaryTemplate: TemplateRef<any>;
1196
     * this.column.summaryTemplate = this.summaryTemplate;
1197
     * ```
1198
     *
1199
     * @memberof IgxColumnComponent
1200
     */
1201
    public set summaryTemplate(template: TemplateRef<IgxSummaryTemplateContext>) {
1202
        this._summaryTemplate = template;
1,397✔
1203
    }
1204

1205
    /**
1206
     * Returns a reference to the `bodyTemplate`.
1207
     * ```typescript
1208
     * let bodyTemplate = this.column.bodyTemplate;
1209
     * ```
1210
     *
1211
     * @memberof IgxColumnComponent
1212
     */
1213
    @notifyChanges()
1214
    @WatchColumnChanges()
1215
    @Input('cellTemplate')
1216
    public get bodyTemplate(): TemplateRef<IgxCellTemplateContext> {
1217
        return this._bodyTemplate;
1,204,073✔
1218
    }
1219
    /**
1220
     * Sets the body template.
1221
     * ```html
1222
     * <ng-template #bodyTemplate igxCell let-val>
1223
     *    <div style = "background-color: yellowgreen" (click) = "changeColor(val)">
1224
     *       <span> {{val}} </span>
1225
     *    </div>
1226
     * </ng-template>
1227
     * ```
1228
     * ```typescript
1229
     * @ViewChild("'bodyTemplate'", {read: TemplateRef })
1230
     * public bodyTemplate: TemplateRef<any>;
1231
     * this.column.bodyTemplate = this.bodyTemplate;
1232
     * ```
1233
     *
1234
     * @memberof IgxColumnComponent
1235
     */
1236
    public set bodyTemplate(template: TemplateRef<IgxCellTemplateContext>) {
1237
        this._bodyTemplate = template;
1,362✔
1238
    }
1239
    /**
1240
     * Returns a reference to the header template.
1241
     * ```typescript
1242
     * let headerTemplate = this.column.headerTemplate;
1243
     * ```
1244
     *
1245
     * @memberof IgxColumnComponent
1246
     */
1247
    @notifyChanges()
1248
    @WatchColumnChanges()
1249
    @Input()
1250
    public get headerTemplate(): TemplateRef<IgxColumnTemplateContext> {
1251
        return this._headerTemplate;
261,344✔
1252
    }
1253
    /**
1254
     * Sets the header template.
1255
     * Note that the column header height is fixed and any content bigger than it will be cut off.
1256
     * ```html
1257
     * <ng-template #headerTemplate>
1258
     *   <div style = "background-color:black" (click) = "changeColor(val)">
1259
     *       <span style="color:red" >{{column.field}}</span>
1260
     *   </div>
1261
     * </ng-template>
1262
     * ```
1263
     * ```typescript
1264
     * @ViewChild("'headerTemplate'", {read: TemplateRef })
1265
     * public headerTemplate: TemplateRef<any>;
1266
     * this.column.headerTemplate = this.headerTemplate;
1267
     * ```
1268
     *
1269
     * @memberof IgxColumnComponent
1270
     */
1271
    public set headerTemplate(template: TemplateRef<IgxColumnTemplateContext>) {
1272
        this._headerTemplate = template;
5,107✔
1273
    }
1274
    /**
1275
     * Returns a reference to the inline editor template.
1276
     * ```typescript
1277
     * let inlineEditorTemplate = this.column.inlineEditorTemplate;
1278
     * ```
1279
     *
1280
     * @memberof IgxColumnComponent
1281
     */
1282
    @notifyChanges()
1283
    @WatchColumnChanges()
1284
    @Input('cellEditorTemplate')
1285
    public get inlineEditorTemplate(): TemplateRef<IgxCellTemplateContext> {
1286
        return this._inlineEditorTemplate;
5,417✔
1287
    }
1288
    /**
1289
     * Sets the inline editor template.
1290
     * ```html
1291
     * <ng-template #inlineEditorTemplate igxCellEditor let-cell="cell">
1292
     *     <input type="string" [(ngModel)]="cell.value"/>
1293
     * </ng-template>
1294
     * ```
1295
     * ```typescript
1296
     * @ViewChild("'inlineEditorTemplate'", {read: TemplateRef })
1297
     * public inlineEditorTemplate: TemplateRef<any>;
1298
     * this.column.inlineEditorTemplate = this.inlineEditorTemplate;
1299
     * ```
1300
     *
1301
     * @memberof IgxColumnComponent
1302
     */
1303
    public set inlineEditorTemplate(template: TemplateRef<IgxCellTemplateContext>) {
1304
        this._inlineEditorTemplate = template;
1,359✔
1305
    }
1306

1307
    /**
1308
     * Returns a reference to the validation error template.
1309
     * ```typescript
1310
     * let errorTemplate = this.column.errorTemplate;
1311
     * ```
1312
     */
1313
    @notifyChanges()
1314
    @WatchColumnChanges()
1315
    @Input('errorTemplate')
1316
    public get errorTemplate(): TemplateRef<IgxCellTemplateContext> {
1317
        return this._errorTemplate;
1,148,478✔
1318
    }
1319
    /**
1320
     * Sets the error template.
1321
     * ```html
1322
     * <ng-template igxCellValidationError let-cell="cell" #errorTemplate >
1323
     *     <div *ngIf="cell.validation.errors?.['forbiddenName']">
1324
     *      This name is forbidden.
1325
     *     </div>
1326
     * </ng-template>
1327
     * ```
1328
     * ```typescript
1329
     * @ViewChild("'errorTemplate'", {read: TemplateRef })
1330
     * public errorTemplate: TemplateRef<any>;
1331
     * this.column.errorTemplate = this.errorTemplate;
1332
     * ```
1333
     */
1334
    public set errorTemplate(template: TemplateRef<IgxCellTemplateContext>) {
1335
        this._errorTemplate = template;
1,391✔
1336
    }
1337

1338
    /**
1339
     * Returns a reference to the `filterCellTemplate`.
1340
     * ```typescript
1341
     * let filterCellTemplate = this.column.filterCellTemplate;
1342
     * ```
1343
     *
1344
     * @memberof IgxColumnComponent
1345
     */
1346
    @notifyChanges()
1347
    @WatchColumnChanges()
1348
    @Input('filterCellTemplate')
1349
    public get filterCellTemplate(): TemplateRef<IgxColumnTemplateContext> {
1350
        return this._filterCellTemplate;
41,567✔
1351
    }
1352
    /**
1353
     * Sets the quick filter template.
1354
     * ```html
1355
     * <ng-template #filterCellTemplate IgxFilterCellTemplate let-column="column">
1356
     *    <input (input)="onInput()">
1357
     * </ng-template>
1358
     * ```
1359
     * ```typescript
1360
     * @ViewChild("'filterCellTemplate'", {read: TemplateRef })
1361
     * public filterCellTemplate: TemplateRef<any>;
1362
     * this.column.filterCellTemplate = this.filterCellTemplate;
1363
     * ```
1364
     *
1365
     * @memberof IgxColumnComponent
1366
     */
1367
    public set filterCellTemplate(template: TemplateRef<IgxColumnTemplateContext>) {
1368
        this._filterCellTemplate = template;
1,407✔
1369
    }
1370

1371
    /**
1372
     * @hidden @internal
1373
     */
1374
    public get cells(): CellType[] {
1375
        return this.grid.dataView
23✔
1376
            .map((rec, index) => {
1377
                if (!this.grid.isGroupByRecord(rec) && !this.grid.isSummaryRow(rec)) {
1,273✔
1378
                    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!
1379
                    const cell = new IgxGridCell(this.grid as any, index, this);
1,273✔
1380
                    return cell;
1,273✔
1381
                }
1382
            }).filter(cell => cell);
1,273✔
1383
    }
1384

1385

1386
    /**
1387
     * @hidden @internal
1388
     */
1389
    public get _cells(): CellType[] {
1390
        return this.grid.rowList.filter((row) => row instanceof IgxRowDirective)
2,865✔
1391
            .map((row) => {
1392
                if (row._cells) {
2,865✔
1393
                    return row._cells.filter((cell) => cell.columnIndex === this.index);
17,213✔
1394
                }
1395
            }).reduce((a, b) => a.concat(b), []);
2,865✔
1396
    }
1397

1398
    /**
1399
     * Gets the column visible index.
1400
     * If the column is not visible, returns `-1`.
1401
     * ```typescript
1402
     * let visibleColumnIndex =  this.column.visibleIndex;
1403
     * ```
1404
     *
1405
     * @memberof IgxColumnComponent
1406
     */
1407
    public get visibleIndex(): number {
1408
        if (!isNaN(this._vIndex)) {
5,435,330✔
1409
            return this._vIndex;
4,984,767✔
1410
        }
1411
        const unpinnedColumns = this.grid.unpinnedColumns.filter(c => !c.columnGroup);
4,423,266✔
1412
        const pinnedColumns = this.grid.pinnedColumns.filter(c => !c.columnGroup);
450,563✔
1413
        // eslint-disable-next-line @typescript-eslint/no-this-alias
1414
        let col = this;
450,563✔
1415
        let vIndex = -1;
450,563✔
1416

1417
        if (this.columnGroup) {
450,563✔
1418
            col = this.allChildren.filter(c => !c.columnGroup && !c.hidden)[0] as any;
24,377✔
1419
        }
1420
        if (this.columnLayoutChild) {
450,563✔
1421
            return this.parent.childrenVisibleIndexes.find(x => x.column === this).index;
874,947✔
1422
        }
1423

1424
        if (!this.pinned) {
112,107✔
1425
            const indexInCollection = unpinnedColumns.indexOf(col);
109,918✔
1426
            vIndex = indexInCollection === -1 ?
109,918✔
1427
                -1 :
1428
                (this.grid.isPinningToStart ?
109,312✔
1429
                    pinnedColumns.length + indexInCollection :
1430
                    indexInCollection);
1431
        } else {
1432
            const indexInCollection = pinnedColumns.indexOf(col);
2,189✔
1433
            vIndex = this.grid.isPinningToStart ?
2,189✔
1434
                indexInCollection :
1435
                unpinnedColumns.length + indexInCollection;
1436
        }
1437
        this._vIndex = vIndex;
112,107✔
1438
        return vIndex;
112,107✔
1439
    }
1440

1441
    /* blazorCSSuppress - Blazor doesn't carry over the ColumnType interface + should translate as static bool value */
1442
    /**
1443
     * Returns a boolean indicating if the column is a `ColumnGroup`.
1444
     * ```typescript
1445
     * let columnGroup =  this.column.columnGroup;
1446
     * ```
1447
     *
1448
     * @memberof IgxColumnComponent
1449
     */
1450
    public get columnGroup() {
1451
        return false;
8,122,378✔
1452
    }
1453

1454
    /* blazorCSSuppress - Blazor doesn't carry over the ColumnType interface + should translate as static bool value */
1455
    /**
1456
     * Returns a boolean indicating if the column is a `ColumnLayout` for multi-row layout.
1457
     * ```typescript
1458
     * let columnGroup =  this.column.columnGroup;
1459
     * ```
1460
     *
1461
     * @memberof IgxColumnComponent
1462
     */
1463
    public get columnLayout() {
1464
        return false;
19,523,518✔
1465
    }
1466

1467
    /**
1468
     * Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
1469
     * ```typescript
1470
     * let columnLayoutChild =  this.column.columnLayoutChild;
1471
     * ```
1472
     *
1473
     * @memberof IgxColumnComponent
1474
     */
1475
    public get columnLayoutChild(): boolean {
1476
        return this.parent && this.parent.columnLayout;
16,966,645✔
1477
    }
1478

1479
    /**
1480
     * A list containing all the child columns under this column (if any).
1481
     * Empty without children or if this column is not Group or Layout.
1482
     */
1483
    public get childColumns(): ColumnType[] {
1484
        return [];
×
1485
    }
1486

1487
    /** @hidden @internal **/
1488
    public get allChildren(): IgxColumnComponent[] {
1489
        return [];
314✔
1490
    }
1491
    /**
1492
     * Returns the level of the column in a column group.
1493
     * Returns `0` if the column doesn't have a `parent`.
1494
     * ```typescript
1495
     * let columnLevel =  this.column.level;
1496
     * ```
1497
     *
1498
     * @memberof IgxColumnComponent
1499
     */
1500
    public get level() {
1501
        let ptr = this.parent;
474,223✔
1502
        let lvl = 0;
474,223✔
1503

1504
        while (ptr) {
474,223✔
1505
            lvl++;
145,373✔
1506
            ptr = ptr.parent;
145,373✔
1507
        }
1508
        return lvl;
474,223✔
1509
    }
1510

1511
    /** @hidden @internal **/
1512
    public get isLastPinned(): boolean {
1513
        return this.grid.isPinningToStart &&
1,104,330✔
1514
            this.grid.pinnedColumns[this.grid.pinnedColumns.length - 1] === this;
1515
    }
1516

1517
    /** @hidden @internal **/
1518
    public get isFirstPinned(): boolean {
1519
        const pinnedCols = this.grid.pinnedColumns.filter(x => !x.columnGroup);
1,016,878✔
1520
        return !this.grid.isPinningToStart && pinnedCols[0] === this;
1,016,878✔
1521
    }
1522

1523
    /** @hidden @internal **/
1524
    public get rightPinnedOffset(): string {
1525
        return this.pinned && !this.grid.isPinningToStart ?
734,149✔
1526
            - this.grid.pinnedWidth - this.grid.headerFeaturesWidth + 'px' :
1527
            null;
1528
    }
1529

1530
    /** @hidden @internal **/
1531
    public get gridRowSpan(): number {
1532
        return this.rowEnd && this.rowStart ? this.rowEnd - this.rowStart : 1;
1,290✔
1533
    }
1534
    /** @hidden @internal **/
1535
    public get gridColumnSpan(): number {
1536
        return this.colEnd && this.colStart ? this.colEnd - this.colStart : 1;
700,895✔
1537
    }
1538

1539
    /**
1540
     * Indicates whether the column will be visible when its parent is collapsed.
1541
     * ```html
1542
     * <igx-column-group>
1543
     *   <igx-column [visibleWhenCollapsed]="true"></igx-column>
1544
     * </igx-column-group>
1545
     * ```
1546
     *
1547
     * @memberof IgxColumnComponent
1548
     */
1549
    @notifyChanges(true)
1550
    @Input({ transform: booleanAttribute })
1551
    public set visibleWhenCollapsed(value: boolean) {
1552
        this._visibleWhenCollapsed = value;
1,734✔
1553
        this.visibleWhenCollapsedChange.emit(this._visibleWhenCollapsed);
1,734✔
1554
        if (this.parent) {
1,734✔
1555
            this.parent?.setExpandCollapseState?.();
26✔
1556
        }
1557
    }
1558

1559
    public get visibleWhenCollapsed(): boolean {
1560
        return this._visibleWhenCollapsed;
9,191✔
1561
    }
1562

1563
    /* mustSetInCodePlatforms: WebComponents;Blazor;React */
1564
    /**
1565
     * @remarks
1566
     * Pass optional parameters for DatePipe and/or DecimalPipe to format the display value for date and numeric columns.
1567
     * Accepts an `IColumnPipeArgs` object with any of the `format`, `timezone` and `digitsInfo` properties.
1568
     * For more details see https://angular.io/api/common/DatePipe and https://angular.io/api/common/DecimalPipe
1569
     * @example
1570
     * ```typescript
1571
     * const pipeArgs: IColumnPipeArgs = {
1572
     *      format: 'longDate',
1573
     *      timezone: 'UTC',
1574
     *      digitsInfo: '1.1-2'
1575
     * }
1576
     * ```
1577
     * ```html
1578
     * <igx-column dataType="date" [pipeArgs]="pipeArgs"></igx-column>
1579
     * <igx-column dataType="number" [pipeArgs]="pipeArgs"></igx-column>
1580
     * ```
1581
     * @memberof IgxColumnComponent
1582
     */
1583
    @notifyChanges()
1584
    @WatchColumnChanges()
1585
    @Input()
1586
    public set pipeArgs(value: IColumnPipeArgs) {
1587
        this._columnPipeArgs = Object.assign(this._columnPipeArgs, value);
1,429✔
1588
        this.grid.summaryService.clearSummaryCache();
1,429✔
1589
        this.grid.pipeTrigger++;
1,429✔
1590
    }
1591
    /* mustSetInCodePlatforms: WebComponents;Blazor */
1592
    public get pipeArgs(): IColumnPipeArgs {
1593
        return this._columnPipeArgs;
1,668,187✔
1594
    }
1595

1596
    /**
1597
     * Pass optional properties for the default column editors.
1598
     * @remarks
1599
     * Options may be applicable only to specific column type editors.
1600
     * @example
1601
     * ```typescript
1602
     * const editorOptions: IColumnEditorOptions = {
1603
     *      dateTimeFormat: 'MM/dd/YYYY',
1604
     * }
1605
     * ```
1606
     * ```html
1607
     * <igx-column dataType="date" [editorOptions]="editorOptions"></igx-column>
1608
     * ```
1609
     * @memberof IgxColumnComponent
1610
     */
1611
    @notifyChanges()
1612
    @WatchColumnChanges()
1613
    @Input()
1614
    public set editorOptions(value: IColumnEditorOptions) {
1615
        this._editorOptions = value;
1,401✔
1616
    }
1617
    public get editorOptions(): IColumnEditorOptions {
1618
        return this._editorOptions;
4,496✔
1619
    }
1620

1621
    /**
1622
     * @hidden
1623
     * @internal
1624
     */
1625
    public get collapsible() {
1626
        return false;
×
1627
    }
1628
    public set collapsible(_value: boolean) { }
1629

1630
    /**
1631
     * @hidden
1632
     * @internal
1633
     */
1634
    public get expanded() {
1635
        return true;
×
1636
    }
1637
    public set expanded(_value: boolean) { }
1638

1639
    /**
1640
     * @hidden
1641
     */
1642
    public defaultWidth: string;
1643

1644
    /**
1645
     * @hidden
1646
     */
1647
    public widthSetByUser: boolean;
1648

1649
    /**
1650
     * @hidden
1651
     */
1652
    public hasNestedPath: boolean;
1653

1654
    /**
1655
     * @hidden
1656
     * @internal
1657
     */
1658
    public defaultTimeFormat = 'hh:mm:ss a';
29,145✔
1659

1660
    /**
1661
     * @hidden
1662
     * @internal
1663
     */
1664
    public defaultDateTimeFormat = 'dd/MM/yyyy HH:mm:ss a';
29,145✔
1665

1666

1667
    /**
1668
     * Returns the filteringExpressionsTree of the column.
1669
     * ```typescript
1670
     * let tree =  this.column.filteringExpressionsTree;
1671
     * ```
1672
     *
1673
     * @memberof IgxColumnComponent
1674
     */
1675
    public get filteringExpressionsTree(): FilteringExpressionsTree {
1676
        return ExpressionsTreeUtil.find(this.grid.filteringExpressionsTree, this.field) as FilteringExpressionsTree;
63,581✔
1677
    }
1678

1679
    /* alternateName: parentColumn */
1680
    /**
1681
     * Sets/gets the parent column.
1682
     * ```typescript
1683
     * let parentColumn = this.column.parent;
1684
     * ```
1685
     * ```typescript
1686
     * this.column.parent = higherLevelColumn;
1687
     * ```
1688
     *
1689
     * @memberof IgxColumnComponent
1690
     */
1691
    public parent = null;
29,145✔
1692

1693
    /* blazorSuppress */
1694
    /**
1695
     * Sets/gets the children columns.
1696
     * ```typescript
1697
     * let columnChildren = this.column.children;
1698
     * ```
1699
     *
1700
     * @deprecated in version 18.1.0. Use the `childColumns` property instead.
1701
     */
1702
    public children: QueryList<IgxColumnComponent>;
1703
    /**
1704
     * @hidden
1705
     */
1706
    public destroy$ = new Subject<any>();
29,145✔
1707

1708
    /**
1709
     * @hidden
1710
     */
1711
    protected _applySelectableClass = false;
29,145✔
1712

1713
    protected _vIndex = NaN;
29,145✔
1714
    /**
1715
     * @hidden
1716
     */
1717
    protected _pinned = false;
29,145✔
1718
    /**
1719
     * @hidden
1720
     */
1721
    protected _bodyTemplate: TemplateRef<IgxCellTemplateContext>;
1722
    /**
1723
     * @hidden
1724
     */
1725
    protected _errorTemplate: TemplateRef<IgxCellTemplateContext>;
1726
    /**
1727
     * @hidden
1728
     */
1729
    protected _headerTemplate: TemplateRef<IgxColumnTemplateContext>;
1730
    /**
1731
     * @hidden
1732
     */
1733
    protected _summaryTemplate: TemplateRef<IgxSummaryTemplateContext>;
1734
    /**
1735
     * @hidden
1736
     */
1737
    protected _inlineEditorTemplate: TemplateRef<IgxCellTemplateContext>;
1738
    /**
1739
     * @hidden
1740
     */
1741
    protected _filterCellTemplate: TemplateRef<IgxColumnTemplateContext>;
1742
    /**
1743
     * @hidden
1744
     */
1745
    protected _summaries = null;
29,145✔
1746
    /**
1747
     * @hidden
1748
     */
1749
    protected _filters = null;
29,145✔
1750
    /**
1751
     * @hidden
1752
     */
1753
    protected _sortStrategy: ISortingStrategy = DefaultSortingStrategy.instance();
29,145✔
1754
    /**
1755
     * @hidden
1756
     */
1757
    protected _groupingComparer: (a: any, b: any, currRec?: any, groupRec?: any) => number;
1758
    /**
1759
     * @hidden
1760
     */
1761
    protected _hidden = false;
29,145✔
1762
    /**
1763
     * @hidden
1764
     */
1765
    protected _index: number;
1766
    /**
1767
     * @hidden
1768
     */
1769
    protected _disablePinning = false;
29,145✔
1770
    /**
1771
     * @hidden
1772
     */
1773
    protected _width: string;
1774
    /**
1775
     * @hidden
1776
     */
1777
    protected _defaultMinWidth = '';
29,145✔
1778
    /**
1779
     * @hidden
1780
     */
1781
    protected _hasSummary = false;
29,145✔
1782
    /**
1783
     * @hidden
1784
     */
1785
    protected _editable: boolean;
1786
    /**
1787
     * @hidden
1788
     */
1789
    protected _groupable = false;
29,145✔
1790
    /**
1791
     *  @hidden
1792
     */
1793
    protected _visibleWhenCollapsed;
1794
    /**
1795
     * @hidden
1796
     */
1797
    protected _collapsible = false;
29,145✔
1798
    /**
1799
     * @hidden
1800
     */
1801
    protected _expanded = true;
29,145✔
1802
    /**
1803
     * @hidden
1804
     */
1805
    protected _selectable = true;
29,145✔
1806
    /**
1807
     * @hidden
1808
     */
1809
    protected get isPrimaryColumn(): boolean {
1810
        return this.field !== undefined && this.grid !== undefined && this.field === this.grid.primaryKey;
2,409,415✔
1811
    }
1812

1813
    private _field: string;
1814
    private _calcWidth = null;
29,145✔
1815
    private _columnPipeArgs: IColumnPipeArgs = { digitsInfo: DEFAULT_DIGITS_INFO };
29,145✔
1816
    private _editorOptions: IColumnEditorOptions = { };
29,145✔
1817

1818
    constructor(
1819
        @Inject(IGX_GRID_BASE) public grid: GridType,
29,145✔
1820
        @Optional() @Self() @Inject(NG_VALIDATORS) private _validators: Validator[],
29,145✔
1821
        /** @hidden @internal **/
1822
        public cdr: ChangeDetectorRef,
29,145✔
1823
        protected platform: PlatformUtil,
29,145✔
1824
    ) {
1825
        this.validators = _validators;
29,145✔
1826
    }
1827

1828
    /**
1829
     * @hidden
1830
     * @internal
1831
     */
1832
    public resetCaches() {
1833
        this._vIndex = NaN;
285,802✔
1834
        if (this.grid) {
285,802✔
1835
            this.cacheCalcWidth();
285,802✔
1836
        }
1837
    }
1838

1839
    /**
1840
     * @hidden
1841
     */
1842
    public ngOnDestroy() {
1843
        this.destroy$.next(true);
16,138✔
1844
        this.destroy$.complete();
16,138✔
1845
    }
1846
    /**
1847
     * @hidden
1848
     */
1849
    public ngAfterContentInit(): void {
1850
        if (this.summaryTemplateDirective) {
23,991✔
1851
            this._summaryTemplate = this.summaryTemplateDirective.template;
6✔
1852
        }
1853
        if (this.cellTemplate) {
23,991✔
1854
            this._bodyTemplate = this.cellTemplate.template;
44✔
1855
        }
1856
        if (this.cellValidationErrorTemplate) {
23,991✔
1857
            this._errorTemplate = this.cellValidationErrorTemplate.template;
16✔
1858
        }
1859
        if (this.headTemplate && this.headTemplate.length) {
23,991✔
1860
            this._headerTemplate = this.headTemplate.toArray()[0].template;
81✔
1861
        }
1862
        if (this.editorTemplate) {
23,991✔
1863
            this._inlineEditorTemplate = this.editorTemplate.template;
4✔
1864
        }
1865
        if (this.filterCellTemplateDirective) {
23,991!
1866
            this._filterCellTemplate = this.filterCellTemplateDirective.template;
×
1867
        }
1868
        if (!this._columnPipeArgs.format) {
23,991✔
1869
            this._columnPipeArgs.format = this.dataType === GridColumnDataType.Time ?
22,723✔
1870
                DEFAULT_TIME_FORMAT : this.dataType === GridColumnDataType.DateTime ?
22,411✔
1871
                    DEFAULT_DATE_TIME_FORMAT : DEFAULT_DATE_FORMAT;
1872
        }
1873
        if (!this.summaries) {
23,991✔
1874
            switch (this.dataType) {
22,672✔
1875
                case GridColumnDataType.Number:
1876
                case GridColumnDataType.Currency:
1877
                case GridColumnDataType.Percent:
1878
                    this.summaries = IgxNumberSummaryOperand;
6,795✔
1879
                    break;
6,795✔
1880
                case GridColumnDataType.Date:
1881
                case GridColumnDataType.DateTime:
1882
                    this.summaries = IgxDateSummaryOperand;
1,809✔
1883
                    break;
1,809✔
1884
                case GridColumnDataType.Time:
1885
                    this.summaries = IgxTimeSummaryOperand;
312✔
1886
                    break;
312✔
1887

1888
                case GridColumnDataType.String:
1889
                case GridColumnDataType.Boolean:
1890
                default:
1891
                    this.summaries = IgxSummaryOperand;
13,756✔
1892
                    break;
13,756✔
1893
            }
1894
        }
1895
        if (!this.filters) {
23,991✔
1896
            switch (this.dataType) {
22,385✔
1897
                case GridColumnDataType.Boolean:
1898
                    this.filters = IgxBooleanFilteringOperand.instance();
1,198✔
1899
                    break;
1,198✔
1900
                case GridColumnDataType.Number:
1901
                case GridColumnDataType.Currency:
1902
                case GridColumnDataType.Percent:
1903
                    this.filters = IgxNumberFilteringOperand.instance();
6,837✔
1904
                    break;
6,837✔
1905
                case GridColumnDataType.Date:
1906
                    this.filters = IgxDateFilteringOperand.instance();
1,546✔
1907
                    break;
1,546✔
1908
                case GridColumnDataType.Time:
1909
                    this.filters = IgxTimeFilteringOperand.instance();
312✔
1910
                    break;
312✔
1911
                case GridColumnDataType.DateTime:
1912
                    this.filters = IgxDateTimeFilteringOperand.instance();
268✔
1913
                    break;
268✔
1914
                case GridColumnDataType.Image:
1915
                    this.filterable = false;
1✔
1916
                    break;
1✔
1917
                case GridColumnDataType.String:
1918
                default:
1919
                    this.filters = IgxStringFilteringOperand.instance();
12,223✔
1920
                    break;
12,223✔
1921
            }
1922
        }
1923
    }
1924

1925
    /**
1926
     * @hidden
1927
     */
1928
    public getGridTemplate(isRow: boolean): string {
1929
        if (isRow) {
27,348✔
1930
            const rowsCount = this.grid.type !== 'pivot' ? this.grid.multiRowLayoutRowSize : this.children.length - 1;
13,675!
1931
            return `repeat(${rowsCount},1fr)`;
13,675✔
1932
        } else {
1933
            return this.getColumnSizesString(this.children);
13,673✔
1934
        }
1935
    }
1936

1937
    /** @hidden @internal **/
1938
    public getInitialChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<MRLColumnSizeInfo> {
1939
        const columnSizes: MRLColumnSizeInfo[] = [];
149,999✔
1940
        // find the smallest col spans
1941
        children.forEach(col => {
149,999✔
1942
            if (!col.colStart) {
469,375✔
1943
                return;
106,154✔
1944
            }
1945
            const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
363,221✔
1946
            const newSpanSmaller = columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].colSpan > col.gridColumnSpan;
363,221✔
1947
            const bothWidthsSet = col.widthSetByUser && columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].widthSetByUser;
363,221✔
1948
            const bothWidthsNotSet = !col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
363,221✔
1949

1950
            if (columnSizes[col.colStart - 1] === undefined) {
363,221✔
1951
                // If nothing is defined yet take any column at first
1952
                // We use colEnd to know where the column actually ends, because not always it starts where we have it set in columnSizes.
1953
                columnSizes[col.colStart - 1] = {
223,203✔
1954
                    ref: col,
1955
                    width: col.width === 'fit-content' ? col.autoSize :
223,203!
1956
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null,
652,762✔
1957
                    colSpan: col.gridColumnSpan,
1958
                    colEnd: col.colStart + col.gridColumnSpan,
1959
                    widthSetByUser: col.widthSetByUser
1960
                };
1961
            } else if (newWidthSet || (newSpanSmaller && ((bothWidthsSet) || (bothWidthsNotSet)))) {
140,018✔
1962
                // If a column is set already it should either not have width defined or have width with bigger span than the new one.
1963

1964
                /**
1965
                 *  If replaced column has bigger span, we want to fill the remaining columns
1966
                 *  that the replacing column does not fill with the old one.
1967
                 */
1968
                if (bothWidthsSet && newSpanSmaller) {
49,990✔
1969
                    // Start from where the new column set would end and apply the old column to the rest depending on how much it spans.
1970
                    // We have not yet replaced it so we can use it directly from the columnSizes collection.
1971
                    // This is where colEnd is used because the colStart of the old column is not actually i + 1.
1972
                    for (let i = col.colStart - 1 + col.gridColumnSpan; i < columnSizes[col.colStart - 1].colEnd - 1; i++) {
4,897✔
1973
                        if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
2,831✔
1974
                            columnSizes[i] = columnSizes[col.colStart - 1];
2,764✔
1975
                        } else {
1976
                            break;
67✔
1977
                        }
1978
                    }
1979
                }
1980

1981
                // Replace the old column with the new one.
1982
                columnSizes[col.colStart - 1] = {
49,990✔
1983
                    ref: col,
1984
                    width: col.width === 'fit-content' ? col.autoSize :
49,990!
1985
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null,
141,403✔
1986
                    colSpan: col.gridColumnSpan,
1987
                    colEnd: col.colStart + col.gridColumnSpan,
1988
                    widthSetByUser: col.widthSetByUser
1989
                };
1990
            } else if (bothWidthsSet && columnSizes[col.colStart - 1].colSpan < col.gridColumnSpan) {
90,028✔
1991
                // If the column already in the columnSizes has smaller span, we still need to fill any empty places with the current col.
1992
                // Start from where the smaller column set would end and apply the bigger column to the rest depending on how much it spans.
1993
                // Since here we do not have it in columnSizes we set it as a new column keeping the same colSpan.
1994
                for (let i = col.colStart - 1 + columnSizes[col.colStart - 1].colSpan; i < col.colStart - 1 + col.gridColumnSpan; i++) {
3,523✔
1995
                    if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
3,523✔
1996
                        columnSizes[i] = {
51✔
1997
                            ref: col,
1998
                            width: col.width === 'fit-content' ? col.autoSize :
51!
1999
                                col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null,
102!
2000
                            colSpan: col.gridColumnSpan,
2001
                            colEnd: col.colStart + col.gridColumnSpan,
2002
                            widthSetByUser: col.widthSetByUser
2003
                        };
2004
                    } else {
2005
                        break;
3,472✔
2006
                    }
2007
                }
2008
            }
2009
        });
2010

2011
        // Flatten columnSizes so there are not columns with colSpan > 1
2012
        for (let i = 0; i < columnSizes.length; i++) {
149,999✔
2013
            if (columnSizes[i] && columnSizes[i].colSpan > 1) {
221,341✔
2014
                let j = 1;
10,910✔
2015

2016
                // Replace all empty places depending on how much the current column spans starting from next col.
2017
                for (; j < columnSizes[i].colSpan && i + j + 1 < columnSizes[i].colEnd; j++) {
10,910✔
2018
                    if (columnSizes[i + j] &&
10,517✔
2019
                        ((!columnSizes[i].width && columnSizes[i + j].width) ||
2020
                            (!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
2021
                            (!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
2022
                        // If we reach an already defined column that has width and the current doesn't have or
2023
                        // if the reached column has bigger colSpan we stop.
2024
                        break;
4,422✔
2025
                    } else {
2026
                        const width = columnSizes[i].widthSetByUser ?
6,095✔
2027
                            columnSizes[i].width / columnSizes[i].colSpan :
2028
                            columnSizes[i].width;
2029
                        columnSizes[i + j] = {
6,095✔
2030
                            ref: columnSizes[i].ref,
2031
                            width,
2032
                            colSpan: 1,
2033
                            colEnd: columnSizes[i].colEnd,
2034
                            widthSetByUser: columnSizes[i].widthSetByUser
2035
                        };
2036
                    }
2037
                }
2038

2039
                // Update the current column width so it is divided between all columns it spans and set it to 1.
2040
                columnSizes[i].width = columnSizes[i].widthSetByUser ?
10,910✔
2041
                    columnSizes[i].width / columnSizes[i].colSpan :
2042
                    columnSizes[i].width;
2043
                columnSizes[i].colSpan = 1;
10,910✔
2044

2045
                // Update the index based on how much we have replaced. Subtract 1 because we started from 1.
2046
                i += j - 1;
10,910✔
2047
            }
2048
        }
2049

2050
        return columnSizes;
149,999✔
2051
    }
2052

2053
    /** @hidden @internal **/
2054
    public getFilledChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<string> {
2055
        const columnSizes = this.getInitialChildColumnSizes(children);
26,275✔
2056

2057
        // fill the gaps if there are any
2058
        const result: string[] = [];
26,275✔
2059
        for (const size of columnSizes) {
26,275✔
2060
            if (size && !!size.width) {
58,737✔
2061
                result.push(size.width + 'px');
22,862✔
2062
            } else {
2063
                result.push(parseInt(this.grid.getPossibleColumnWidth(), 10) + 'px');
35,875✔
2064
            }
2065
        }
2066
        return result;
26,275✔
2067
    }
2068

2069
    /** @hidden @internal **/
2070
    public getResizableColUnderEnd(): MRLResizeColumnInfo[] {
2071
        if (this.columnLayout || !this.columnLayoutChild || this.columnGroup) {
6!
2072
            return [{ target: this, spanUsed: 1 }];
×
2073
        }
2074

2075
        const columnSized = this.getInitialChildColumnSizes(this.parent.children);
6✔
2076
        const targets: MRLResizeColumnInfo[] = [];
6✔
2077
        const colEnd = this.colEnd ? this.colEnd : this.colStart + 1;
6!
2078

2079
        for (let i = 0; i < columnSized.length; i++) {
6✔
2080
            if (this.colStart <= i + 1 && i + 1 < colEnd) {
36✔
2081
                targets.push({ target: columnSized[i].ref, spanUsed: 1 });
10✔
2082
            }
2083
        }
2084

2085
        const targetsSquashed: MRLResizeColumnInfo[] = [];
6✔
2086
        for (const target of targets) {
6✔
2087
            if (targetsSquashed.length && targetsSquashed[targetsSquashed.length - 1].target.field === target.target.field) {
10!
2088
                targetsSquashed[targetsSquashed.length - 1].spanUsed++;
×
2089
            } else {
2090
                targetsSquashed.push(target);
10✔
2091
            }
2092
        }
2093

2094
        return targetsSquashed;
6✔
2095
    }
2096

2097
    /**
2098
     * Pins the column at the provided index in the pinned area.
2099
     * Defaults to index `0` if not provided, or to the initial index in the pinned area.
2100
     * Returns `true` if the column is successfully pinned. Returns `false` if the column cannot be pinned.
2101
     * Column cannot be pinned if:
2102
     * - Is already pinned
2103
     * - index argument is out of range
2104
     * - The pinned area exceeds 80% of the grid width
2105
     * ```typescript
2106
     * let success = this.column.pin();
2107
     * ```
2108
     *
2109
     * @memberof IgxColumnComponent
2110
     */
2111
    public pin(index?: number): boolean {
2112
        // TODO: Probably should the return type of the old functions
2113
        // should be moved as a event parameter.
2114
        const grid = (this.grid as any);
613✔
2115
        if (this._pinned) {
613✔
2116
            return false;
56✔
2117
        }
2118

2119
        if (this.parent && !this.parent.pinned) {
557✔
2120
            return this.topLevelParent.pin(index);
10✔
2121
        }
2122

2123
        const hasIndex = index !== undefined;
547✔
2124
        if (hasIndex && (index < 0 || index > grid.pinnedColumns.length)) {
547✔
2125
            return false;
2✔
2126
        }
2127

2128
        if (!this.parent && !this.pinnable) {
545!
2129
            return false;
×
2130
        }
2131

2132
        const rootPinnedCols = grid._pinnedColumns.filter((c) => c.level === 0);
1,080✔
2133
        index = hasIndex ? index : rootPinnedCols.length;
545✔
2134
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: false, cancel: false };
545✔
2135
        this.grid.columnPin.emit(args);
545✔
2136

2137
        if (args.cancel) {
545!
2138
            return;
×
2139
        }
2140

2141
        this.grid.crudService.endEdit(false);
545✔
2142

2143
        this._pinned = true;
545✔
2144
        this.pinnedChange.emit(this._pinned);
545✔
2145
        // it is possible that index is the last position, so will need to find target column by [index-1]
2146
        const targetColumn = args.insertAtIndex === grid._pinnedColumns.length ?
545✔
2147
            grid._pinnedColumns[args.insertAtIndex - 1] : grid._pinnedColumns[args.insertAtIndex];
2148

2149
        if (grid._pinnedColumns.indexOf(this) === -1) {
545✔
2150
            if (!grid.hasColumnGroups) {
420✔
2151
                grid._pinnedColumns.splice(args.insertAtIndex, 0, this);
371✔
2152
            } else {
2153
                // insert based only on root collection
2154
                rootPinnedCols.splice(args.insertAtIndex, 0, this);
49✔
2155
                let allPinned = [];
49✔
2156
                // re-create hierarchy
2157
                rootPinnedCols.forEach(group => {
49✔
2158
                    allPinned.push(group);
86✔
2159
                    allPinned = allPinned.concat(group.allChildren);
86✔
2160
                });
2161
                grid._pinnedColumns = allPinned;
49✔
2162
            }
2163

2164
            if (grid._unpinnedColumns.indexOf(this) !== -1) {
420✔
2165
                const childrenCount = this.allChildren.length;
189✔
2166
                grid._unpinnedColumns.splice(grid._unpinnedColumns.indexOf(this), 1 + childrenCount);
189✔
2167
            }
2168
        }
2169

2170
        if (hasIndex) {
545✔
2171
            index === grid._pinnedColumns.length - 1 ?
10✔
2172
                grid._moveColumns(this, targetColumn, DropPosition.AfterDropTarget) : grid._moveColumns(this, targetColumn, DropPosition.BeforeDropTarget);
2173
        }
2174

2175
        if (this.columnGroup) {
545✔
2176
            this.allChildren.forEach(child => child.pin());
186✔
2177
            grid.reinitPinStates();
59✔
2178
        }
2179

2180
        grid.resetCaches();
545✔
2181
        grid.notifyChanges();
545✔
2182
        if (this.columnLayoutChild) {
545✔
2183
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
407✔
2184
        }
2185
        this.grid.filteringService.refreshExpressions();
545✔
2186
        const eventArgs: IPinColumnEventArgs = { column: this, insertAtIndex: index, isPinned: true };
545✔
2187
        this.grid.columnPinned.emit(eventArgs);
545✔
2188
        return true;
545✔
2189
    }
2190
    /**
2191
     * Unpins the column and place it at the provided index in the unpinned area.
2192
     * Defaults to index `0` if not provided, or to the initial index in the unpinned area.
2193
     * Returns `true` if the column is successfully unpinned. Returns `false` if the column cannot be unpinned.
2194
     * Column cannot be unpinned if:
2195
     * - Is already unpinned
2196
     * - index argument is out of range
2197
     * ```typescript
2198
     * let success = this.column.unpin();
2199
     * ```
2200
     *
2201
     * @memberof IgxColumnComponent
2202
     */
2203
    public unpin(index?: number): boolean {
2204
        const grid = (this.grid as any);
173✔
2205
        if (!this._pinned) {
173✔
2206
            return false;
32✔
2207
        }
2208

2209
        if (this.parent && this.parent.pinned) {
141✔
2210
            return this.topLevelParent.unpin(index);
7✔
2211
        }
2212
        const hasIndex = index !== undefined;
134✔
2213
        if (hasIndex && (index < 0 || index > grid._unpinnedColumns.length)) {
134✔
2214
            return false;
2✔
2215
        }
2216

2217
        // estimate the exact index at which column will be inserted
2218
        // takes into account initial unpinned index of the column
2219
        if (!hasIndex) {
132✔
2220
            const indices = grid.unpinnedColumns.map(col => col.index);
1,082✔
2221
            indices.push(this.index);
128✔
2222
            indices.sort((a, b) => a - b);
1,413✔
2223
            index = indices.indexOf(this.index);
128✔
2224
        }
2225

2226
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: true, cancel: false };
132✔
2227
        this.grid.columnPin.emit(args);
132✔
2228

2229
        if (args.cancel) {
132!
2230
            return;
×
2231
        }
2232

2233
        this.grid.crudService.endEdit(false);
132✔
2234

2235
        this._pinned = false;
132✔
2236
        this.pinnedChange.emit(this._pinned);
132✔
2237

2238
        // it is possible that index is the last position, so will need to find target column by [index-1]
2239
        const targetColumn = args.insertAtIndex === grid._unpinnedColumns.length ?
132✔
2240
            grid._unpinnedColumns[args.insertAtIndex - 1] : grid._unpinnedColumns[args.insertAtIndex];
2241

2242
        if (!hasIndex) {
132✔
2243
            grid._unpinnedColumns.splice(index, 0, this);
128✔
2244
            if (grid._pinnedColumns.indexOf(this) !== -1) {
128✔
2245
                grid._pinnedColumns.splice(grid._pinnedColumns.indexOf(this), 1);
128✔
2246
            }
2247
        }
2248

2249
        if (hasIndex) {
132✔
2250
            grid.moveColumn(this, targetColumn);
4✔
2251
        }
2252

2253
        if (this.columnGroup) {
132✔
2254
            this.allChildren.forEach(child => child.unpin());
94✔
2255
        }
2256

2257
        grid.reinitPinStates();
132✔
2258
        grid.resetCaches();
132✔
2259

2260
        grid.notifyChanges();
132✔
2261
        if (this.columnLayoutChild) {
132✔
2262
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
236✔
2263
        }
2264
        this.grid.filteringService.refreshExpressions();
132✔
2265

2266
        this.grid.columnPinned.emit({ column: this, insertAtIndex: index, isPinned: false });
132✔
2267

2268
        return true;
132✔
2269
    }
2270

2271
    /**
2272
     * Moves a column to the specified visible index.
2273
     * If passed index is invalid, or if column would receive a different visible index after moving, moving is not performed.
2274
     * If passed index would move the column to a different column group. moving is not performed.
2275
     *
2276
     * @example
2277
     * ```typescript
2278
     * column.move(index);
2279
     * ```
2280
     * @memberof IgxColumnComponent
2281
     */
2282
    public move(index: number) {
2283
        let target;
2284
        let columns = this.grid.columns.filter(c => c.visibleIndex > -1);
349✔
2285
        // grid last visible index
2286
        const li = columns.map(c => c.visibleIndex).reduce((a, b) => Math.max(a, b));
343✔
2287
        const parent = this.parent;
36✔
2288
        const isPreceding = this.visibleIndex < index;
36✔
2289

2290
        if (index === this.visibleIndex || index < 0 || index > li) {
36✔
2291
            return;
3✔
2292
        }
2293

2294
        if (parent) {
33✔
2295
            columns = columns.filter(c => c.level >= this.level && c !== this && c.parent !== this &&
84✔
2296
                c.topLevelParent === this.topLevelParent);
2297
        }
2298
        /* eslint-disable max-len */
2299
        // 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.
2300
        // 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.
2301
        /* eslint-enable max-len */
2302
        if (isPreceding) {
33✔
2303
            columns = columns.filter(c => c.visibleIndex > this.visibleIndex);
200✔
2304
            target = columns.find(c => c.level === this.level && c.visibleIndex + (c as any).calcChildren() - this.calcChildren() === index);
80✔
2305
        } else {
2306
            columns = columns.filter(c => c.visibleIndex < this.visibleIndex);
65✔
2307
            target = columns.find(c => c.level === this.level && c.visibleIndex === index);
15✔
2308
        }
2309

2310
        if (!target || (target.pinned && this.disablePinning)) {
33✔
2311
            return;
9✔
2312
        }
2313

2314
        const pos = isPreceding ? DropPosition.AfterDropTarget : DropPosition.BeforeDropTarget;
24✔
2315
        this.grid.moveColumn(this, target as IgxColumnComponent, pos);
24✔
2316
    }
2317

2318
    /**
2319
     * No children for the column, so will returns 1 or 0, if the column is hidden.
2320
     *
2321
     * @hidden
2322
     */
2323
    public calcChildren(): number {
2324
        const children = this.hidden ? 0 : 1;
70✔
2325
        return children;
70✔
2326
    }
2327

2328
    /**
2329
     * Toggles column vibisility and emits the respective event.
2330
     *
2331
     * @hidden
2332
     */
2333
    public toggleVisibility(value?: boolean) {
2334
        const newValue = value ?? !this.hidden;
65✔
2335
        const eventArgs: IColumnVisibilityChangingEventArgs = { column: this, newValue, cancel: false };
65✔
2336
        this.grid.columnVisibilityChanging.emit(eventArgs);
65✔
2337

2338
        if (eventArgs.cancel) {
65!
2339
            return;
×
2340
        }
2341
        this.hidden = newValue;
65✔
2342
        this.grid.columnVisibilityChanged.emit({ column: this, newValue });
65✔
2343
    }
2344

2345
    /**
2346
     * Returns a reference to the top level parent column.
2347
     * ```typescript
2348
     * let topLevelParent =  this.column.topLevelParent;
2349
     * ```
2350
     */
2351
    public get topLevelParent(): ColumnType | undefined {
2352
        let parent = this.parent;
490✔
2353
        while (parent && parent.parent) {
490✔
2354
            parent = parent.parent;
34✔
2355
        }
2356
        return parent ?? undefined;
490✔
2357
    }
2358

2359
    /**
2360
     * @hidden @internal
2361
     */
2362
    public get headerCell(): IgxGridHeaderComponent {
2363
        return this.grid.headerCellList.find((header) => header.column === this);
1,574✔
2364
    }
2365

2366
    /**
2367
     * @hidden @internal
2368
     */
2369
    public get filterCell(): IgxGridFilteringCellComponent {
2370
        return this.grid.filterCellList.find((filterCell) => filterCell.column === this);
7,009✔
2371
    }
2372

2373
    /**
2374
     * @hidden @internal
2375
     */
2376
    public get headerGroup(): IgxGridHeaderGroupComponent {
2377
        return this.grid.headerGroupsList.find(group => group.column === this);
6,309✔
2378
    }
2379

2380
    /**
2381
     * Autosize the column to the longest currently visible cell value, including the header cell.
2382
     * ```typescript
2383
     * @ViewChild('grid') grid: IgxGridComponent;
2384
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2385
     * column.autosize();
2386
     * ```
2387
     *
2388
     * @memberof IgxColumnComponent
2389
     * @param byHeaderOnly Set if column should be autosized based only on the header content.
2390
     */
2391
    public autosize(byHeaderOnly = false) {
17✔
2392
        if (!this.columnGroup) {
18✔
2393
            this.width = this.getAutoSize(byHeaderOnly);
18✔
2394
            this.grid.reflow();
18✔
2395
        }
2396
    }
2397

2398
    /**
2399
     * @hidden
2400
     */
2401
    public getAutoSize(byHeader = false): string {
8✔
2402
        const size = !byHeader ? this.getLargestCellWidth() :
26✔
2403
            (Object.values(this.getHeaderCellWidths()).reduce((a, b) => a + b) + 'px');
1✔
2404
        const isPercentageWidth = this.width && typeof this.width === 'string' && this.width.indexOf('%') !== -1;
26✔
2405

2406
        let newWidth;
2407
        if (isPercentageWidth) {
26✔
2408
            const gridAvailableSize = this.grid.calcWidth;
2✔
2409
            const percentageSize = parseFloat(size) / gridAvailableSize * 100;
2✔
2410
            newWidth = percentageSize + '%';
2✔
2411
        } else {
2412
            newWidth = size;
24✔
2413
        }
2414

2415
        const maxWidth = isPercentageWidth ? this.maxWidthPercent : this.maxWidthPx;
26✔
2416
        const minWidth = isPercentageWidth ? this.minWidthPercent : this.minWidthPx;
26✔
2417
        if (this.maxWidth && (parseFloat(newWidth) > maxWidth)) {
26✔
2418
            newWidth = isPercentageWidth ? maxWidth + '%' : maxWidth + 'px';
1!
2419
        } else if (parseFloat(newWidth) < minWidth) {
25✔
2420
            newWidth = isPercentageWidth ? minWidth + '%' : minWidth + 'px';
1!
2421
        }
2422

2423
        return newWidth;
26✔
2424
    }
2425

2426
    /**
2427
     * @hidden
2428
     */
2429
    public getCalcWidth(): any {
2430
        if (this._calcWidth && !isNaN(this.calcPixelWidth)) {
238,477✔
2431
            return this._calcWidth;
232,211✔
2432
        }
2433
        this.cacheCalcWidth();
6,266✔
2434
        return this._calcWidth;
6,266✔
2435
    }
2436

2437

2438
    /**
2439
     * @hidden
2440
     * Returns the width and padding of a header cell.
2441
     */
2442
    public getHeaderCellWidths() {
2443
        return this.grid.getHeaderCellWidth(this.headerCell.nativeElement);
25✔
2444
    }
2445

2446
    /**
2447
     * @hidden
2448
     * Returns the size (in pixels) of the longest currently visible cell, including the header cell.
2449
     * ```typescript
2450
     * @ViewChild('grid') grid: IgxGridComponent;
2451
     *
2452
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2453
     * let size = column.getLargestCellWidth();
2454
     * ```
2455
     * @memberof IgxColumnComponent
2456
     */
2457
    public getLargestCellWidth(): string {
2458
        const range = this.grid.document.createRange();
25✔
2459
        const largest = new Map<number, number>();
25✔
2460

2461
        if (this._cells.length > 0) {
25✔
2462
            const cellsContentWidths = [];
25✔
2463
            this._cells.forEach((cell) => cellsContentWidths.push(cell.calculateSizeToFit(range)));
270✔
2464

2465
            const index = cellsContentWidths.indexOf(Math.max(...cellsContentWidths));
25✔
2466
            const cellStyle = this.grid.document.defaultView.getComputedStyle(this._cells[index].nativeElement);
25✔
2467
            const cellPadding = parseFloat(cellStyle.paddingLeft) + parseFloat(cellStyle.paddingRight) +
25✔
2468
                parseFloat(cellStyle.borderLeftWidth) + parseFloat(cellStyle.borderRightWidth);
2469

2470
            largest.set(Math.max(...cellsContentWidths), cellPadding);
25✔
2471
        }
2472

2473
        if (this.headerCell && this.autosizeHeader) {
25✔
2474
            const headerCellWidths = this.getHeaderCellWidths();
24✔
2475
            largest.set(headerCellWidths.width, headerCellWidths.padding);
24✔
2476
        }
2477

2478
        const largestCell = Math.max(...Array.from(largest.keys()));
25✔
2479
        const width = Math.ceil(largestCell + largest.get(largestCell));
25✔
2480

2481
        if (Number.isNaN(width)) {
25!
2482
            return this.width;
×
2483
        } else {
2484
            return width + 'px';
25✔
2485
        }
2486
    }
2487

2488
    /**
2489
     * @hidden
2490
     */
2491
    public getCellWidth() {
2492
        const colWidth = this.width;
1,161,848✔
2493
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
1,161,848✔
2494

2495
        if (this.columnLayoutChild) {
1,161,848!
2496
            return '';
×
2497
        }
2498

2499
        if (colWidth && !isPercentageWidth) {
1,161,848✔
2500

2501
            let cellWidth = colWidth;
1,150,423✔
2502
            if (typeof cellWidth !== 'string' || cellWidth.endsWith('px') === false) {
1,150,423✔
2503
                cellWidth += 'px';
2,609✔
2504
            }
2505

2506
            return cellWidth;
1,150,423✔
2507
        } else {
2508
            return colWidth;
11,425✔
2509
        }
2510
    }
2511

2512
    /**
2513
     * @hidden
2514
     */
2515
    public populateVisibleIndexes() { }
2516

2517
    protected getColumnSizesString(children: QueryList<IgxColumnComponent>): string {
2518
        const res = this.getFilledChildColumnSizes(children);
13,673✔
2519
        return res.join(' ');
13,673✔
2520
    }
2521

2522
    /**
2523
     * @hidden
2524
     * @internal
2525
     */
2526
    protected cacheCalcWidth(): any {
2527
        const colWidth = this.width;
305,828✔
2528
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
305,828✔
2529
        const isAutoWidth = colWidth && typeof colWidth === 'string' && colWidth === 'fit-content';
305,828✔
2530
        if (isPercentageWidth && this.grid.isColumnWidthSum) {
305,828✔
2531
            this._calcWidth = this.grid.minColumnWidth;
32✔
2532
        } else if (isPercentageWidth ) {
305,796✔
2533
            this._calcWidth = Math.floor(parseFloat(colWidth) / 100 * this.grid.calcWidth);
906✔
2534
        } else if (!colWidth || isAutoWidth && !this.autoSize) {
304,890✔
2535
            // no width
2536
            this._calcWidth = this.defaultWidth || this.grid.getPossibleColumnWidth();
26,394✔
2537
        } else {
2538
            this._calcWidth = this.width;
278,496✔
2539
        }
2540
        this.calcPixelWidth = parseInt(this._calcWidth, 10);
305,828✔
2541
    }
2542

2543
    /**
2544
     * @hidden
2545
     * @internal
2546
     */
2547
    protected setExpandCollapseState() {
2548
        this.children.filter(col => (col.visibleWhenCollapsed !== undefined)).forEach(c => {
280✔
2549
            if (!this.collapsible) {
255✔
2550
                c.hidden = this.hidden; return;
2✔
2551
            }
2552
            c.hidden = this._expanded ? c.visibleWhenCollapsed : !c.visibleWhenCollapsed;
253✔
2553
        });
2554
    }
2555
    /**
2556
     * @hidden
2557
     * @internal
2558
     */
2559
    protected checkCollapsibleState() {
2560
        if (!this.children) {
2,406!
2561
            return false;
×
2562
        }
2563
        const cols = this.children.map(child => child.visibleWhenCollapsed);
5,894✔
2564
        return (cols.some(c => c === true) && cols.some(c => c === false));
3,648✔
2565
    }
2566

2567
    /**
2568
     * @hidden
2569
     */
2570
    public get pinnable() {
2571
        return (this.grid as any)._init || !this.pinned;
401✔
2572
    }
2573

2574
    /**
2575
     * @hidden
2576
     */
2577
    public get applySelectableClass(): boolean {
2578
        return this._applySelectableClass;
11,025✔
2579
    }
2580

2581
    /**
2582
     * @hidden
2583
     */
2584
    public set applySelectableClass(value: boolean) {
2585
        if (this.selectable) {
15✔
2586
            this._applySelectableClass = value;
13✔
2587
        }
2588
    }
2589
}
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