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

IgniteUI / igniteui-angular / 16053471080

03 Jul 2025 02:41PM UTC coverage: 4.981% (-86.4%) from 91.409%
16053471080

Pull #16021

github

web-flow
Merge 7c49966eb into 7e40671a1
Pull Request #16021: fix(radio-group): dynamically added radio buttons do not initialize

178 of 15753 branches covered (1.13%)

13 of 14 new or added lines in 2 files covered. (92.86%)

25644 existing lines in 324 files now uncovered.

1478 of 29670 relevant lines covered (4.98%)

0.51 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
    styles: `:host { display: none }`,
87
    standalone: true
88
})
89
export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnType {
3✔
90
    /**
91
     * Sets/gets the `field` value.
92
     * ```typescript
93
     * let columnField = this.column.field;
94
     * ```
95
     * ```html
96
     * <igx-column [field] = "'ID'"></igx-column>
97
     * ```
98
     *
99
     * @memberof IgxColumnComponent
100
     */
101
    @Input()
102
    public set field(value: string) {
UNCOV
103
        this._field = value;
×
UNCOV
104
        this.hasNestedPath = value?.includes('.');
×
105
    }
106
    public get field(): string {
UNCOV
107
        return this._field;
×
108
    }
109

110

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

993

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1461

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1742

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
2139
        return columnSizes;
×
2140
    }
2141

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

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

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

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

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

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

UNCOV
2184
        return targetsSquashed;
×
2185
    }
2186

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
2361
        return true;
×
2362
    }
2363

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
2516
        return newWidth;
×
2517
    }
2518

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

2530

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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