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

IgniteUI / igniteui-angular / 14730016194

29 Apr 2025 11:22AM UTC coverage: 91.611% (+0.01%) from 91.6%
14730016194

Pull #15744

github

web-flow
fix(elements): Handle template setting of components passed as event args through proxy.  (#15649)
Pull Request #15744: Mass merging 19.2.x to master

13429 of 15707 branches covered (85.5%)

39 of 41 new or added lines in 7 files covered. (95.12%)

245 existing lines in 7 files now uncovered.

27027 of 29502 relevant lines covered (91.61%)

34340.72 hits per line

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

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

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

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

109

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

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

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

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

226
        if (this.isPrimaryColumn && (rowEditable || hasTransactions)) {
2,423,763✔
227
            return false;
100,523✔
228
        }
229

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

965

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1433

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

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

1462
        let col = this;
445,380✔
1463
        let vIndex = -1;
445,380✔
1464

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

1472
        if (!this.pinned) {
112,193✔
1473
            const indexInCollection = unpinnedColumns.indexOf(col);
110,001✔
1474
            vIndex = indexInCollection === -1 ?
110,001✔
1475
                -1 :
1476
                (this.grid.isPinningToStart ?
109,385✔
1477
                    pinnedColumns.length + indexInCollection :
1478
                    indexInCollection);
1479
        } else {
1480
            const indexInCollection = pinnedColumns.indexOf(col);
2,192✔
1481
            vIndex = this.grid.isPinningToStart ?
2,192✔
1482
                indexInCollection :
1483
                unpinnedColumns.length + indexInCollection;
1484
        }
1485
        this._vIndex = vIndex;
112,193✔
1486
        return vIndex;
112,193✔
1487
    }
1488

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

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

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

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

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

1552
        while (ptr) {
474,396✔
1553
            lvl++;
145,216✔
1554
            ptr = ptr.parent;
145,216✔
1555
        }
1556
        return lvl;
474,396✔
1557
    }
1558

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1714

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2072
        // Flatten columnSizes so there are not columns with colSpan > 1
2073
        for (let i = 0; i < columnSizes.length; i++) {
148,335✔
2074
            if (columnSizes[i] && columnSizes[i].colSpan > 1) {
216,775✔
2075
                let j = 1;
10,834✔
2076

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

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

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

2111
        return columnSizes;
148,335✔
2112
    }
2113

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

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

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

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

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

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

2156
        return targetsSquashed;
6✔
2157
    }
2158

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2333
        return true;
147✔
2334
    }
2335

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2488
        return newWidth;
26✔
2489
    }
2490

2491
    /**
2492
     * @hidden
2493
     */
2494
    public getCalcWidth(): any {
2495
        if (this._calcWidth && !isNaN(this.calcPixelWidth)) {
238,853✔
2496
            return this._calcWidth;
232,446✔
2497
        }
2498
        this.cacheCalcWidth();
6,407✔
2499
        return this._calcWidth;
6,407✔
2500
    }
2501

2502

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

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

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

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

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

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

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

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

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

2560
        if (this.columnLayoutChild) {
1,169,628!
UNCOV
2561
            return '';
×
2562
        }
2563

2564
        if (colWidth && !isPercentageWidth) {
1,169,628✔
2565

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

2571
            return cellWidth;
1,157,935✔
2572
        } else {
2573
            return colWidth;
11,693✔
2574
        }
2575
    }
2576

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

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

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

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

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

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

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

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