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

IgniteUI / igniteui-angular / 16193564787

10 Jul 2025 11:13AM UTC coverage: 4.657% (-87.0%) from 91.64%
16193564787

Pull #16028

github

web-flow
Merge ad90a37c4 into 87246e3ce
Pull Request #16028: fix(radio-group): dynamically added radio buttons do not initialize

178 of 15764 branches covered (1.13%)

18 of 19 new or added lines in 2 files covered. (94.74%)

25721 existing lines in 324 files now uncovered.

1377 of 29570 relevant lines covered (4.66%)

0.53 hits per line

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

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

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

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

109

110
    /**
111
     * @hidden @internal
112
     */
UNCOV
113
    public validators: Validator[] = [];
×
114

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

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

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

UNCOV
226
        if (this.isPrimaryColumn && (rowEditable || hasTransactions)) {
×
UNCOV
227
            return false;
×
228
        }
229

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

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

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

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

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

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

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

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

431
    /** @hidden */
432
    @Output()
UNCOV
433
    public collapsibleChange = new EventEmitter<boolean>();
×
434

435
    /** @hidden */
436
    @Output()
UNCOV
437
    public visibleWhenCollapsedChange = new EventEmitter<boolean>();
×
438

439
    /** @hidden @internal */
440
    @Output()
UNCOV
441
    public columnChange = new EventEmitter<void>();
×
442

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

468
    /**
469
     * Gets the `width` of the column.
470
     * ```typescript
471
     * let columnWidth = this.column.width;
472
     * ```
473
     *
474
     * @memberof IgxColumnComponent
475
     */
476
    @notifyChanges(true)
477
    @WatchColumnChanges()
478
    @Input()
479
    public get width(): string {
UNCOV
480
        const isAutoWidth = this._width && typeof this._width === 'string' && this._width === 'auto';
×
UNCOV
481
        if (isAutoWidth) {
×
UNCOV
482
            if (!this.autoSize) {
×
UNCOV
483
                return 'fit-content';
×
484
            } else {
UNCOV
485
                return this.autoSize + 'px';
×
486
            }
487

488
        }
UNCOV
489
        return this.widthSetByUser ? this._width : this.defaultWidth;
×
490
    }
491

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

526
    /** @hidden @internal **/
527
    public autoSize: number;
528

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

878
    /**
879
     * Emitted when the column width changes.
880
     *
881
     * ```html
882
     * <igx-column (widthChange)="widthChange($event)">
883
     * </igx-column>
884
     * ```
885
     *
886
     */
887
    @Output()
UNCOV
888
    public widthChange = new EventEmitter<string>();
×
889

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

944
    /** @hidden @internal **/
945
    public calcPixelWidth: number;
946

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

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

965
    /**
966
     * @hidden
967
     */
968
    public get minWidthPx() {
UNCOV
969
        const gridAvailableSize = this.grid.calcWidth;
×
UNCOV
970
        const isPercentageWidth = this.minWidth && typeof this.minWidth === 'string' && this.minWidth.indexOf('%') !== -1;
×
UNCOV
971
        return isPercentageWidth ? parseFloat(this.minWidth) / 100 * gridAvailableSize : parseFloat(this.minWidth);
×
972
    }
973

974
    /**
975
     * @hidden
976
     */
977
    public get userSetMinWidthPx() {
UNCOV
978
        const gridAvailableSize = this.grid.calcWidth;
×
UNCOV
979
        const isPercentageWidth = this._defaultMinWidth && typeof this._defaultMinWidth === 'string' && this._defaultMinWidth.indexOf('%') !== -1;
×
UNCOV
980
        return isPercentageWidth ? parseFloat(this._defaultMinWidth) / 100 * gridAvailableSize : parseFloat(this._defaultMinWidth);
×
981
    }
982

983
    /**
984
     * @hidden
985
     */
986
    public get minWidthPercent() {
UNCOV
987
        const gridAvailableSize = this.grid.calcWidth;
×
UNCOV
988
        const isPercentageWidth = this.minWidth && typeof this.minWidth === 'string' && this.minWidth.indexOf('%') !== -1;
×
UNCOV
989
        return isPercentageWidth ? parseFloat(this.minWidth) : parseFloat(this.minWidth) / gridAvailableSize * 100;
×
990
    }
991

992

993
    /**
994
     * Sets/gets the minimum `width` of the column.
995
     * Default value is `88`;
996
     * ```typescript
997
     * let columnMinWidth = this.column.minWidth;
998
     * ```
999
     * ```html
1000
     * <igx-column [minWidth] = "'100px'"></igx-column>
1001
     * ```
1002
     *
1003
     * @memberof IgxColumnComponent
1004
     */
1005
    @notifyChanges()
1006
    @WatchColumnChanges()
1007
    @Input()
1008
    public set minWidth(value: string) {
UNCOV
1009
        const minVal = parseFloat(value);
×
UNCOV
1010
        if (Number.isNaN(minVal)) {
×
UNCOV
1011
            return;
×
1012
        }
UNCOV
1013
        this._defaultMinWidth = value;
×
UNCOV
1014
        this.grid.notifyChanges(true);
×
1015
    }
1016
    public get minWidth(): string {
UNCOV
1017
        return !this._defaultMinWidth ? this.defaultMinWidth : this._defaultMinWidth;
×
1018
    }
1019

1020
    /** @hidden @internal **/
1021
    public get resolvedWidth(): string {
UNCOV
1022
        if (this.columnLayoutChild) {
×
1023
            return '';
×
1024
        }
UNCOV
1025
        const isAutoWidth = this._width && typeof this._width === 'string' && this._width === 'auto';
×
UNCOV
1026
        return isAutoWidth ? this.width : this.calcPixelWidth + 'px';
×
1027
    }
1028

1029
    /**
1030
     * Gets the column index.
1031
     * ```typescript
1032
     * let columnIndex = this.column.index;
1033
     * ```
1034
     *
1035
     * @memberof IgxColumnComponent
1036
     */
1037
    public get index(): number {
UNCOV
1038
        return (this.grid as any)._columns.indexOf(this);
×
1039
    }
1040

1041
    /**
1042
     * Gets whether the column is `pinned`.
1043
     * ```typescript
1044
     * let isPinned = this.column.pinned;
1045
     * ```
1046
     *
1047
     * @memberof IgxColumnComponent
1048
     */
1049
    @WatchColumnChanges()
1050
    @Input({ transform: booleanAttribute })
1051
    public get pinned(): boolean {
UNCOV
1052
        return this._pinned;
×
1053
    }
1054
    /**
1055
     * Sets whether the column is pinned.
1056
     * Default value is `false`.
1057
     * ```html
1058
     * <igx-column [pinned] = "true"></igx-column>
1059
     * ```
1060
     *
1061
     * Two-way data binding.
1062
     * ```html
1063
     * <igx-column [(pinned)] = "model.columns[0].isPinned"></igx-column>
1064
     * ```
1065
     *
1066
     * @memberof IgxColumnComponent
1067
     */
1068
    public set pinned(value: boolean) {
UNCOV
1069
        if (this._pinned !== value) {
×
UNCOV
1070
            const isAutoWidth = this.width && typeof this.width === 'string' && this.width === 'fit-content';
×
UNCOV
1071
            if (this.grid && this.width && (isAutoWidth || !isNaN(parseInt(this.width, 10)))) {
×
UNCOV
1072
                if (value) {
×
UNCOV
1073
                    this.pin();
×
1074
                } else {
UNCOV
1075
                    this.unpin();
×
1076
                }
UNCOV
1077
                return;
×
1078
            }
1079
            /* No grid/width available at initialization. `initPinning` in the grid
1080
               will re-init the group (if present)
1081
            */
UNCOV
1082
            this._pinned = value;
×
UNCOV
1083
            this.pinnedChange.emit(this._pinned);
×
1084
        }
1085
    }
1086

1087
    /* treatAsRef */
1088
    /**
1089
     * Gets the column `summaries`.
1090
     * ```typescript
1091
     * let columnSummaries = this.column.summaries;
1092
     * ```
1093
     *
1094
     * @memberof IgxColumnComponent
1095
     */
1096
    @notifyChanges(true)
1097
    @WatchColumnChanges()
1098
    @Input()
1099
    public get summaries(): any {
UNCOV
1100
        return this._summaries;
×
1101
    }
1102

1103
    /* treatAsRef */
1104
    /**
1105
     * Sets the column `summaries`.
1106
     * ```typescript
1107
     * this.column.summaries = IgxNumberSummaryOperand;
1108
     * ```
1109
     *
1110
     * @memberof IgxColumnComponent
1111
     */
1112
    public set summaries(classRef: any) {
UNCOV
1113
        if (isConstructor(classRef)) {
×
UNCOV
1114
            this._summaries = new classRef();
×
1115
        }
1116

UNCOV
1117
        if (this.grid) {
×
UNCOV
1118
            this.grid.summaryService.removeSummariesCachePerColumn(this.field);
×
UNCOV
1119
            this.grid.summaryPipeTrigger++;
×
UNCOV
1120
            this.grid.summaryService.resetSummaryHeight();
×
1121
        }
1122
    }
1123

1124
    /**
1125
     * Sets/gets the summary operands to exclude from display.
1126
     * Accepts an array of string keys representing the summary types to disable, such as 'Min', 'Max', 'Count' etc.
1127
     * ```typescript
1128
     * let disabledSummaries = this.column.disabledSummaries;
1129
     * ```
1130
     * ```html
1131
     * <igx-column [disabledSummaries]="['min', 'max', 'average']"></igx-column>
1132
     * ```
1133
     *
1134
     * @memberof IgxColumnComponent
1135
     */
1136
    @WatchColumnChanges()
1137
    @Input()
1138
    public get disabledSummaries(): string[] {
UNCOV
1139
        return this._disabledSummaries;
×
1140
    }
1141

1142
    public set disabledSummaries(value: string[]) {
UNCOV
1143
        if (isEqual(this._disabledSummaries, value)) {
×
UNCOV
1144
            return;
×
1145
        }
UNCOV
1146
        this._disabledSummaries = value;
×
UNCOV
1147
        if (this.grid) {
×
UNCOV
1148
            this.grid.summaryService.removeSummariesCachePerColumn(this.field);
×
UNCOV
1149
            this.grid.summaryPipeTrigger++;
×
UNCOV
1150
            this.grid.summaryService.resetSummaryHeight();
×
1151
        }
1152
    }
1153

1154
    /**
1155
     * Gets the column `filters`.
1156
     * ```typescript
1157
     * let columnFilters = this.column.filters'
1158
     * ```
1159
     *
1160
     * @memberof IgxColumnComponent
1161
     */
1162
    @Input()
1163
    public get filters(): IgxFilteringOperand {
UNCOV
1164
        return this._filters;
×
1165
    }
1166
    /**
1167
     * Sets the column `filters`.
1168
     * ```typescript
1169
     * this.column.filters = IgxBooleanFilteringOperand.instance().
1170
     * ```
1171
     *
1172
     * @memberof IgxColumnComponent
1173
     */
1174
    public set filters(instance: IgxFilteringOperand) {
UNCOV
1175
        this._filters = instance;
×
1176
    }
1177
    /**
1178
     * Gets the column `sortStrategy`.
1179
     * ```typescript
1180
     * let sortStrategy = this.column.sortStrategy
1181
     * ```
1182
     *
1183
     * @memberof IgxColumnComponent
1184
     */
1185
    @Input()
1186
    public get sortStrategy(): ISortingStrategy {
UNCOV
1187
        return this._sortStrategy;
×
1188
    }
1189
    /**
1190
     * Sets the column `sortStrategy`.
1191
     * ```typescript
1192
     * this.column.sortStrategy = new CustomSortingStrategy().
1193
     * class CustomSortingStrategy extends SortingStrategy {...}
1194
     * ```
1195
     *
1196
     * @memberof IgxColumnComponent
1197
     */
1198
    public set sortStrategy(classRef: ISortingStrategy) {
UNCOV
1199
        this._sortStrategy = classRef;
×
1200
    }
1201

1202
    /* blazorSuppress */
1203
    /**
1204
     * Gets the function that compares values for grouping.
1205
     * ```typescript
1206
     * let groupingComparer = this.column.groupingComparer'
1207
     * ```
1208
     *
1209
     * @memberof IgxColumnComponent
1210
     */
1211
    @Input()
1212
    public get groupingComparer(): (a: any, b: any, currRec?: any, groupRec?: any) => number {
UNCOV
1213
        return this._groupingComparer;
×
1214
    }
1215

1216
    /* blazorSuppress */
1217
    /**
1218
     * Sets a custom function to compare values for grouping.
1219
     * Subsequent values in the sorted data that the function returns 0 for are grouped.
1220
     * ```typescript
1221
     * this.column.groupingComparer = (a: any, b: any, currRec?: any, groupRec?: any) => { return a === b ? 0 : -1; }
1222
     * ```
1223
     *
1224
     * @memberof IgxColumnComponent
1225
     */
1226
    public set groupingComparer(funcRef: (a: any, b: any, currRec?: any, groupRec?: any) => number) {
UNCOV
1227
        this._groupingComparer = funcRef;
×
1228
    }
1229
    /**
1230
     * @hidden @internal
1231
     */
1232
    public get defaultMinWidth(): string {
UNCOV
1233
        if (!this.grid) {
×
1234
            return '80';
×
1235
        }
UNCOV
1236
        switch (this.grid.gridSize) {
×
1237
            case Size.Medium:
UNCOV
1238
                return '64';
×
1239
            case Size.Small:
UNCOV
1240
                return '56';
×
1241
            default:
UNCOV
1242
                return '80';
×
1243
        }
1244
    }
1245
    /**
1246
     * Returns a reference to the `summaryTemplate`.
1247
     * ```typescript
1248
     * let summaryTemplate = this.column.summaryTemplate;
1249
     * ```
1250
     *
1251
     * @memberof IgxColumnComponent
1252
     */
1253
    @notifyChanges()
1254
    @WatchColumnChanges()
1255
    @Input()
1256
    public get summaryTemplate(): TemplateRef<IgxSummaryTemplateContext> {
UNCOV
1257
        return this._summaryTemplate;
×
1258
    }
1259
    /**
1260
     * Sets the summary template.
1261
     * ```html
1262
     * <ng-template #summaryTemplate igxSummary let-summaryResults>
1263
     *    <p>{{ summaryResults[0].label }}: {{ summaryResults[0].summaryResult }}</p>
1264
     *    <p>{{ summaryResults[1].label }}: {{ summaryResults[1].summaryResult }}</p>
1265
     * </ng-template>
1266
     * ```
1267
     * ```typescript
1268
     * @ViewChild("'summaryTemplate'", {read: TemplateRef })
1269
     * public summaryTemplate: TemplateRef<any>;
1270
     * this.column.summaryTemplate = this.summaryTemplate;
1271
     * ```
1272
     *
1273
     * @memberof IgxColumnComponent
1274
     */
1275
    public set summaryTemplate(template: TemplateRef<IgxSummaryTemplateContext>) {
UNCOV
1276
        this._summaryTemplate = template;
×
1277
    }
1278

1279
    /**
1280
     * Returns a reference to the `bodyTemplate`.
1281
     * ```typescript
1282
     * let bodyTemplate = this.column.bodyTemplate;
1283
     * ```
1284
     *
1285
     * @memberof IgxColumnComponent
1286
     */
1287
    @notifyChanges()
1288
    @WatchColumnChanges()
1289
    @Input('cellTemplate')
1290
    public get bodyTemplate(): TemplateRef<IgxCellTemplateContext> {
UNCOV
1291
        return this._bodyTemplate;
×
1292
    }
1293
    /**
1294
     * Sets the body template.
1295
     * ```html
1296
     * <ng-template #bodyTemplate igxCell let-val>
1297
     *    <div style = "background-color: yellowgreen" (click) = "changeColor(val)">
1298
     *       <span> {{val}} </span>
1299
     *    </div>
1300
     * </ng-template>
1301
     * ```
1302
     * ```typescript
1303
     * @ViewChild("'bodyTemplate'", {read: TemplateRef })
1304
     * public bodyTemplate: TemplateRef<any>;
1305
     * this.column.bodyTemplate = this.bodyTemplate;
1306
     * ```
1307
     *
1308
     * @memberof IgxColumnComponent
1309
     */
1310
    public set bodyTemplate(template: TemplateRef<IgxCellTemplateContext>) {
UNCOV
1311
        this._bodyTemplate = template;
×
1312
    }
1313
    /**
1314
     * Returns a reference to the header template.
1315
     * ```typescript
1316
     * let headerTemplate = this.column.headerTemplate;
1317
     * ```
1318
     *
1319
     * @memberof IgxColumnComponent
1320
     */
1321
    @notifyChanges()
1322
    @WatchColumnChanges()
1323
    @Input()
1324
    public get headerTemplate(): TemplateRef<IgxColumnTemplateContext> {
UNCOV
1325
        return this._headerTemplate;
×
1326
    }
1327
    /**
1328
     * Sets the header template.
1329
     * Note that the column header height is fixed and any content bigger than it will be cut off.
1330
     * ```html
1331
     * <ng-template #headerTemplate>
1332
     *   <div style = "background-color:black" (click) = "changeColor(val)">
1333
     *       <span style="color:red" >{{column.field}}</span>
1334
     *   </div>
1335
     * </ng-template>
1336
     * ```
1337
     * ```typescript
1338
     * @ViewChild("'headerTemplate'", {read: TemplateRef })
1339
     * public headerTemplate: TemplateRef<any>;
1340
     * this.column.headerTemplate = this.headerTemplate;
1341
     * ```
1342
     *
1343
     * @memberof IgxColumnComponent
1344
     */
1345
    public set headerTemplate(template: TemplateRef<IgxColumnTemplateContext>) {
UNCOV
1346
        this._headerTemplate = template;
×
1347
    }
1348
    /**
1349
     * Returns a reference to the inline editor template.
1350
     * ```typescript
1351
     * let inlineEditorTemplate = this.column.inlineEditorTemplate;
1352
     * ```
1353
     *
1354
     * @memberof IgxColumnComponent
1355
     */
1356
    @notifyChanges()
1357
    @WatchColumnChanges()
1358
    @Input('cellEditorTemplate')
1359
    public get inlineEditorTemplate(): TemplateRef<IgxCellTemplateContext> {
UNCOV
1360
        return this._inlineEditorTemplate;
×
1361
    }
1362
    /**
1363
     * Sets the inline editor template.
1364
     * ```html
1365
     * <ng-template #inlineEditorTemplate igxCellEditor let-cell="cell">
1366
     *     <input type="string" [(ngModel)]="cell.value"/>
1367
     * </ng-template>
1368
     * ```
1369
     * ```typescript
1370
     * @ViewChild("'inlineEditorTemplate'", {read: TemplateRef })
1371
     * public inlineEditorTemplate: TemplateRef<any>;
1372
     * this.column.inlineEditorTemplate = this.inlineEditorTemplate;
1373
     * ```
1374
     *
1375
     * @memberof IgxColumnComponent
1376
     */
1377
    public set inlineEditorTemplate(template: TemplateRef<IgxCellTemplateContext>) {
UNCOV
1378
        this._inlineEditorTemplate = template;
×
1379
    }
1380

1381
    /**
1382
     * Returns a reference to the validation error template.
1383
     * ```typescript
1384
     * let errorTemplate = this.column.errorTemplate;
1385
     * ```
1386
     */
1387
    @notifyChanges()
1388
    @WatchColumnChanges()
1389
    @Input('errorTemplate')
1390
    public get errorTemplate(): TemplateRef<IgxCellTemplateContext> {
UNCOV
1391
        return this._errorTemplate;
×
1392
    }
1393
    /**
1394
     * Sets the error template.
1395
     * ```html
1396
     * <ng-template igxCellValidationError let-cell="cell" #errorTemplate >
1397
     *     <div *ngIf="cell.validation.errors?.['forbiddenName']">
1398
     *      This name is forbidden.
1399
     *     </div>
1400
     * </ng-template>
1401
     * ```
1402
     * ```typescript
1403
     * @ViewChild("'errorTemplate'", {read: TemplateRef })
1404
     * public errorTemplate: TemplateRef<any>;
1405
     * this.column.errorTemplate = this.errorTemplate;
1406
     * ```
1407
     */
1408
    public set errorTemplate(template: TemplateRef<IgxCellTemplateContext>) {
UNCOV
1409
        this._errorTemplate = template;
×
1410
    }
1411

1412
    /**
1413
     * Returns a reference to the `filterCellTemplate`.
1414
     * ```typescript
1415
     * let filterCellTemplate = this.column.filterCellTemplate;
1416
     * ```
1417
     *
1418
     * @memberof IgxColumnComponent
1419
     */
1420
    @notifyChanges()
1421
    @WatchColumnChanges()
1422
    @Input('filterCellTemplate')
1423
    public get filterCellTemplate(): TemplateRef<IgxColumnTemplateContext> {
UNCOV
1424
        return this._filterCellTemplate;
×
1425
    }
1426
    /**
1427
     * Sets the quick filter template.
1428
     * ```html
1429
     * <ng-template #filterCellTemplate IgxFilterCellTemplate let-column="column">
1430
     *    <input (input)="onInput()">
1431
     * </ng-template>
1432
     * ```
1433
     * ```typescript
1434
     * @ViewChild("'filterCellTemplate'", {read: TemplateRef })
1435
     * public filterCellTemplate: TemplateRef<any>;
1436
     * this.column.filterCellTemplate = this.filterCellTemplate;
1437
     * ```
1438
     *
1439
     * @memberof IgxColumnComponent
1440
     */
1441
    public set filterCellTemplate(template: TemplateRef<IgxColumnTemplateContext>) {
UNCOV
1442
        this._filterCellTemplate = template;
×
1443
    }
1444

1445
    /**
1446
     * @hidden @internal
1447
     */
1448
    public get cells(): CellType[] {
UNCOV
1449
        return this.grid.dataView
×
1450
            .map((rec, index) => {
UNCOV
1451
                if (!this.grid.isGroupByRecord(rec) && !this.grid.isSummaryRow(rec)) {
×
UNCOV
1452
                    this.grid.pagingMode === 'remote' && this.grid.page !== 0 ?
×
1453
                        index = index + this.grid.perPage * this.grid.page : index = this.grid.dataRowList.first.index + index;
UNCOV
1454
                    const cell = new IgxGridCell(this.grid as any, index, this);
×
UNCOV
1455
                    return cell;
×
1456
                }
UNCOV
1457
            }).filter(cell => cell);
×
1458
    }
1459

1460

1461
    /**
1462
     * @hidden @internal
1463
     */
1464
    public get _cells(): CellType[] {
UNCOV
1465
        return this.grid.rowList.filter((row) => row instanceof IgxRowDirective)
×
1466
            .map((row) => {
UNCOV
1467
                if (row._cells) {
×
UNCOV
1468
                    return row._cells.filter((cell) => cell.columnIndex === this.index);
×
1469
                }
UNCOV
1470
            }).reduce((a, b) => a.concat(b), []);
×
1471
    }
1472

1473
    /**
1474
     * Gets the column visible index.
1475
     * If the column is not visible, returns `-1`.
1476
     * ```typescript
1477
     * let visibleColumnIndex =  this.column.visibleIndex;
1478
     * ```
1479
     *
1480
     * @memberof IgxColumnComponent
1481
     */
1482
    public get visibleIndex(): number {
UNCOV
1483
        if (!isNaN(this._vIndex)) {
×
UNCOV
1484
            return this._vIndex;
×
1485
        }
UNCOV
1486
        const unpinnedColumns = this.grid.unpinnedColumns.filter(c => !c.columnGroup);
×
UNCOV
1487
        const pinnedColumns = this.grid.pinnedColumns.filter(c => !c.columnGroup);
×
1488

UNCOV
1489
        let col = this;
×
UNCOV
1490
        let vIndex = -1;
×
1491

UNCOV
1492
        if (this.columnGroup) {
×
UNCOV
1493
            col = this.allChildren.filter(c => !c.columnGroup && !c.hidden)[0] as any;
×
1494
        }
UNCOV
1495
        if (this.columnLayoutChild) {
×
UNCOV
1496
            return this.parent.childrenVisibleIndexes.find(x => x.column === this).index;
×
1497
        }
1498

UNCOV
1499
        if (!this.pinned) {
×
UNCOV
1500
            const indexInCollection = unpinnedColumns.indexOf(col);
×
UNCOV
1501
            vIndex = indexInCollection === -1 ?
×
1502
                -1 :
1503
                (this.grid.isPinningToStart ?
×
1504
                    pinnedColumns.length + indexInCollection :
1505
                    indexInCollection);
1506
        } else {
UNCOV
1507
            const indexInCollection = pinnedColumns.indexOf(col);
×
UNCOV
1508
            vIndex = this.grid.isPinningToStart ?
×
1509
                indexInCollection :
1510
                unpinnedColumns.length + indexInCollection;
1511
        }
UNCOV
1512
        this._vIndex = vIndex;
×
UNCOV
1513
        return vIndex;
×
1514
    }
1515

1516
    /* blazorCSSuppress - Blazor doesn't carry over the ColumnType interface + should translate as static bool value */
1517
    /**
1518
     * Returns a boolean indicating if the column is a `ColumnGroup`.
1519
     * ```typescript
1520
     * let columnGroup =  this.column.columnGroup;
1521
     * ```
1522
     *
1523
     * @memberof IgxColumnComponent
1524
     */
1525
    public get columnGroup() {
UNCOV
1526
        return false;
×
1527
    }
1528

1529
    /* blazorCSSuppress - Blazor doesn't carry over the ColumnType interface + should translate as static bool value */
1530
    /**
1531
     * Returns a boolean indicating if the column is a `ColumnLayout` for multi-row layout.
1532
     * ```typescript
1533
     * let columnGroup =  this.column.columnGroup;
1534
     * ```
1535
     *
1536
     * @memberof IgxColumnComponent
1537
     */
1538
    public get columnLayout() {
UNCOV
1539
        return false;
×
1540
    }
1541

1542
    /**
1543
     * Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
1544
     * ```typescript
1545
     * let columnLayoutChild =  this.column.columnLayoutChild;
1546
     * ```
1547
     *
1548
     * @memberof IgxColumnComponent
1549
     */
1550
    public get columnLayoutChild(): boolean {
UNCOV
1551
        return this.parent && this.parent.columnLayout;
×
1552
    }
1553

1554
    /**
1555
     * A list containing all the child columns under this column (if any).
1556
     * Empty without children or if this column is not Group or Layout.
1557
     */
1558
    public get childColumns(): ColumnType[] {
1559
        return [];
×
1560
    }
1561

1562
    /** @hidden @internal **/
1563
    public get allChildren(): IgxColumnComponent[] {
UNCOV
1564
        return [];
×
1565
    }
1566
    /**
1567
     * Returns the level of the column in a column group.
1568
     * Returns `0` if the column doesn't have a `parent`.
1569
     * ```typescript
1570
     * let columnLevel =  this.column.level;
1571
     * ```
1572
     *
1573
     * @memberof IgxColumnComponent
1574
     */
1575
    public get level() {
UNCOV
1576
        let ptr = this.parent;
×
UNCOV
1577
        let lvl = 0;
×
1578

UNCOV
1579
        while (ptr) {
×
UNCOV
1580
            lvl++;
×
UNCOV
1581
            ptr = ptr.parent;
×
1582
        }
UNCOV
1583
        return lvl;
×
1584
    }
1585

1586
    /** @hidden @internal **/
1587
    public get isLastPinned(): boolean {
UNCOV
1588
        return this.grid.isPinningToStart &&
×
1589
            this.grid.pinnedColumns[this.grid.pinnedColumns.length - 1] === this;
1590
    }
1591

1592
    /** @hidden @internal **/
1593
    public get isFirstPinned(): boolean {
UNCOV
1594
        const pinnedCols = this.grid.pinnedColumns.filter(x => !x.columnGroup);
×
UNCOV
1595
        return !this.grid.isPinningToStart && pinnedCols[0] === this;
×
1596
    }
1597

1598
    /** @hidden @internal **/
1599
    public get rightPinnedOffset(): string {
UNCOV
1600
        return this.pinned && !this.grid.isPinningToStart ?
×
1601
            - this.grid.pinnedWidth - this.grid.headerFeaturesWidth + 'px' :
1602
            null;
1603
    }
1604

1605
    /** @hidden @internal **/
1606
    public get gridRowSpan(): number {
UNCOV
1607
        return this.rowEnd && this.rowStart ? this.rowEnd - this.rowStart : 1;
×
1608
    }
1609
    /** @hidden @internal **/
1610
    public get gridColumnSpan(): number {
UNCOV
1611
        return this.colEnd && this.colStart ? this.colEnd - this.colStart : 1;
×
1612
    }
1613

1614
    /**
1615
     * Indicates whether the column will be visible when its parent is collapsed.
1616
     * ```html
1617
     * <igx-column-group>
1618
     *   <igx-column [visibleWhenCollapsed]="true"></igx-column>
1619
     * </igx-column-group>
1620
     * ```
1621
     *
1622
     * @memberof IgxColumnComponent
1623
     */
1624
    @notifyChanges(true)
1625
    @Input({ transform: booleanAttribute })
1626
    public set visibleWhenCollapsed(value: boolean) {
UNCOV
1627
        this._visibleWhenCollapsed = value;
×
UNCOV
1628
        this.visibleWhenCollapsedChange.emit(this._visibleWhenCollapsed);
×
UNCOV
1629
        if (this.parent) {
×
UNCOV
1630
            this.parent?.setExpandCollapseState?.();
×
1631
        }
1632
    }
1633

1634
    public get visibleWhenCollapsed(): boolean {
UNCOV
1635
        return this._visibleWhenCollapsed;
×
1636
    }
1637

1638
    /* mustSetInCodePlatforms: WebComponents;Blazor;React */
1639
    /**
1640
     * @remarks
1641
     * Pass optional parameters for DatePipe and/or DecimalPipe to format the display value for date and numeric columns.
1642
     * Accepts an `IColumnPipeArgs` object with any of the `format`, `timezone` and `digitsInfo` properties.
1643
     * For more details see https://angular.io/api/common/DatePipe and https://angular.io/api/common/DecimalPipe
1644
     * @example
1645
     * ```typescript
1646
     * const pipeArgs: IColumnPipeArgs = {
1647
     *      format: 'longDate',
1648
     *      timezone: 'UTC',
1649
     *      digitsInfo: '1.1-2'
1650
     * }
1651
     * ```
1652
     * ```html
1653
     * <igx-column dataType="date" [pipeArgs]="pipeArgs"></igx-column>
1654
     * <igx-column dataType="number" [pipeArgs]="pipeArgs"></igx-column>
1655
     * ```
1656
     * @memberof IgxColumnComponent
1657
     */
1658
    @notifyChanges()
1659
    @WatchColumnChanges()
1660
    @Input()
1661
    public set pipeArgs(value: IColumnPipeArgs) {
UNCOV
1662
        this._columnPipeArgs = Object.assign(this._columnPipeArgs, value);
×
UNCOV
1663
        this.grid.summaryService.clearSummaryCache();
×
UNCOV
1664
        this.grid.pipeTrigger++;
×
1665
    }
1666
    /* mustSetInCodePlatforms: WebComponents;Blazor */
1667
    public get pipeArgs(): IColumnPipeArgs {
UNCOV
1668
        return this._columnPipeArgs;
×
1669
    }
1670

1671
    /**
1672
     * Pass optional properties for the default column editors.
1673
     * @remarks
1674
     * Options may be applicable only to specific column type editors.
1675
     * @example
1676
     * ```typescript
1677
     * const editorOptions: IColumnEditorOptions = {
1678
     *      dateTimeFormat: 'MM/dd/YYYY',
1679
     * }
1680
     * ```
1681
     * ```html
1682
     * <igx-column dataType="date" [editorOptions]="editorOptions"></igx-column>
1683
     * ```
1684
     * @memberof IgxColumnComponent
1685
     */
1686
    @notifyChanges()
1687
    @WatchColumnChanges()
1688
    @Input()
1689
    public set editorOptions(value: IColumnEditorOptions) {
UNCOV
1690
        this._editorOptions = value;
×
1691
    }
1692
    public get editorOptions(): IColumnEditorOptions {
UNCOV
1693
        return this._editorOptions;
×
1694
    }
1695

1696
    /**
1697
     * @hidden
1698
     * @internal
1699
     */
1700
    public get collapsible() {
1701
        return false;
×
1702
    }
1703
    public set collapsible(_value: boolean) { }
1704

1705
    /**
1706
     * @hidden
1707
     * @internal
1708
     */
1709
    public get expanded() {
1710
        return true;
×
1711
    }
1712
    public set expanded(_value: boolean) { }
1713

1714
    /**
1715
     * @hidden
1716
     */
1717
    public defaultWidth: string;
1718

1719
    /**
1720
     * @hidden
1721
     */
1722
    public widthSetByUser: boolean;
1723

1724
    /**
1725
     * @hidden
1726
     */
1727
    public hasNestedPath: boolean;
1728

1729
    /**
1730
     * @hidden
1731
     * @internal
1732
     */
UNCOV
1733
    public defaultTimeFormat = 'hh:mm:ss a';
×
1734

1735
    /**
1736
     * @hidden
1737
     * @internal
1738
     */
UNCOV
1739
    public defaultDateTimeFormat = 'dd/MM/yyyy HH:mm:ss a';
×
1740

1741

1742
    /**
1743
     * Returns the filteringExpressionsTree of the column.
1744
     * ```typescript
1745
     * let tree =  this.column.filteringExpressionsTree;
1746
     * ```
1747
     *
1748
     * @memberof IgxColumnComponent
1749
     */
1750
    public get filteringExpressionsTree(): FilteringExpressionsTree {
UNCOV
1751
        return ExpressionsTreeUtil.find(this.grid.filteringExpressionsTree, this.field) as FilteringExpressionsTree;
×
1752
    }
1753

1754
    /* alternateName: parentColumn */
1755
    /**
1756
     * Sets/gets the parent column.
1757
     * ```typescript
1758
     * let parentColumn = this.column.parent;
1759
     * ```
1760
     * ```typescript
1761
     * this.column.parent = higherLevelColumn;
1762
     * ```
1763
     *
1764
     * @memberof IgxColumnComponent
1765
     */
UNCOV
1766
    public parent = null;
×
1767

1768
    /* blazorSuppress */
1769
    /**
1770
     * Sets/gets the children columns.
1771
     * ```typescript
1772
     * let columnChildren = this.column.children;
1773
     * ```
1774
     *
1775
     * @deprecated in version 18.1.0. Use the `childColumns` property instead.
1776
     */
1777
    public children: QueryList<IgxColumnComponent>;
1778
    /**
1779
     * @hidden
1780
     */
UNCOV
1781
    public destroy$ = new Subject<any>();
×
1782

1783
    /**
1784
     * @hidden
1785
     */
UNCOV
1786
    public widthConstrained = false;
×
1787

1788
    /**
1789
     * @hidden
1790
     */
UNCOV
1791
    protected _applySelectableClass = false;
×
1792

UNCOV
1793
    protected _vIndex = NaN;
×
1794
    /**
1795
     * @hidden
1796
     */
UNCOV
1797
    protected _pinned = false;
×
1798
    /**
1799
     * @hidden
1800
     */
1801
    protected _bodyTemplate: TemplateRef<IgxCellTemplateContext>;
1802
    /**
1803
     * @hidden
1804
     */
1805
    protected _errorTemplate: TemplateRef<IgxCellTemplateContext>;
1806
    /**
1807
     * @hidden
1808
     */
1809
    protected _headerTemplate: TemplateRef<IgxColumnTemplateContext>;
1810
    /**
1811
     * @hidden
1812
     */
1813
    protected _summaryTemplate: TemplateRef<IgxSummaryTemplateContext>;
1814
    /**
1815
     * @hidden
1816
     */
1817
    protected _inlineEditorTemplate: TemplateRef<IgxCellTemplateContext>;
1818
    /**
1819
     * @hidden
1820
     */
1821
    protected _filterCellTemplate: TemplateRef<IgxColumnTemplateContext>;
1822
    /**
1823
     * @hidden
1824
     */
UNCOV
1825
    protected _summaries = null;
×
1826
    /**
1827
     * @hidden
1828
     */
UNCOV
1829
    private _disabledSummaries: string[] = [];
×
1830
    /**
1831
     * @hidden
1832
     */
UNCOV
1833
    protected _filters = null;
×
1834
    /**
1835
     * @hidden
1836
     */
UNCOV
1837
    protected _sortStrategy: ISortingStrategy = DefaultSortingStrategy.instance();
×
1838
    /**
1839
     * @hidden
1840
     */
1841
    protected _groupingComparer: (a: any, b: any, currRec?: any, groupRec?: any) => number;
1842
    /**
1843
     * @hidden
1844
     */
UNCOV
1845
    protected _hidden = false;
×
1846
    /**
1847
     * @hidden
1848
     */
1849
    protected _index: number;
1850
    /**
1851
     * @hidden
1852
     */
UNCOV
1853
    protected _disablePinning = false;
×
1854
    /**
1855
     * @hidden
1856
     */
1857
    protected _width: string;
1858
    /**
1859
     * @hidden
1860
     */
UNCOV
1861
    protected _defaultMinWidth = '';
×
1862
    /**
1863
     * @hidden
1864
     */
1865
    protected _maxWidth;
1866
    /**
1867
     * @hidden
1868
     */
UNCOV
1869
    protected _hasSummary = false;
×
1870
    /**
1871
     * @hidden
1872
     */
1873
    protected _editable: boolean;
1874
    /**
1875
     * @hidden
1876
     */
UNCOV
1877
    protected _groupable = false;
×
1878
    /**
1879
     *  @hidden
1880
     */
1881
    protected _visibleWhenCollapsed;
1882
    /**
1883
     * @hidden
1884
     */
UNCOV
1885
    protected _collapsible = false;
×
1886
    /**
1887
     * @hidden
1888
     */
UNCOV
1889
    protected _expanded = true;
×
1890
    /**
1891
     * @hidden
1892
     */
UNCOV
1893
    protected _selectable = true;
×
1894
    /**
1895
     * @hidden
1896
     */
1897
    protected get isPrimaryColumn(): boolean {
UNCOV
1898
        return this.field !== undefined && this.grid !== undefined && this.field === this.grid.primaryKey;
×
1899
    }
1900

1901
    private _field: string;
UNCOV
1902
    private _calcWidth = null;
×
UNCOV
1903
    private _columnPipeArgs: IColumnPipeArgs = { digitsInfo: DEFAULT_DIGITS_INFO };
×
UNCOV
1904
    private _editorOptions: IColumnEditorOptions = { };
×
1905

1906
    constructor(
UNCOV
1907
        @Inject(IGX_GRID_BASE) public grid: GridType,
×
UNCOV
1908
        @Optional() @Self() @Inject(NG_VALIDATORS) private _validators: Validator[],
×
1909
        /** @hidden @internal **/
UNCOV
1910
        public cdr: ChangeDetectorRef,
×
UNCOV
1911
        protected platform: PlatformUtil,
×
1912
    ) {
UNCOV
1913
        this.validators = _validators;
×
1914
    }
1915

1916
    /**
1917
     * @hidden
1918
     * @internal
1919
     */
1920
    public resetCaches() {
UNCOV
1921
        this._vIndex = NaN;
×
UNCOV
1922
        if (this.grid) {
×
UNCOV
1923
            this.cacheCalcWidth();
×
1924
        }
1925
    }
1926

1927
    /**
1928
     * @hidden
1929
     */
1930
    public ngOnDestroy() {
UNCOV
1931
        this.destroy$.next(true);
×
UNCOV
1932
        this.destroy$.complete();
×
1933
    }
1934
    /**
1935
     * @hidden
1936
     */
1937
    public ngAfterContentInit(): void {
UNCOV
1938
        if (this.summaryTemplateDirective) {
×
UNCOV
1939
            this._summaryTemplate = this.summaryTemplateDirective.template;
×
1940
        }
UNCOV
1941
        if (this.cellTemplate) {
×
UNCOV
1942
            this._bodyTemplate = this.cellTemplate.template;
×
1943
        }
UNCOV
1944
        if (this.cellValidationErrorTemplate) {
×
UNCOV
1945
            this._errorTemplate = this.cellValidationErrorTemplate.template;
×
1946
        }
UNCOV
1947
        if (this.headTemplate && this.headTemplate.length) {
×
UNCOV
1948
            this._headerTemplate = this.headTemplate.toArray()[0].template;
×
1949
        }
UNCOV
1950
        if (this.editorTemplate) {
×
UNCOV
1951
            this._inlineEditorTemplate = this.editorTemplate.template;
×
1952
        }
UNCOV
1953
        if (this.filterCellTemplateDirective) {
×
1954
            this._filterCellTemplate = this.filterCellTemplateDirective.template;
×
1955
        }
UNCOV
1956
        if (!this._columnPipeArgs.format) {
×
UNCOV
1957
            this._columnPipeArgs.format = this.dataType === GridColumnDataType.Time ?
×
1958
                DEFAULT_TIME_FORMAT : this.dataType === GridColumnDataType.DateTime ?
×
1959
                    DEFAULT_DATE_TIME_FORMAT : DEFAULT_DATE_FORMAT;
1960
        }
UNCOV
1961
        if (!this.summaries) {
×
UNCOV
1962
            switch (this.dataType) {
×
1963
                case GridColumnDataType.Number:
1964
                case GridColumnDataType.Currency:
1965
                case GridColumnDataType.Percent:
UNCOV
1966
                    this.summaries = IgxNumberSummaryOperand;
×
UNCOV
1967
                    break;
×
1968
                case GridColumnDataType.Date:
1969
                case GridColumnDataType.DateTime:
UNCOV
1970
                    this.summaries = IgxDateSummaryOperand;
×
UNCOV
1971
                    break;
×
1972
                case GridColumnDataType.Time:
UNCOV
1973
                    this.summaries = IgxTimeSummaryOperand;
×
UNCOV
1974
                    break;
×
1975

1976
                case GridColumnDataType.String:
1977
                case GridColumnDataType.Boolean:
1978
                default:
UNCOV
1979
                    this.summaries = IgxSummaryOperand;
×
UNCOV
1980
                    break;
×
1981
            }
1982
        }
UNCOV
1983
        if (!this.filters) {
×
UNCOV
1984
            switch (this.dataType) {
×
1985
                case GridColumnDataType.Boolean:
UNCOV
1986
                    this.filters = IgxBooleanFilteringOperand.instance();
×
UNCOV
1987
                    break;
×
1988
                case GridColumnDataType.Number:
1989
                case GridColumnDataType.Currency:
1990
                case GridColumnDataType.Percent:
UNCOV
1991
                    this.filters = IgxNumberFilteringOperand.instance();
×
UNCOV
1992
                    break;
×
1993
                case GridColumnDataType.Date:
UNCOV
1994
                    this.filters = IgxDateFilteringOperand.instance();
×
UNCOV
1995
                    break;
×
1996
                case GridColumnDataType.Time:
UNCOV
1997
                    this.filters = IgxTimeFilteringOperand.instance();
×
UNCOV
1998
                    break;
×
1999
                case GridColumnDataType.DateTime:
UNCOV
2000
                    this.filters = IgxDateTimeFilteringOperand.instance();
×
UNCOV
2001
                    break;
×
2002
                case GridColumnDataType.Image:
UNCOV
2003
                    this.filterable = false;
×
UNCOV
2004
                    break;
×
2005
                case GridColumnDataType.String:
2006
                default:
UNCOV
2007
                    this.filters = IgxStringFilteringOperand.instance();
×
UNCOV
2008
                    break;
×
2009
            }
2010
        }
2011
    }
2012

2013
    /**
2014
     * @hidden
2015
     */
2016
    public getGridTemplate(isRow: boolean): string {
UNCOV
2017
        if (isRow) {
×
UNCOV
2018
            const rowsCount = this.grid.type !== 'pivot' ? this.grid.multiRowLayoutRowSize : this.children.length - 1;
×
UNCOV
2019
            return `repeat(${rowsCount},1fr)`;
×
2020
        } else {
UNCOV
2021
            return this.getColumnSizesString(this.children);
×
2022
        }
2023
    }
2024

2025
    /** @hidden @internal **/
2026
    public getInitialChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<MRLColumnSizeInfo> {
UNCOV
2027
        const columnSizes: MRLColumnSizeInfo[] = [];
×
2028
        // find the smallest col spans
UNCOV
2029
        children.forEach(col => {
×
UNCOV
2030
            if (!col.colStart) {
×
UNCOV
2031
                return;
×
2032
            }
UNCOV
2033
            const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
×
UNCOV
2034
            const newSpanSmaller = columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].colSpan > col.gridColumnSpan;
×
UNCOV
2035
            const bothWidthsSet = col.widthSetByUser && columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].widthSetByUser;
×
UNCOV
2036
            const bothWidthsNotSet = !col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
×
2037

UNCOV
2038
            if (columnSizes[col.colStart - 1] === undefined) {
×
2039
                // If nothing is defined yet take any column at first
2040
                // We use colEnd to know where the column actually ends, because not always it starts where we have it set in columnSizes.
UNCOV
2041
                columnSizes[col.colStart - 1] = {
×
2042
                    ref: col,
2043
                    width: col.width === 'fit-content' ? col.autoSize :
×
2044
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
×
2045
                    colSpan: col.gridColumnSpan,
2046
                    colEnd: col.colStart + col.gridColumnSpan,
2047
                    widthSetByUser: col.widthSetByUser
2048
                };
UNCOV
2049
            } else if (newWidthSet || (newSpanSmaller && ((bothWidthsSet) || (bothWidthsNotSet)))) {
×
2050
                // If a column is set already it should either not have width defined or have width with bigger span than the new one.
2051

2052
                /**
2053
                 *  If replaced column has bigger span, we want to fill the remaining columns
2054
                 *  that the replacing column does not fill with the old one.
2055
                 */
UNCOV
2056
                if (bothWidthsSet && newSpanSmaller) {
×
2057
                    // Start from where the new column set would end and apply the old column to the rest depending on how much it spans.
2058
                    // We have not yet replaced it so we can use it directly from the columnSizes collection.
2059
                    // This is where colEnd is used because the colStart of the old column is not actually i + 1.
UNCOV
2060
                    for (let i = col.colStart - 1 + col.gridColumnSpan; i < columnSizes[col.colStart - 1].colEnd - 1; i++) {
×
UNCOV
2061
                        if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
×
UNCOV
2062
                            columnSizes[i] = columnSizes[col.colStart - 1];
×
2063
                        } else {
UNCOV
2064
                            break;
×
2065
                        }
2066
                    }
2067
                }
2068

2069
                // Replace the old column with the new one.
UNCOV
2070
                columnSizes[col.colStart - 1] = {
×
2071
                    ref: col,
2072
                    width: col.width === 'fit-content' ? col.autoSize :
×
2073
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
×
2074
                    colSpan: col.gridColumnSpan,
2075
                    colEnd: col.colStart + col.gridColumnSpan,
2076
                    widthSetByUser: col.widthSetByUser
2077
                };
UNCOV
2078
            } else if (bothWidthsSet && columnSizes[col.colStart - 1].colSpan < col.gridColumnSpan) {
×
2079
                // If the column already in the columnSizes has smaller span, we still need to fill any empty places with the current col.
2080
                // Start from where the smaller column set would end and apply the bigger column to the rest depending on how much it spans.
2081
                // Since here we do not have it in columnSizes we set it as a new column keeping the same colSpan.
UNCOV
2082
                for (let i = col.colStart - 1 + columnSizes[col.colStart - 1].colSpan; i < col.colStart - 1 + col.gridColumnSpan; i++) {
×
UNCOV
2083
                    if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
×
UNCOV
2084
                        columnSizes[i] = {
×
2085
                            ref: col,
2086
                            width: col.width === 'fit-content' ? col.autoSize :
×
2087
                                col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
×
2088
                            colSpan: col.gridColumnSpan,
2089
                            colEnd: col.colStart + col.gridColumnSpan,
2090
                            widthSetByUser: col.widthSetByUser
2091
                        };
2092
                    } else {
UNCOV
2093
                        break;
×
2094
                    }
2095
                }
2096
            }
2097
        });
2098

2099
        // Flatten columnSizes so there are not columns with colSpan > 1
UNCOV
2100
        for (let i = 0; i < columnSizes.length; i++) {
×
UNCOV
2101
            if (columnSizes[i] && columnSizes[i].colSpan > 1) {
×
UNCOV
2102
                let j = 1;
×
2103

2104
                // Replace all empty places depending on how much the current column spans starting from next col.
UNCOV
2105
                for (; j < columnSizes[i].colSpan && i + j + 1 < columnSizes[i].colEnd; j++) {
×
UNCOV
2106
                    if (columnSizes[i + j] &&
×
2107
                        ((!columnSizes[i].width && columnSizes[i + j].width) ||
2108
                            (!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
2109
                            (!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
2110
                        // If we reach an already defined column that has width and the current doesn't have or
2111
                        // if the reached column has bigger colSpan we stop.
UNCOV
2112
                        break;
×
2113
                    } else {
UNCOV
2114
                        const width = columnSizes[i].widthSetByUser ?
×
2115
                            columnSizes[i].width / columnSizes[i].colSpan :
2116
                            columnSizes[i].width;
UNCOV
2117
                        columnSizes[i + j] = {
×
2118
                            ref: columnSizes[i].ref,
2119
                            width,
2120
                            colSpan: 1,
2121
                            colEnd: columnSizes[i].colEnd,
2122
                            widthSetByUser: columnSizes[i].widthSetByUser
2123
                        };
2124
                    }
2125
                }
2126

2127
                // Update the current column width so it is divided between all columns it spans and set it to 1.
UNCOV
2128
                columnSizes[i].width = columnSizes[i].widthSetByUser ?
×
2129
                    columnSizes[i].width / columnSizes[i].colSpan :
2130
                    columnSizes[i].width;
UNCOV
2131
                columnSizes[i].colSpan = 1;
×
2132

2133
                // Update the index based on how much we have replaced. Subtract 1 because we started from 1.
UNCOV
2134
                i += j - 1;
×
2135
            }
2136
        }
2137

UNCOV
2138
        return columnSizes;
×
2139
    }
2140

2141
    /** @hidden @internal **/
2142
    public getFilledChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<string> {
UNCOV
2143
        const columnSizes = this.getInitialChildColumnSizes(children);
×
2144

2145
        // fill the gaps if there are any
UNCOV
2146
        const result: string[] = [];
×
UNCOV
2147
        for (const size of columnSizes) {
×
UNCOV
2148
            if (size && !!size.width) {
×
UNCOV
2149
                result.push(size.width + 'px');
×
2150
            } else {
UNCOV
2151
                const currentWidth = parseFloat(this.grid.getPossibleColumnWidth());
×
UNCOV
2152
                result.push((this.getConstrainedSizePx(currentWidth)) + 'px');
×
2153
            }
2154
        }
UNCOV
2155
        return result;
×
2156
    }
2157

2158
    /** @hidden @internal **/
2159
    public getResizableColUnderEnd(): MRLResizeColumnInfo[] {
UNCOV
2160
        if (this.columnLayout || !this.columnLayoutChild || this.columnGroup) {
×
2161
            return [{ target: this, spanUsed: 1 }];
×
2162
        }
2163

UNCOV
2164
        const columnSized = this.getInitialChildColumnSizes(this.parent.children);
×
UNCOV
2165
        const targets: MRLResizeColumnInfo[] = [];
×
UNCOV
2166
        const colEnd = this.colEnd ? this.colEnd : this.colStart + 1;
×
2167

UNCOV
2168
        for (let i = 0; i < columnSized.length; i++) {
×
UNCOV
2169
            if (this.colStart <= i + 1 && i + 1 < colEnd) {
×
UNCOV
2170
                targets.push({ target: columnSized[i].ref, spanUsed: 1 });
×
2171
            }
2172
        }
2173

UNCOV
2174
        const targetsSquashed: MRLResizeColumnInfo[] = [];
×
UNCOV
2175
        for (const target of targets) {
×
UNCOV
2176
            if (targetsSquashed.length && targetsSquashed[targetsSquashed.length - 1].target.field === target.target.field) {
×
2177
                targetsSquashed[targetsSquashed.length - 1].spanUsed++;
×
2178
            } else {
UNCOV
2179
                targetsSquashed.push(target);
×
2180
            }
2181
        }
2182

UNCOV
2183
        return targetsSquashed;
×
2184
    }
2185

2186
    /**
2187
     * Pins the column at the provided index in the pinned area.
2188
     * Defaults to index `0` if not provided, or to the initial index in the pinned area.
2189
     * Returns `true` if the column is successfully pinned. Returns `false` if the column cannot be pinned.
2190
     * Column cannot be pinned if:
2191
     * - Is already pinned
2192
     * - index argument is out of range
2193
     * - The pinned area exceeds 80% of the grid width
2194
     * ```typescript
2195
     * let success = this.column.pin();
2196
     * ```
2197
     *
2198
     * @memberof IgxColumnComponent
2199
     */
2200
    public pin(index?: number): boolean {
2201
        // TODO: Probably should the return type of the old functions
2202
        // should be moved as a event parameter.
UNCOV
2203
        const grid = (this.grid as any);
×
UNCOV
2204
        if (this._pinned) {
×
UNCOV
2205
            return false;
×
2206
        }
2207

UNCOV
2208
        if (this.parent && !this.parent.pinned) {
×
UNCOV
2209
            return this.topLevelParent.pin(index);
×
2210
        }
2211

UNCOV
2212
        const hasIndex = index !== undefined;
×
UNCOV
2213
        if (hasIndex && (index < 0 || index > grid.pinnedColumns.length)) {
×
UNCOV
2214
            return false;
×
2215
        }
2216

UNCOV
2217
        if (!this.parent && !this.pinnable) {
×
2218
            return false;
×
2219
        }
2220

UNCOV
2221
        const rootPinnedCols = grid._pinnedColumns.filter((c) => c.level === 0);
×
UNCOV
2222
        index = hasIndex ? index : rootPinnedCols.length;
×
UNCOV
2223
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: false, cancel: false };
×
UNCOV
2224
        this.grid.columnPin.emit(args);
×
2225

UNCOV
2226
        if (args.cancel) {
×
2227
            return;
×
2228
        }
2229

UNCOV
2230
        this.grid.crudService.endEdit(false);
×
2231

UNCOV
2232
        this._pinned = true;
×
UNCOV
2233
        this.pinnedChange.emit(this._pinned);
×
2234
        // it is possible that index is the last position, so will need to find target column by [index-1]
UNCOV
2235
        const targetColumn = args.insertAtIndex === grid._pinnedColumns.length ?
×
2236
            grid._pinnedColumns[args.insertAtIndex - 1] : grid._pinnedColumns[args.insertAtIndex];
2237

UNCOV
2238
        if (grid._pinnedColumns.indexOf(this) === -1) {
×
UNCOV
2239
            if (!grid.hasColumnGroups) {
×
UNCOV
2240
                grid._pinnedColumns.splice(args.insertAtIndex, 0, this);
×
2241
            } else {
2242
                // insert based only on root collection
UNCOV
2243
                if (this.level === 0) {
×
UNCOV
2244
                    rootPinnedCols.splice(args.insertAtIndex, 0, this);
×
2245
                }
UNCOV
2246
                let allPinned = [];
×
2247
                // FIX: this is duplicated on every step in the hierarchy....
2248
                // re-create hierarchy
UNCOV
2249
                rootPinnedCols.forEach(group => {
×
UNCOV
2250
                    allPinned.push(group);
×
UNCOV
2251
                    allPinned = allPinned.concat(group.allChildren);
×
2252
                });
UNCOV
2253
                grid._pinnedColumns = allPinned;
×
2254
            }
2255

UNCOV
2256
            if (grid._unpinnedColumns.indexOf(this) !== -1) {
×
UNCOV
2257
                const childrenCount = this.allChildren.length;
×
UNCOV
2258
                grid._unpinnedColumns.splice(grid._unpinnedColumns.indexOf(this), 1 + childrenCount);
×
2259
            }
2260
        }
2261

UNCOV
2262
        if (hasIndex) {
×
UNCOV
2263
            index === grid._pinnedColumns.length - 1 ?
×
2264
                grid._moveColumns(this, targetColumn, DropPosition.AfterDropTarget) : grid._moveColumns(this, targetColumn, DropPosition.BeforeDropTarget);
2265
        }
2266

UNCOV
2267
        if (this.columnGroup) {
×
UNCOV
2268
            this.allChildren.forEach(child => child.pin());
×
UNCOV
2269
            grid.reinitPinStates();
×
2270
        }
2271

UNCOV
2272
        grid.resetCaches();
×
UNCOV
2273
        grid.notifyChanges();
×
UNCOV
2274
        if (this.columnLayoutChild) {
×
UNCOV
2275
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
×
2276
        }
UNCOV
2277
        this.grid.filteringService.refreshExpressions();
×
UNCOV
2278
        const eventArgs: IPinColumnEventArgs = { column: this, insertAtIndex: index, isPinned: true };
×
UNCOV
2279
        this.grid.columnPinned.emit(eventArgs);
×
UNCOV
2280
        return true;
×
2281
    }
2282
    /**
2283
     * Unpins the column and place it at the provided index in the unpinned area.
2284
     * Defaults to index `0` if not provided, or to the initial index in the unpinned area.
2285
     * Returns `true` if the column is successfully unpinned. Returns `false` if the column cannot be unpinned.
2286
     * Column cannot be unpinned if:
2287
     * - Is already unpinned
2288
     * - index argument is out of range
2289
     * ```typescript
2290
     * let success = this.column.unpin();
2291
     * ```
2292
     *
2293
     * @memberof IgxColumnComponent
2294
     */
2295
    public unpin(index?: number): boolean {
UNCOV
2296
        const grid = (this.grid as any);
×
UNCOV
2297
        if (!this._pinned) {
×
UNCOV
2298
            return false;
×
2299
        }
2300

UNCOV
2301
        if (this.parent && this.parent.pinned) {
×
UNCOV
2302
            return this.topLevelParent.unpin(index);
×
2303
        }
UNCOV
2304
        const hasIndex = index !== undefined;
×
UNCOV
2305
        if (hasIndex && (index < 0 || index > grid._unpinnedColumns.length)) {
×
UNCOV
2306
            return false;
×
2307
        }
2308

2309
        // estimate the exact index at which column will be inserted
2310
        // takes into account initial unpinned index of the column
UNCOV
2311
        if (!hasIndex) {
×
UNCOV
2312
            const indices = grid._unpinnedColumns.map(col => col.index);
×
UNCOV
2313
            indices.push(this.index);
×
UNCOV
2314
            indices.sort((a, b) => a - b);
×
UNCOV
2315
            index = indices.indexOf(this.index);
×
2316
        }
2317

UNCOV
2318
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: true, cancel: false };
×
UNCOV
2319
        this.grid.columnPin.emit(args);
×
2320

UNCOV
2321
        if (args.cancel) {
×
2322
            return;
×
2323
        }
2324

UNCOV
2325
        this.grid.crudService.endEdit(false);
×
2326

UNCOV
2327
        this._pinned = false;
×
UNCOV
2328
        this.pinnedChange.emit(this._pinned);
×
2329

2330
        // it is possible that index is the last position, so will need to find target column by [index-1]
UNCOV
2331
        const targetColumn = args.insertAtIndex === grid._unpinnedColumns.length ?
×
2332
            grid._unpinnedColumns[args.insertAtIndex - 1] : grid._unpinnedColumns[args.insertAtIndex];
2333

UNCOV
2334
        if (!hasIndex) {
×
UNCOV
2335
            grid._unpinnedColumns.splice(index, 0, this);
×
UNCOV
2336
            if (grid._pinnedColumns.indexOf(this) !== -1) {
×
UNCOV
2337
                grid._pinnedColumns.splice(grid._pinnedColumns.indexOf(this), 1);
×
2338
            }
2339
        }
2340

UNCOV
2341
        if (hasIndex) {
×
UNCOV
2342
            grid.moveColumn(this, targetColumn);
×
2343
        }
2344

UNCOV
2345
        if (this.columnGroup) {
×
UNCOV
2346
            this.allChildren.forEach(child => child.unpin());
×
2347
        }
2348

UNCOV
2349
        grid.reinitPinStates();
×
UNCOV
2350
        grid.resetCaches();
×
2351

UNCOV
2352
        grid.notifyChanges();
×
UNCOV
2353
        if (this.columnLayoutChild) {
×
UNCOV
2354
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
×
2355
        }
UNCOV
2356
        this.grid.filteringService.refreshExpressions();
×
2357

UNCOV
2358
        this.grid.columnPinned.emit({ column: this, insertAtIndex: index, isPinned: false });
×
2359

UNCOV
2360
        return true;
×
2361
    }
2362

2363
    /**
2364
     * Moves a column to the specified visible index.
2365
     * If passed index is invalid, or if column would receive a different visible index after moving, moving is not performed.
2366
     * If passed index would move the column to a different column group. moving is not performed.
2367
     *
2368
     * @example
2369
     * ```typescript
2370
     * column.move(index);
2371
     * ```
2372
     * @memberof IgxColumnComponent
2373
     */
2374
    public move(index: number) {
2375
        let target;
UNCOV
2376
        let columns = this.grid.columns.filter(c => c.visibleIndex > -1);
×
2377
        // grid last visible index
UNCOV
2378
        const li = columns.map(c => c.visibleIndex).reduce((a, b) => Math.max(a, b));
×
UNCOV
2379
        const parent = this.parent;
×
UNCOV
2380
        const isPreceding = this.visibleIndex < index;
×
2381

UNCOV
2382
        if (index === this.visibleIndex || index < 0 || index > li) {
×
UNCOV
2383
            return;
×
2384
        }
2385

UNCOV
2386
        if (parent) {
×
UNCOV
2387
            columns = columns.filter(c => c.level >= this.level && c !== this && c.parent !== this &&
×
2388
                c.topLevelParent === this.topLevelParent);
2389
        }
2390

2391
        // 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.
2392
        // 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.
2393

UNCOV
2394
        if (isPreceding) {
×
UNCOV
2395
            columns = columns.filter(c => c.visibleIndex > this.visibleIndex);
×
UNCOV
2396
            target = columns.find(c => c.level === this.level && c.visibleIndex + (c as any).calcChildren() - this.calcChildren() === index);
×
2397
        } else {
UNCOV
2398
            columns = columns.filter(c => c.visibleIndex < this.visibleIndex);
×
UNCOV
2399
            target = columns.find(c => c.level === this.level && c.visibleIndex === index);
×
2400
        }
2401

UNCOV
2402
        if (!target || (target.pinned && this.disablePinning)) {
×
UNCOV
2403
            return;
×
2404
        }
2405

UNCOV
2406
        const pos = isPreceding ? DropPosition.AfterDropTarget : DropPosition.BeforeDropTarget;
×
UNCOV
2407
        this.grid.moveColumn(this, target as IgxColumnComponent, pos);
×
2408
    }
2409

2410
    /**
2411
     * No children for the column, so will returns 1 or 0, if the column is hidden.
2412
     *
2413
     * @hidden
2414
     */
2415
    public calcChildren(): number {
UNCOV
2416
        const children = this.hidden ? 0 : 1;
×
UNCOV
2417
        return children;
×
2418
    }
2419

2420
    /**
2421
     * Toggles column vibisility and emits the respective event.
2422
     *
2423
     * @hidden
2424
     */
2425
    public toggleVisibility(value?: boolean) {
UNCOV
2426
        const newValue = value ?? !this.hidden;
×
UNCOV
2427
        const eventArgs: IColumnVisibilityChangingEventArgs = { column: this, newValue, cancel: false };
×
UNCOV
2428
        this.grid.columnVisibilityChanging.emit(eventArgs);
×
2429

UNCOV
2430
        if (eventArgs.cancel) {
×
2431
            return;
×
2432
        }
UNCOV
2433
        this.hidden = newValue;
×
UNCOV
2434
        this.grid.columnVisibilityChanged.emit({ column: this, newValue });
×
2435
    }
2436

2437
    /**
2438
     * Returns a reference to the top level parent column.
2439
     * ```typescript
2440
     * let topLevelParent =  this.column.topLevelParent;
2441
     * ```
2442
     */
2443
    public get topLevelParent(): ColumnType | undefined {
UNCOV
2444
        let parent = this.parent;
×
UNCOV
2445
        while (parent && parent.parent) {
×
UNCOV
2446
            parent = parent.parent;
×
2447
        }
UNCOV
2448
        return parent ?? undefined;
×
2449
    }
2450

2451
    /**
2452
     * @hidden @internal
2453
     */
2454
    public get headerCell(): IgxGridHeaderComponent {
UNCOV
2455
        return this.grid.headerCellList.find((header) => header.column === this);
×
2456
    }
2457

2458
    /**
2459
     * @hidden @internal
2460
     */
2461
    public get filterCell(): IgxGridFilteringCellComponent {
UNCOV
2462
        return this.grid.filterCellList.find((filterCell) => filterCell.column === this);
×
2463
    }
2464

2465
    /**
2466
     * @hidden @internal
2467
     */
2468
    public get headerGroup(): IgxGridHeaderGroupComponent {
UNCOV
2469
        return this.grid.headerGroupsList.find(group => group.column === this);
×
2470
    }
2471

2472
    /**
2473
     * Autosize the column to the longest currently visible cell value, including the header cell.
2474
     * ```typescript
2475
     * @ViewChild('grid') grid: IgxGridComponent;
2476
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2477
     * column.autosize();
2478
     * ```
2479
     *
2480
     * @memberof IgxColumnComponent
2481
     * @param byHeaderOnly Set if column should be autosized based only on the header content.
2482
     */
2483
    public autosize(byHeaderOnly = false) {
×
UNCOV
2484
        if (!this.columnGroup) {
×
UNCOV
2485
            this.width = this.getAutoSize(byHeaderOnly);
×
UNCOV
2486
            this.grid.reflow();
×
2487
        }
2488
    }
2489

2490
    /**
2491
     * @hidden
2492
     */
2493
    public getAutoSize(byHeader = false): string {
×
UNCOV
2494
        const size = !byHeader ? this.getLargestCellWidth() :
×
UNCOV
2495
            (Object.values(this.getHeaderCellWidths()).reduce((a, b) => a + b) + 'px');
×
UNCOV
2496
        const isPercentageWidth = this.width && typeof this.width === 'string' && this.width.indexOf('%') !== -1;
×
2497

2498
        let newWidth;
UNCOV
2499
        if (isPercentageWidth) {
×
UNCOV
2500
            const gridAvailableSize = this.grid.calcWidth;
×
UNCOV
2501
            const percentageSize = parseFloat(size) / gridAvailableSize * 100;
×
UNCOV
2502
            newWidth = percentageSize + '%';
×
2503
        } else {
UNCOV
2504
            newWidth = size;
×
2505
        }
2506

UNCOV
2507
        const maxWidth = isPercentageWidth ? this.maxWidthPercent : this.maxWidthPx;
×
UNCOV
2508
        const minWidth = isPercentageWidth ? this.minWidthPercent : this.minWidthPx;
×
UNCOV
2509
        if (this.maxWidth && (parseFloat(newWidth) > maxWidth)) {
×
UNCOV
2510
            newWidth = isPercentageWidth ? maxWidth + '%' : maxWidth + 'px';
×
UNCOV
2511
        } else if (parseFloat(newWidth) < minWidth) {
×
UNCOV
2512
            newWidth = isPercentageWidth ? minWidth + '%' : minWidth + 'px';
×
2513
        }
2514

UNCOV
2515
        return newWidth;
×
2516
    }
2517

2518
    /**
2519
     * @hidden
2520
     */
2521
    public getCalcWidth(): any {
UNCOV
2522
        if (this._calcWidth && !isNaN(this.calcPixelWidth)) {
×
UNCOV
2523
            return this._calcWidth;
×
2524
        }
UNCOV
2525
        this.cacheCalcWidth();
×
UNCOV
2526
        return this._calcWidth;
×
2527
    }
2528

2529

2530
    /**
2531
     * @hidden
2532
     * Returns the width and padding of a header cell.
2533
     */
2534
    public getHeaderCellWidths() {
UNCOV
2535
        return this.grid.getHeaderCellWidth(this.headerCell.nativeElement);
×
2536
    }
2537

2538
    /**
2539
     * @hidden
2540
     * Returns the size (in pixels) of the longest currently visible cell, including the header cell.
2541
     * ```typescript
2542
     * @ViewChild('grid') grid: IgxGridComponent;
2543
     *
2544
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2545
     * let size = column.getLargestCellWidth();
2546
     * ```
2547
     * @memberof IgxColumnComponent
2548
     */
2549
    public getLargestCellWidth(): string {
UNCOV
2550
        const range = this.grid.document.createRange();
×
UNCOV
2551
        const largest = new Map<number, number>();
×
2552

UNCOV
2553
        if (this._cells.length > 0) {
×
UNCOV
2554
            const cellsContentWidths = [];
×
UNCOV
2555
            this._cells.forEach((cell) => cellsContentWidths.push(cell.calculateSizeToFit(range)));
×
2556

UNCOV
2557
            const index = cellsContentWidths.indexOf(Math.max(...cellsContentWidths));
×
UNCOV
2558
            const cellStyle = this.grid.document.defaultView.getComputedStyle(this._cells[index].nativeElement);
×
UNCOV
2559
            const cellPadding = parseFloat(cellStyle.paddingLeft) + parseFloat(cellStyle.paddingRight) +
×
2560
                parseFloat(cellStyle.borderLeftWidth) + parseFloat(cellStyle.borderRightWidth);
2561

UNCOV
2562
            largest.set(Math.max(...cellsContentWidths), cellPadding);
×
2563
        }
2564

UNCOV
2565
        if (this.headerCell && this.autosizeHeader) {
×
UNCOV
2566
            const headerCellWidths = this.getHeaderCellWidths();
×
UNCOV
2567
            largest.set(headerCellWidths.width, headerCellWidths.padding);
×
2568
        }
2569

UNCOV
2570
        const largestCell = Math.max(...Array.from(largest.keys()));
×
UNCOV
2571
        const width = Math.ceil(largestCell + largest.get(largestCell));
×
2572

UNCOV
2573
        if (Number.isNaN(width)) {
×
2574
            return this.width;
×
2575
        } else {
UNCOV
2576
            return width + 'px';
×
2577
        }
2578
    }
2579

2580
    /**
2581
     * @hidden
2582
     */
2583
    public getCellWidth() {
UNCOV
2584
        const colWidth = this.width;
×
UNCOV
2585
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
×
2586

UNCOV
2587
        if (this.columnLayoutChild) {
×
2588
            return '';
×
2589
        }
2590

UNCOV
2591
        if (colWidth && !isPercentageWidth) {
×
2592

UNCOV
2593
            let cellWidth = colWidth;
×
UNCOV
2594
            if (typeof cellWidth !== 'string' || cellWidth.endsWith('px') === false) {
×
UNCOV
2595
                cellWidth += 'px';
×
2596
            }
2597

UNCOV
2598
            return cellWidth;
×
2599
        } else {
UNCOV
2600
            return colWidth;
×
2601
        }
2602
    }
2603

2604
    /**
2605
     * @hidden
2606
     */
2607
    public populateVisibleIndexes() { }
2608

2609
    protected getColumnSizesString(children: QueryList<IgxColumnComponent>): string {
UNCOV
2610
        const res = this.getFilledChildColumnSizes(children);
×
UNCOV
2611
        return res.join(' ');
×
2612
    }
2613

2614
    /**
2615
     * @hidden
2616
     * @internal
2617
     */
2618
    public getConstrainedSizePx(newSize){
UNCOV
2619
        if (this.maxWidth && newSize > this.maxWidthPx) {
×
UNCOV
2620
            this.widthConstrained = true;
×
UNCOV
2621
            return this.maxWidthPx;
×
UNCOV
2622
        } else if (this.minWidth && newSize < this.userSetMinWidthPx) {
×
UNCOV
2623
            this.widthConstrained = true;
×
UNCOV
2624
            return this.userSetMinWidthPx;
×
2625
        } else {
UNCOV
2626
            this.widthConstrained = false;
×
UNCOV
2627
            return newSize;
×
2628
        }
2629
    }
2630

2631
    /**
2632
     * @hidden
2633
     * @internal
2634
     */
2635
    protected cacheCalcWidth(): any {
UNCOV
2636
        const colWidth = this.width;
×
UNCOV
2637
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
×
UNCOV
2638
        const isAutoWidth = colWidth && typeof colWidth === 'string' && colWidth === 'fit-content';
×
UNCOV
2639
        if (isPercentageWidth && this.grid.isColumnWidthSum) {
×
UNCOV
2640
            this._calcWidth = this.userSetMinWidthPx ? this.userSetMinWidthPx : this.grid.minColumnWidth;
×
UNCOV
2641
        } else if (isPercentageWidth) {
×
UNCOV
2642
            const currentCalcWidth = parseFloat(colWidth) / 100 * this.grid.calcWidth;
×
UNCOV
2643
            this._calcWidth = this.grid.calcWidth ? this.getConstrainedSizePx(currentCalcWidth) : 0;
×
UNCOV
2644
        } else if (!colWidth || isAutoWidth && !this.autoSize) {
×
2645
            // no width
UNCOV
2646
            const currentCalcWidth = this.defaultWidth || this.grid.getPossibleColumnWidth();
×
UNCOV
2647
            this._calcWidth = this.getConstrainedSizePx(currentCalcWidth);
×
2648
        } else {
UNCOV
2649
            const currentCalcWidth =  parseFloat(this.width);
×
UNCOV
2650
            this._calcWidth =this.getConstrainedSizePx(currentCalcWidth);
×
2651
        }
UNCOV
2652
        this.calcPixelWidth = parseFloat(this._calcWidth);
×
2653
    }
2654

2655
    /**
2656
     * @hidden
2657
     * @internal
2658
     */
2659
    protected setExpandCollapseState() {
UNCOV
2660
        this.children.filter(col => (col.visibleWhenCollapsed !== undefined)).forEach(c => {
×
UNCOV
2661
            if (!this.collapsible) {
×
UNCOV
2662
                c.hidden = this.hidden; return;
×
2663
            }
UNCOV
2664
            c.hidden = this._expanded ? c.visibleWhenCollapsed : !c.visibleWhenCollapsed;
×
2665
        });
2666
    }
2667
    /**
2668
     * @hidden
2669
     * @internal
2670
     */
2671
    protected checkCollapsibleState() {
UNCOV
2672
        if (!this.children) {
×
2673
            return false;
×
2674
        }
UNCOV
2675
        const cols = this.children.map(child => child.visibleWhenCollapsed);
×
UNCOV
2676
        return (cols.some(c => c === true) && cols.some(c => c === false));
×
2677
    }
2678

2679
    /**
2680
     * @hidden
2681
     */
2682
    public get pinnable() {
UNCOV
2683
        return (this.grid as any)._init || !this.pinned;
×
2684
    }
2685

2686
    /**
2687
     * @hidden
2688
     */
2689
    public get applySelectableClass(): boolean {
UNCOV
2690
        return this._applySelectableClass;
×
2691
    }
2692

2693
    /**
2694
     * @hidden
2695
     */
2696
    public set applySelectableClass(value: boolean) {
UNCOV
2697
        if (this.selectable) {
×
UNCOV
2698
            this._applySelectableClass = value;
×
2699
        }
2700
    }
2701
}
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