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

IgniteUI / igniteui-angular / 26023601418

18 May 2026 08:57AM UTC coverage: 4.854% (-85.3%) from 90.174%
26023601418

Pull #17281

github

web-flow
Merge e7ce7a18e into 5a85df190
Pull Request #17281: feat: Added virtual scroll component and sample implementation

400 of 17347 branches covered (2.31%)

Branch coverage included in aggregate %.

63 of 222 new or added lines in 4 files covered. (28.38%)

27932 existing lines in 341 files now uncovered.

2022 of 32547 relevant lines covered (6.21%)

0.72 hits per line

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

0.47
/projects/igniteui-angular/grids/core/src/columns/column.component.ts
1
import { Subject } from 'rxjs';
2
import { isEqual } from 'lodash-es';
3
import { AfterContentInit, ChangeDetectorRef, ChangeDetectionStrategy, Component, ContentChild, ContentChildren, Input, QueryList, TemplateRef, Output, EventEmitter, OnDestroy, booleanAttribute, inject } from '@angular/core';
4
import { notifyChanges } from '../watch-changes';
5
import { WatchColumnChanges } from '../watch-changes';
6
import { IgxRowDirective } from '../row.directive';
7
import { CellType, GridType, IgxCellTemplateContext, IgxColumnTemplateContext, IgxSummaryTemplateContext, IGX_GRID_BASE } from '../common/grid.interface';
8
import { IgxGridHeaderComponent } from '../headers/grid-header.component';
9
import { IgxGridFilteringCellComponent } from '../filtering/base/grid-filtering-cell.component';
10
import { IgxGridHeaderGroupComponent } from '../headers/grid-header-group.component';
11
import {
12
    IgxSummaryOperand, IgxNumberSummaryOperand, IgxDateSummaryOperand, IgxTimeSummaryOperand
13
} from '../summaries/grid-summary';
14
import {
15
    IgxCellTemplateDirective,
16
    IgxCellHeaderTemplateDirective,
17
    IgxCellEditorTemplateDirective,
18
    IgxCollapsibleIndicatorTemplateDirective,
19
    IgxFilterCellTemplateDirective,
20
    IgxSummaryTemplateDirective,
21
    IgxCellValidationErrorDirective
22
} from './templates.directive';
23
import { DropPosition } from '../moving/moving.service';
24
import { IColumnVisibilityChangingEventArgs, IPinColumnCancellableEventArgs, IPinColumnEventArgs } from '../common/events';
25
import { IgxGridCell } from '../grid-public-cell';
26
import { NG_VALIDATORS, Validator } from '@angular/forms';
27
import { ColumnPinningPosition, ColumnType, DefaultSortingStrategy, ExpressionsTreeUtil, FilteringExpressionsTree, GridColumnDataType, IColumnEditorOptions, IColumnPipeArgs, IgxBooleanFilteringOperand, IgxDateFilteringOperand, IgxDateTimeFilteringOperand, IgxFilteringOperand, IgxNumberFilteringOperand, IgxStringFilteringOperand, IgxSummaryResult, IgxTimeFilteringOperand, isConstructor, ISortingStrategy, MRLColumnSizeInfo, MRLResizeColumnInfo, PlatformUtil, ɵSize } from 'igniteui-angular/core';
28
import type { IgxColumnLayoutComponent } from './column-layout.component';
29

30
const DEFAULT_DATE_FORMAT = 'mediumDate';
3✔
31
const DEFAULT_TIME_FORMAT = 'mediumTime';
3✔
32
const DEFAULT_DATE_TIME_FORMAT = 'medium';
3✔
33
const DEFAULT_DIGITS_INFO = '1.0-3';
3✔
34

35
/* blazorElement */
36
/* contentParent: ColumnGroup */
37
/* wcElementTag: igc-column */
38
/* additionalIdentifier: Field */
39
/* blazorIndirectRender */
40
/**
41
 * **Ignite UI for Angular Column** -
42
 * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid#columns-configuration)
43
 *
44
 * The Ignite UI Column is used within an `igx-grid` element to define what data the column will show. Features such as sorting,
45
 * filtering & editing are enabled at the column level.  You can also provide a template containing custom content inside
46
 * the column using `ng-template` which will be used for all cells within the column.
47
 *
48
 * @igxParent IgxGridComponent, IgxTreeGridComponent, IgxHierarchicalGridComponent, IgxPivotGridComponent, IgxRowIslandComponent, IgxColumnGroupComponent, IgxColumnLayoutComponent
49
 */
50
@Component({
51
    changeDetection: ChangeDetectionStrategy.OnPush,
52
    selector: 'igx-column',
53
    template: ``,
54
    styles: `:host { display: none }`,
55
    standalone: true
56
})
57
export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnType {
3✔
58
    /* blazorSuppress */
UNCOV
59
    public grid = inject<GridType>(IGX_GRID_BASE);
×
UNCOV
60
    private _validators = inject<Validator[]>(NG_VALIDATORS, { optional: true, self: true });
×
61

62
    /** @hidden @internal **/
UNCOV
63
    public cdr = inject(ChangeDetectorRef);
×
UNCOV
64
    protected platform = inject(PlatformUtil);
×
65

66
    /**
67
     * Sets/gets the `field` value.
68
     * ```typescript
69
     * let columnField = this.column.field;
70
     * ```
71
     * ```html
72
     * <igx-column [field] = "'ID'"></igx-column>
73
     * ```
74
     *
75
     * @memberof IgxColumnComponent
76
     */
77
    @Input()
78
    public set field(value: string) {
UNCOV
79
        this._field = value;
×
UNCOV
80
        this.hasNestedPath = value?.includes('.');
×
81
    }
82
    public get field(): string {
UNCOV
83
        return this._field;
×
84
    }
85

86
    /**
87
     * Sets/gets whether to merge cells in this column.
88
     * ```html
89
     * <igx-column [merge]="true"></igx-column>
90
     * ```
91
     *
92
     */
93
    @Input()
94
    public get merge() {
UNCOV
95
        return this._merge;
×
96
    }
97

98
    public set merge(value) {
UNCOV
99
        if (this.grid.hasColumnLayouts) {
×
UNCOV
100
            console.warn('Merging is not supported with multi-row layouts.');
×
UNCOV
101
            return;
×
102
        }
UNCOV
103
        if (value !== this._merge) {
×
UNCOV
104
            this._merge = value;
×
UNCOV
105
            if (this.grid) {
×
UNCOV
106
                this.grid.resetColumnCollections();
×
UNCOV
107
                this.grid.notifyChanges();
×
108
            }
109
        }
110
    }
111

112
    /**
113
     * @hidden @internal
114
     */
UNCOV
115
    public validators: Validator[] = this._validators;
×
116

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

996

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

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

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

1045
    /* mustCoerceToInt */
1046
    /**
1047
     * Gets the pinning position of the column.
1048
     * ```typescript
1049
     * let pinningPosition = this.column.pinningPosition;
1050
     */
1051
    @WatchColumnChanges()
1052
    @Input()
1053
    public get pinningPosition(): ColumnPinningPosition {
UNCOV
1054
        const userSet = this._pinningPosition !== null && this._pinningPosition !== undefined;
×
UNCOV
1055
        return userSet ? this._pinningPosition : this.grid.pinning.columns;
×
1056
    }
1057

1058
    /**
1059
     * Sets the pinning position of the column.
1060
     *```html
1061
     * <igx-column [pinningPosition]="1"></igx-column>
1062
     * ```
1063
     */
1064
    public set pinningPosition(value: ColumnPinningPosition) {
UNCOV
1065
        this._pinningPosition = value;
×
1066
    }
1067

1068
    /**
1069
     * Gets whether the column is `pinned`.
1070
     * ```typescript
1071
     * let isPinned = this.column.pinned;
1072
     * ```
1073
     *
1074
     * @memberof IgxColumnComponent
1075
     */
1076
    @WatchColumnChanges()
1077
    @Input({ transform: booleanAttribute })
1078
    public get pinned(): boolean {
UNCOV
1079
        return this._pinned;
×
1080
    }
1081
    /**
1082
     * Sets whether the column is pinned.
1083
     * Default value is `false`.
1084
     * ```html
1085
     * <igx-column [pinned] = "true"></igx-column>
1086
     * ```
1087
     *
1088
     * Two-way data binding.
1089
     * ```html
1090
     * <igx-column [(pinned)] = "model.columns[0].isPinned"></igx-column>
1091
     * ```
1092
     *
1093
     * @memberof IgxColumnComponent
1094
     */
1095
    public set pinned(value: boolean) {
UNCOV
1096
        if (this._pinned !== value) {
×
UNCOV
1097
            const isAutoWidth = this.width && typeof this.width === 'string' && this.width === 'fit-content';
×
UNCOV
1098
            if (this.grid && this.width && (isAutoWidth || !isNaN(parseInt(this.width, 10)))) {
×
UNCOV
1099
                if (value) {
×
UNCOV
1100
                    this.pin();
×
1101
                } else {
UNCOV
1102
                    this.unpin();
×
1103
                }
UNCOV
1104
                return;
×
1105
            }
1106
            /* No grid/width available at initialization. `initPinning` in the grid
1107
               will re-init the group (if present)
1108
            */
UNCOV
1109
            this._pinned = value;
×
UNCOV
1110
            this.pinnedChange.emit(this._pinned);
×
1111
        }
1112
    }
1113

1114
    /* treatAsRef */
1115
    /**
1116
     * Gets the column `summaries`.
1117
     * ```typescript
1118
     * let columnSummaries = this.column.summaries;
1119
     * ```
1120
     *
1121
     * @memberof IgxColumnComponent
1122
     */
1123
    @notifyChanges(true)
1124
    @WatchColumnChanges()
1125
    @Input()
1126
    public get summaries(): any {
UNCOV
1127
        return this._summaries;
×
1128
    }
1129

1130
    /* treatAsRef */
1131
    /**
1132
     * Sets the column `summaries`.
1133
     * ```typescript
1134
     * this.column.summaries = IgxNumberSummaryOperand;
1135
     * ```
1136
     *
1137
     * @memberof IgxColumnComponent
1138
     */
1139
    public set summaries(classRef: any) {
UNCOV
1140
        if (isConstructor(classRef)) {
×
UNCOV
1141
            this._summaries = new classRef();
×
1142
        }
1143

UNCOV
1144
        if (this.grid) {
×
UNCOV
1145
            this.grid.summaryService.removeSummariesCachePerColumn(this.field);
×
UNCOV
1146
            this.grid.summaryPipeTrigger++;
×
UNCOV
1147
            this.grid.summaryService.resetSummaryHeight();
×
1148
        }
1149
    }
1150

1151
    /**
1152
     * Sets/gets the summary operands to exclude from display.
1153
     * Accepts an array of string keys representing the summary types to disable, such as 'Min', 'Max', 'Count' etc.
1154
     * ```typescript
1155
     * let disabledSummaries = this.column.disabledSummaries;
1156
     * ```
1157
     * ```html
1158
     * <igx-column [disabledSummaries]="['min', 'max', 'average']"></igx-column>
1159
     * ```
1160
     *
1161
     * @memberof IgxColumnComponent
1162
     */
1163
    @WatchColumnChanges()
1164
    @Input()
1165
    public get disabledSummaries(): string[] {
UNCOV
1166
        return this._disabledSummaries;
×
1167
    }
1168

1169
    public set disabledSummaries(value: string[]) {
UNCOV
1170
        if (isEqual(this._disabledSummaries, value)) {
×
UNCOV
1171
            return;
×
1172
        }
UNCOV
1173
        this._disabledSummaries = value;
×
UNCOV
1174
        if (this.grid) {
×
UNCOV
1175
            this.grid.summaryService.removeSummariesCachePerColumn(this.field);
×
UNCOV
1176
            this.grid.summaryPipeTrigger++;
×
UNCOV
1177
            this.grid.summaryService.resetSummaryHeight();
×
1178
        }
1179
    }
1180

1181
    /**
1182
     * Gets the column `filters`.
1183
     * ```typescript
1184
     * let columnFilters = this.column.filters'
1185
     * ```
1186
     *
1187
     * @memberof IgxColumnComponent
1188
     */
1189
    @Input()
1190
    public get filters(): IgxFilteringOperand {
UNCOV
1191
        return this._filters;
×
1192
    }
1193
    /**
1194
     * Sets the column `filters`.
1195
     * ```typescript
1196
     * this.column.filters = IgxBooleanFilteringOperand.instance().
1197
     * ```
1198
     *
1199
     * @memberof IgxColumnComponent
1200
     */
1201
    public set filters(instance: IgxFilteringOperand) {
UNCOV
1202
        this._filters = instance;
×
1203
    }
1204
    /**
1205
     * Gets the column `sortStrategy`.
1206
     * ```typescript
1207
     * let sortStrategy = this.column.sortStrategy
1208
     * ```
1209
     *
1210
     * @memberof IgxColumnComponent
1211
     */
1212
    @Input()
1213
    public get sortStrategy(): ISortingStrategy {
UNCOV
1214
        return this._sortStrategy;
×
1215
    }
1216
    /**
1217
     * Sets the column `sortStrategy`.
1218
     * ```typescript
1219
     * this.column.sortStrategy = new CustomSortingStrategy().
1220
     * class CustomSortingStrategy extends SortingStrategy {...}
1221
     * ```
1222
     *
1223
     * @memberof IgxColumnComponent
1224
     */
1225
    public set sortStrategy(classRef: ISortingStrategy) {
UNCOV
1226
        this._sortStrategy = classRef;
×
1227
    }
1228

1229
    /* blazorSuppress */
1230
    /**
1231
     * Gets the function that compares values for merging.
1232
     * ```typescript
1233
     * let mergingComparer = this.column.mergingComparer'
1234
     * ```
1235
     */
1236
    @Input()
1237
    public get mergingComparer(): (prevRecord: any, record: any, field: string) => boolean {
UNCOV
1238
        return this._mergingComparer;
×
1239
    }
1240

1241
    /* blazorSuppress */
1242
    /**
1243
     * Sets a custom function to compare values for merging.
1244
     * ```typescript
1245
     * this.column.mergingComparer = (prevRecord: any, record: any, field: string) => { return prevRecord[field] === record[field]; }
1246
     * ```
1247
     */
1248
    public set mergingComparer(funcRef: (prevRecord: any, record: any, field: string) => boolean) {
UNCOV
1249
        this._mergingComparer = funcRef;
×
1250
    }
1251

1252

1253
    /* blazorSuppress */
1254
    /**
1255
     * Gets the function that compares values for grouping.
1256
     * ```typescript
1257
     * let groupingComparer = this.column.groupingComparer'
1258
     * ```
1259
     *
1260
     * @memberof IgxColumnComponent
1261
     */
1262
    @Input()
1263
    public get groupingComparer(): (a: any, b: any, currRec?: any, groupRec?: any) => number {
UNCOV
1264
        return this._groupingComparer;
×
1265
    }
1266

1267
    /* blazorSuppress */
1268
    /**
1269
     * Sets a custom function to compare values for grouping.
1270
     * Subsequent values in the sorted data that the function returns 0 for are grouped.
1271
     * ```typescript
1272
     * this.column.groupingComparer = (a: any, b: any, currRec?: any, groupRec?: any) => { return a === b ? 0 : -1; }
1273
     * ```
1274
     *
1275
     * @memberof IgxColumnComponent
1276
     */
1277
    public set groupingComparer(funcRef: (a: any, b: any, currRec?: any, groupRec?: any) => number) {
UNCOV
1278
        this._groupingComparer = funcRef;
×
1279
    }
1280
    /**
1281
     * @hidden @internal
1282
     */
1283
    public get defaultMinWidth(): string {
UNCOV
1284
        if (!this.grid) {
×
1285
            return '80';
×
1286
        }
UNCOV
1287
        switch (this.grid.gridSize) {
×
1288
            case ɵSize.Medium:
UNCOV
1289
                return '64';
×
1290
            case ɵSize.Small:
UNCOV
1291
                return '56';
×
1292
            default:
UNCOV
1293
                return '80';
×
1294
        }
1295
    }
1296
    /**
1297
     * Returns a reference to the `summaryTemplate`.
1298
     * ```typescript
1299
     * let summaryTemplate = this.column.summaryTemplate;
1300
     * ```
1301
     *
1302
     * @memberof IgxColumnComponent
1303
     */
1304
    @notifyChanges()
1305
    @WatchColumnChanges()
1306
    @Input()
1307
    public get summaryTemplate(): TemplateRef<IgxSummaryTemplateContext> {
UNCOV
1308
        return this._summaryTemplate;
×
1309
    }
1310
    /**
1311
     * Sets the summary template.
1312
     * ```html
1313
     * <ng-template #summaryTemplate igxSummary let-summaryResults>
1314
     *    <p>{{ summaryResults[0].label }}: {{ summaryResults[0].summaryResult }}</p>
1315
     *    <p>{{ summaryResults[1].label }}: {{ summaryResults[1].summaryResult }}</p>
1316
     * </ng-template>
1317
     * ```
1318
     * ```typescript
1319
     * @ViewChild("'summaryTemplate'", {read: TemplateRef })
1320
     * public summaryTemplate: TemplateRef<any>;
1321
     * this.column.summaryTemplate = this.summaryTemplate;
1322
     * ```
1323
     *
1324
     * @memberof IgxColumnComponent
1325
     */
1326
    public set summaryTemplate(template: TemplateRef<IgxSummaryTemplateContext>) {
UNCOV
1327
        this._summaryTemplate = template;
×
1328
    }
1329

1330
    /**
1331
     * Returns a reference to the `bodyTemplate`.
1332
     * ```typescript
1333
     * let bodyTemplate = this.column.bodyTemplate;
1334
     * ```
1335
     *
1336
     * @memberof IgxColumnComponent
1337
     */
1338
    @notifyChanges()
1339
    @WatchColumnChanges()
1340
    @Input('cellTemplate')
1341
    public get bodyTemplate(): TemplateRef<IgxCellTemplateContext> {
UNCOV
1342
        return this._bodyTemplate;
×
1343
    }
1344
    /**
1345
     * Sets the body template.
1346
     * ```html
1347
     * <ng-template #bodyTemplate igxCell let-val>
1348
     *    <div style = "background-color: yellowgreen" (click) = "changeColor(val)">
1349
     *       <span> {{val}} </span>
1350
     *    </div>
1351
     * </ng-template>
1352
     * ```
1353
     * ```typescript
1354
     * @ViewChild("'bodyTemplate'", {read: TemplateRef })
1355
     * public bodyTemplate: TemplateRef<any>;
1356
     * this.column.bodyTemplate = this.bodyTemplate;
1357
     * ```
1358
     *
1359
     * @memberof IgxColumnComponent
1360
     */
1361
    public set bodyTemplate(template: TemplateRef<IgxCellTemplateContext>) {
UNCOV
1362
        this._bodyTemplate = template;
×
1363
    }
1364
    /**
1365
     * Returns a reference to the header template.
1366
     * ```typescript
1367
     * let headerTemplate = this.column.headerTemplate;
1368
     * ```
1369
     *
1370
     * @memberof IgxColumnComponent
1371
     */
1372
    @notifyChanges()
1373
    @WatchColumnChanges()
1374
    @Input()
1375
    public get headerTemplate(): TemplateRef<IgxColumnTemplateContext> {
UNCOV
1376
        return this._headerTemplate;
×
1377
    }
1378
    /**
1379
     * Sets the header template.
1380
     * Note that the column header height is fixed and any content bigger than it will be cut off.
1381
     * ```html
1382
     * <ng-template #headerTemplate>
1383
     *   <div style = "background-color:black" (click) = "changeColor(val)">
1384
     *       <span style="color:red" >{{column.field}}</span>
1385
     *   </div>
1386
     * </ng-template>
1387
     * ```
1388
     * ```typescript
1389
     * @ViewChild("'headerTemplate'", {read: TemplateRef })
1390
     * public headerTemplate: TemplateRef<any>;
1391
     * this.column.headerTemplate = this.headerTemplate;
1392
     * ```
1393
     *
1394
     * @memberof IgxColumnComponent
1395
     */
1396
    public set headerTemplate(template: TemplateRef<IgxColumnTemplateContext>) {
UNCOV
1397
        this._headerTemplate = template;
×
1398
    }
1399
    /**
1400
     * Returns a reference to the inline editor template.
1401
     * ```typescript
1402
     * let inlineEditorTemplate = this.column.inlineEditorTemplate;
1403
     * ```
1404
     *
1405
     * @memberof IgxColumnComponent
1406
     */
1407
    @notifyChanges()
1408
    @WatchColumnChanges()
1409
    @Input('cellEditorTemplate')
1410
    public get inlineEditorTemplate(): TemplateRef<IgxCellTemplateContext> {
UNCOV
1411
        return this._inlineEditorTemplate;
×
1412
    }
1413
    /**
1414
     * Sets the inline editor template.
1415
     * ```html
1416
     * <ng-template #inlineEditorTemplate igxCellEditor let-cell="cell">
1417
     *     <input type="string" [(ngModel)]="cell.value"/>
1418
     * </ng-template>
1419
     * ```
1420
     * ```typescript
1421
     * @ViewChild("'inlineEditorTemplate'", {read: TemplateRef })
1422
     * public inlineEditorTemplate: TemplateRef<any>;
1423
     * this.column.inlineEditorTemplate = this.inlineEditorTemplate;
1424
     * ```
1425
     *
1426
     * @memberof IgxColumnComponent
1427
     */
1428
    public set inlineEditorTemplate(template: TemplateRef<IgxCellTemplateContext>) {
UNCOV
1429
        this._inlineEditorTemplate = template;
×
1430
    }
1431

1432
    /**
1433
     * Returns a reference to the validation error template.
1434
     * ```typescript
1435
     * let errorTemplate = this.column.errorTemplate;
1436
     * ```
1437
     */
1438
    @notifyChanges()
1439
    @WatchColumnChanges()
1440
    @Input('errorTemplate')
1441
    public get errorTemplate(): TemplateRef<IgxCellTemplateContext> {
UNCOV
1442
        return this._errorTemplate;
×
1443
    }
1444
    /**
1445
     * Sets the error template.
1446
     * ```html
1447
     * <ng-template igxCellValidationError let-cell="cell" #errorTemplate >
1448
     *     <div *ngIf="cell.validation.errors?.['forbiddenName']">
1449
     *      This name is forbidden.
1450
     *     </div>
1451
     * </ng-template>
1452
     * ```
1453
     * ```typescript
1454
     * @ViewChild("'errorTemplate'", {read: TemplateRef })
1455
     * public errorTemplate: TemplateRef<any>;
1456
     * this.column.errorTemplate = this.errorTemplate;
1457
     * ```
1458
     */
1459
    public set errorTemplate(template: TemplateRef<IgxCellTemplateContext>) {
UNCOV
1460
        this._errorTemplate = template;
×
1461
    }
1462

1463
    /**
1464
     * Returns a reference to the `filterCellTemplate`.
1465
     * ```typescript
1466
     * let filterCellTemplate = this.column.filterCellTemplate;
1467
     * ```
1468
     *
1469
     * @memberof IgxColumnComponent
1470
     */
1471
    @notifyChanges()
1472
    @WatchColumnChanges()
1473
    @Input('filterCellTemplate')
1474
    public get filterCellTemplate(): TemplateRef<IgxColumnTemplateContext> {
UNCOV
1475
        return this._filterCellTemplate;
×
1476
    }
1477
    /**
1478
     * Sets the quick filter template.
1479
     * ```html
1480
     * <ng-template #filterCellTemplate IgxFilterCellTemplate let-column="column">
1481
     *    <input (input)="onInput()">
1482
     * </ng-template>
1483
     * ```
1484
     * ```typescript
1485
     * @ViewChild("'filterCellTemplate'", {read: TemplateRef })
1486
     * public filterCellTemplate: TemplateRef<any>;
1487
     * this.column.filterCellTemplate = this.filterCellTemplate;
1488
     * ```
1489
     *
1490
     * @memberof IgxColumnComponent
1491
     */
1492
    public set filterCellTemplate(template: TemplateRef<IgxColumnTemplateContext>) {
UNCOV
1493
        this._filterCellTemplate = template;
×
1494
    }
1495

1496
    /**
1497
     * @hidden @internal
1498
     */
1499
    public get cells(): CellType[] {
UNCOV
1500
        return this.grid.dataView
×
1501
            .map((rec, index) => {
UNCOV
1502
                if (!this.grid.isGroupByRecord(rec) && !this.grid.isSummaryRow(rec)) {
×
UNCOV
1503
                    this.grid.pagingMode === 'remote' && this.grid.page !== 0 ?
×
1504
                        index = index + this.grid.perPage * this.grid.page : index = this.grid.dataRowList.first.index + index;
UNCOV
1505
                    const cell = new IgxGridCell(this.grid as any, index, this);
×
UNCOV
1506
                    return cell;
×
1507
                }
UNCOV
1508
            }).filter(cell => cell);
×
1509
    }
1510

1511

1512
    /**
1513
     * @hidden @internal
1514
     */
1515
    public get _cells(): CellType[] {
UNCOV
1516
        return this.grid.rowList.filter((row) => row instanceof IgxRowDirective)
×
1517
            .map((row) => {
UNCOV
1518
                if (row._cells) {
×
UNCOV
1519
                    return row._cells.filter((cell) => cell.columnIndex === this.index);
×
1520
                }
UNCOV
1521
            }).reduce((a, b) => a.concat(b), []);
×
1522
    }
1523

1524
    /**
1525
     * Gets the column visible index.
1526
     * If the column is not visible, returns `-1`.
1527
     * ```typescript
1528
     * let visibleColumnIndex =  this.column.visibleIndex;
1529
     * ```
1530
     */
1531
    public get visibleIndex(): number {
UNCOV
1532
        if (!isNaN(this._vIndex)) {
×
UNCOV
1533
            return this._vIndex;
×
1534
        }
UNCOV
1535
        const unpinnedColumns = this.grid.unpinnedColumns.filter(c => !c.columnGroup);
×
UNCOV
1536
        const pinnedStartColumns = this.grid.pinnedStartColumns.filter(c => !c.columnGroup);
×
UNCOV
1537
        const pinnedEndColumns = this.grid.pinnedEndColumns.filter(c => !c.columnGroup);
×
1538

UNCOV
1539
        let col = this;
×
UNCOV
1540
        let vIndex = -1;
×
1541

UNCOV
1542
        if (this.columnGroup) {
×
UNCOV
1543
            col = this.allChildren.filter(c => !c.columnGroup && !c.hidden)[0] as any;
×
1544
        }
UNCOV
1545
        if (this.columnLayoutChild) {
×
1546
            // TODO: Refactor/redo/remove this
UNCOV
1547
            return (this.parent as IgxColumnLayoutComponent).childrenVisibleIndexes.find(x => x.column === this).index;
×
1548
        }
1549

UNCOV
1550
        if (!this.pinned) {
×
UNCOV
1551
            const indexInCollection = unpinnedColumns.indexOf(col);
×
UNCOV
1552
            vIndex = indexInCollection === -1 ?
×
1553
                -1 : pinnedStartColumns.length + indexInCollection;
1554
        } else {
UNCOV
1555
            const indexInCollection = this.pinningPosition === ColumnPinningPosition.Start ?
×
1556
            pinnedStartColumns.indexOf(col) : pinnedEndColumns.indexOf(col);
UNCOV
1557
            vIndex = this.pinningPosition === ColumnPinningPosition.Start ?
×
1558
                indexInCollection :
1559
                pinnedStartColumns.length + unpinnedColumns.length + indexInCollection;
1560
        }
UNCOV
1561
        this._vIndex = vIndex;
×
UNCOV
1562
        return vIndex;
×
1563
    }
1564

1565
    /* blazorCSSuppress - Blazor doesn't carry over the ColumnType interface + should translate as static bool value */
1566
    /**
1567
     * Returns a boolean indicating if the column is a `ColumnGroup`.
1568
     * ```typescript
1569
     * let columnGroup =  this.column.columnGroup;
1570
     * ```
1571
     *
1572
     * @memberof IgxColumnComponent
1573
     */
1574
    public get columnGroup() {
UNCOV
1575
        return false;
×
1576
    }
1577

1578
    /* blazorCSSuppress - Blazor doesn't carry over the ColumnType interface + should translate as static bool value */
1579
    /**
1580
     * Returns a boolean indicating if the column is a `ColumnLayout` for multi-row layout.
1581
     * ```typescript
1582
     * let columnGroup =  this.column.columnGroup;
1583
     * ```
1584
     *
1585
     * @memberof IgxColumnComponent
1586
     */
1587
    public get columnLayout() {
UNCOV
1588
        return false;
×
1589
    }
1590

1591
    /**
1592
     * Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
1593
     * ```typescript
1594
     * let columnLayoutChild =  this.column.columnLayoutChild;
1595
     * ```
1596
     *
1597
     * @memberof IgxColumnComponent
1598
     */
1599
    public get columnLayoutChild(): boolean {
UNCOV
1600
        return this.parent && this.parent.columnLayout;
×
1601
    }
1602

1603
    /**
1604
     * A list containing all the child columns under this column (if any).
1605
     * Empty without children or if this column is not Group or Layout.
1606
     */
1607
    public get childColumns(): ColumnType[] {
1608
        return [];
×
1609
    }
1610

1611
    /** @hidden @internal **/
1612
    public get allChildren(): IgxColumnComponent[] {
UNCOV
1613
        return [];
×
1614
    }
1615
    /**
1616
     * Returns the level of the column in a column group.
1617
     * Returns `0` if the column doesn't have a `parent`.
1618
     * ```typescript
1619
     * let columnLevel =  this.column.level;
1620
     * ```
1621
     *
1622
     * @memberof IgxColumnComponent
1623
     */
1624
    public get level() {
UNCOV
1625
        let ptr = this.parent;
×
UNCOV
1626
        let lvl = 0;
×
1627

UNCOV
1628
        while (ptr) {
×
UNCOV
1629
            lvl++;
×
UNCOV
1630
            ptr = ptr.parent;
×
1631
        }
UNCOV
1632
        return lvl;
×
1633
    }
1634

1635
    /** @hidden @internal **/
1636
    public get isLastPinned(): boolean {
UNCOV
1637
        return this.pinningPosition === ColumnPinningPosition.Start &&
×
1638
            this.grid.pinnedStartColumns[this.grid.pinnedStartColumns.length - 1] === this;
1639
    }
1640

1641
    /** @hidden @internal **/
1642
    public get isFirstPinned(): boolean {
UNCOV
1643
        const pinnedCols = this.grid.pinnedEndColumns.filter(x => !x.columnGroup);
×
UNCOV
1644
        return this.pinningPosition === ColumnPinningPosition.End && pinnedCols[0] === this;
×
1645
    }
1646

1647
    /** @hidden @internal **/
1648
    public get gridRowSpan(): number {
UNCOV
1649
        return this.rowEnd && this.rowStart ? this.rowEnd - this.rowStart : 1;
×
1650
    }
1651
    /** @hidden @internal **/
1652
    public get gridColumnSpan(): number {
UNCOV
1653
        return this.colEnd && this.colStart ? this.colEnd - this.colStart : 1;
×
1654
    }
1655

1656
    /**
1657
     * Indicates whether the column will be visible when its parent is collapsed.
1658
     * ```html
1659
     * <igx-column-group>
1660
     *   <igx-column [visibleWhenCollapsed]="true"></igx-column>
1661
     * </igx-column-group>
1662
     * ```
1663
     *
1664
     * @memberof IgxColumnComponent
1665
     */
1666
    @notifyChanges(true)
1667
    @Input({ transform: booleanAttribute })
1668
    public set visibleWhenCollapsed(value: boolean) {
UNCOV
1669
        this._visibleWhenCollapsed = value;
×
UNCOV
1670
        this.visibleWhenCollapsedChange.emit(this._visibleWhenCollapsed);
×
UNCOV
1671
        if (this.parent) {
×
1672
            // TODO: Refactor/redo/remove this
UNCOV
1673
            (this.parent as IgxColumnLayoutComponent)?.setExpandCollapseState?.();
×
1674
        }
1675
    }
1676

1677
    public get visibleWhenCollapsed(): boolean {
UNCOV
1678
        return this._visibleWhenCollapsed;
×
1679
    }
1680

1681
    /* mustSetInCodePlatforms: WebComponents;Blazor;React */
1682
    /**
1683
     * @remarks
1684
     * Pass optional parameters for DatePipe and/or DecimalPipe to format the display value for date and numeric columns.
1685
     * Accepts an `IColumnPipeArgs` object with any of the `format`, `timezone` and `digitsInfo` properties.
1686
     * For more details see https://angular.io/api/common/DatePipe and https://angular.io/api/common/DecimalPipe
1687
     * @example
1688
     * ```typescript
1689
     * const pipeArgs: IColumnPipeArgs = {
1690
     *      format: 'longDate',
1691
     *      timezone: 'UTC',
1692
     *      digitsInfo: '1.1-2'
1693
     * }
1694
     * ```
1695
     * ```html
1696
     * <igx-column dataType="date" [pipeArgs]="pipeArgs"></igx-column>
1697
     * <igx-column dataType="number" [pipeArgs]="pipeArgs"></igx-column>
1698
     * ```
1699
     * @memberof IgxColumnComponent
1700
     */
1701
    @notifyChanges()
1702
    @WatchColumnChanges()
1703
    @Input()
1704
    public set pipeArgs(value: IColumnPipeArgs) {
UNCOV
1705
        this._columnPipeArgs = Object.assign(this._columnPipeArgs, value);
×
UNCOV
1706
        this.grid.summaryService.clearSummaryCache();
×
UNCOV
1707
        this.grid.pipeTrigger++;
×
1708
    }
1709
    /* mustSetInCodePlatforms: WebComponents;Blazor */
1710
    public get pipeArgs(): IColumnPipeArgs {
UNCOV
1711
        return this._columnPipeArgs;
×
1712
    }
1713

1714
    /**
1715
     * Pass optional properties for the default column editors.
1716
     * @remarks
1717
     * Options may be applicable only to specific column type editors.
1718
     * @example
1719
     * ```typescript
1720
     * const editorOptions: IColumnEditorOptions = {
1721
     *      dateTimeFormat: 'MM/dd/YYYY',
1722
     * }
1723
     * ```
1724
     * ```html
1725
     * <igx-column dataType="date" [editorOptions]="editorOptions"></igx-column>
1726
     * ```
1727
     * @memberof IgxColumnComponent
1728
     */
1729
    @notifyChanges()
1730
    @WatchColumnChanges()
1731
    @Input()
1732
    public set editorOptions(value: IColumnEditorOptions) {
UNCOV
1733
        this._editorOptions = value;
×
1734
    }
1735
    public get editorOptions(): IColumnEditorOptions {
UNCOV
1736
        return this._editorOptions;
×
1737
    }
1738

1739
    /**
1740
     * @hidden
1741
     * @internal
1742
     */
1743
    public get collapsible() {
1744
        return false;
×
1745
    }
1746
    public set collapsible(_value: boolean) { }
1747

1748
    /**
1749
     * @hidden
1750
     * @internal
1751
     */
1752
    public get expanded() {
1753
        return true;
×
1754
    }
1755
    public set expanded(_value: boolean) { }
1756

1757
    /**
1758
     * @hidden
1759
     */
1760
    public defaultWidth: string;
1761

1762
    /**
1763
     * @hidden
1764
     */
1765
    public widthSetByUser: boolean;
1766

1767
    /**
1768
     * @hidden
1769
     */
1770
    public hasNestedPath: boolean;
1771

1772
    /**
1773
     * @hidden
1774
     * @internal
1775
     */
UNCOV
1776
    public defaultTimeFormat = 'hh:mm:ss a';
×
1777

1778
    /**
1779
     * @hidden
1780
     * @internal
1781
     */
UNCOV
1782
    public defaultDateTimeFormat = 'dd/MM/yyyy HH:mm:ss a';
×
1783

1784

1785
    /**
1786
     * Returns the filteringExpressionsTree of the column.
1787
     * ```typescript
1788
     * let tree =  this.column.filteringExpressionsTree;
1789
     * ```
1790
     *
1791
     * @memberof IgxColumnComponent
1792
     */
1793
    public get filteringExpressionsTree(): FilteringExpressionsTree {
UNCOV
1794
        return ExpressionsTreeUtil.find(this.grid.filteringExpressionsTree, this.field) as FilteringExpressionsTree;
×
1795
    }
1796

1797
    /* alternateName: parentColumn */
1798
    /* blazorAlternateType: object */
1799
    // We need that because Blazor cannot handle the type correctly.
1800
    /**
1801
     * Sets/gets the parent column.
1802
     * ```typescript
1803
     * let parentColumn = this.column.parent;
1804
     * ```
1805
     * ```typescript
1806
     * this.column.parent = higherLevelColumn;
1807
     * ```
1808
     */
UNCOV
1809
    public parent: ColumnType | null = null;
×
1810

1811
    /* blazorSuppress */
1812
    /**
1813
     * Sets/gets the children columns.
1814
     * ```typescript
1815
     * let columnChildren = this.column.children;
1816
     * ```
1817
     *
1818
     * @deprecated in version 18.1.0. Use the `childColumns` property instead.
1819
     */
1820
    public children: QueryList<IgxColumnComponent>;
1821
    /**
1822
     * @hidden
1823
     */
UNCOV
1824
    public destroy$ = new Subject<any>();
×
1825

1826
    /**
1827
     * @hidden
1828
     */
UNCOV
1829
    public widthConstrained = false;
×
1830

1831
    /**
1832
     * @hidden
1833
     */
UNCOV
1834
    protected _applySelectableClass = false;
×
1835

UNCOV
1836
    protected _vIndex = NaN;
×
UNCOV
1837
    protected _pinningPosition = null;
×
1838
    /**
1839
     * @hidden
1840
     */
UNCOV
1841
    protected _pinned = false;
×
1842
    /**
1843
     * @hidden
1844
     */
1845
    protected _bodyTemplate: TemplateRef<IgxCellTemplateContext>;
1846
    /**
1847
     * @hidden
1848
     */
1849
    protected _errorTemplate: TemplateRef<IgxCellTemplateContext>;
1850
    /**
1851
     * @hidden
1852
     */
1853
    protected _headerTemplate: TemplateRef<IgxColumnTemplateContext>;
1854
    /**
1855
     * @hidden
1856
     */
1857
    protected _summaryTemplate: TemplateRef<IgxSummaryTemplateContext>;
1858
    /**
1859
     * @hidden
1860
     */
1861
    protected _inlineEditorTemplate: TemplateRef<IgxCellTemplateContext>;
1862
    /**
1863
     * @hidden
1864
     */
1865
    protected _filterCellTemplate: TemplateRef<IgxColumnTemplateContext>;
1866
    /**
1867
     * @hidden
1868
     */
UNCOV
1869
    protected _summaries = null;
×
1870
    /**
1871
     * @hidden
1872
     */
UNCOV
1873
    private _disabledSummaries: string[] = [];
×
1874
    /**
1875
     * @hidden
1876
     */
UNCOV
1877
    protected _filters = null;
×
1878
    /**
1879
     * @hidden
1880
     */
UNCOV
1881
    protected _sortStrategy: ISortingStrategy = DefaultSortingStrategy.instance();
×
1882
    /**
1883
     * @hidden
1884
     */
1885
    protected _groupingComparer: (a: any, b: any, currRec?: any, groupRec?: any) => number;
1886

1887
    protected _mergingComparer: (prevRecord: any, record: any, field: string) => boolean;
1888
    /**
1889
     * @hidden
1890
     */
UNCOV
1891
    protected _hidden = false;
×
1892
    /**
1893
     * @hidden
1894
     */
1895
    protected _index: number;
1896
    /**
1897
     * @hidden
1898
     */
UNCOV
1899
    protected _disablePinning = false;
×
1900
    /**
1901
     * @hidden
1902
     */
1903
    protected _width: string;
1904
    /**
1905
     * @hidden
1906
     */
UNCOV
1907
    protected _defaultMinWidth = '';
×
1908
    /**
1909
     * @hidden
1910
     */
1911
    protected _maxWidth;
1912
    /**
1913
     * @hidden
1914
     */
UNCOV
1915
    protected _hasSummary = false;
×
1916
    /**
1917
     * @hidden
1918
     */
1919
    protected _editable: boolean;
1920
    /**
1921
     * @hidden
1922
     */
UNCOV
1923
    protected _groupable = false;
×
1924
    /**
1925
     * @hidden
1926
     */
UNCOV
1927
    protected _merge = false;
×
1928
    /**
1929
     *  @hidden
1930
     */
1931
    protected _visibleWhenCollapsed;
1932
    /**
1933
     * @hidden
1934
     */
UNCOV
1935
    protected _collapsible = false;
×
1936
    /**
1937
     * @hidden
1938
     */
UNCOV
1939
    protected _expanded = true;
×
1940
    /**
1941
     * @hidden
1942
     */
UNCOV
1943
    protected _selectable = true;
×
1944
    /**
1945
     * @hidden
1946
     */
1947
    protected get isPrimaryColumn(): boolean {
UNCOV
1948
        return this.field !== undefined && this.grid !== undefined && this.field === this.grid.primaryKey;
×
1949
    }
1950

1951
    private _field: string;
UNCOV
1952
    private _calcWidth = null;
×
UNCOV
1953
    private _columnPipeArgs: IColumnPipeArgs = { digitsInfo: DEFAULT_DIGITS_INFO };
×
UNCOV
1954
    private _editorOptions: IColumnEditorOptions = { };
×
1955

1956
    /**
1957
     * @hidden
1958
     * @internal
1959
     */
1960
    public resetCaches() {
UNCOV
1961
        this._vIndex = NaN;
×
UNCOV
1962
        if (this.grid) {
×
UNCOV
1963
            this.cacheCalcWidth();
×
1964
        }
1965
    }
1966

1967
    /**
1968
     * @hidden
1969
     */
1970
    public ngOnDestroy() {
UNCOV
1971
        this.destroy$.next(true);
×
UNCOV
1972
        this.destroy$.complete();
×
1973
    }
1974
    /**
1975
     * @hidden
1976
     */
1977
    public ngAfterContentInit(): void {
UNCOV
1978
        if (this.summaryTemplateDirective) {
×
UNCOV
1979
            this._summaryTemplate = this.summaryTemplateDirective.template;
×
1980
        }
UNCOV
1981
        if (this.cellTemplate) {
×
UNCOV
1982
            this._bodyTemplate = this.cellTemplate.template;
×
1983
        }
UNCOV
1984
        if (this.cellValidationErrorTemplate) {
×
UNCOV
1985
            this._errorTemplate = this.cellValidationErrorTemplate.template;
×
1986
        }
UNCOV
1987
        if (this.headTemplate && this.headTemplate.length) {
×
UNCOV
1988
            this._headerTemplate = this.headTemplate.toArray()[0].template;
×
1989
        }
UNCOV
1990
        if (this.editorTemplate) {
×
UNCOV
1991
            this._inlineEditorTemplate = this.editorTemplate.template;
×
1992
        }
UNCOV
1993
        if (this.filterCellTemplateDirective) {
×
1994
            this._filterCellTemplate = this.filterCellTemplateDirective.template;
×
1995
        }
UNCOV
1996
        if (!this._columnPipeArgs.format) {
×
UNCOV
1997
            this._columnPipeArgs.format = this.dataType === GridColumnDataType.Time ?
×
1998
                DEFAULT_TIME_FORMAT : this.dataType === GridColumnDataType.DateTime ?
×
1999
                    DEFAULT_DATE_TIME_FORMAT : DEFAULT_DATE_FORMAT;
2000
        }
UNCOV
2001
        if (!this.summaries) {
×
UNCOV
2002
            switch (this.dataType) {
×
2003
                case GridColumnDataType.Number:
2004
                case GridColumnDataType.Currency:
2005
                case GridColumnDataType.Percent:
UNCOV
2006
                    this.summaries = IgxNumberSummaryOperand;
×
UNCOV
2007
                    break;
×
2008
                case GridColumnDataType.Date:
2009
                case GridColumnDataType.DateTime:
UNCOV
2010
                    this.summaries = IgxDateSummaryOperand;
×
UNCOV
2011
                    break;
×
2012
                case GridColumnDataType.Time:
UNCOV
2013
                    this.summaries = IgxTimeSummaryOperand;
×
UNCOV
2014
                    break;
×
2015

2016
                case GridColumnDataType.String:
2017
                case GridColumnDataType.Boolean:
2018
                default:
UNCOV
2019
                    this.summaries = IgxSummaryOperand;
×
UNCOV
2020
                    break;
×
2021
            }
2022
        }
UNCOV
2023
        if (!this.filters) {
×
UNCOV
2024
            switch (this.dataType) {
×
2025
                case GridColumnDataType.Boolean:
UNCOV
2026
                    this.filters = IgxBooleanFilteringOperand.instance();
×
UNCOV
2027
                    break;
×
2028
                case GridColumnDataType.Number:
2029
                case GridColumnDataType.Currency:
2030
                case GridColumnDataType.Percent:
UNCOV
2031
                    this.filters = IgxNumberFilteringOperand.instance();
×
UNCOV
2032
                    break;
×
2033
                case GridColumnDataType.Date:
UNCOV
2034
                    this.filters = IgxDateFilteringOperand.instance();
×
UNCOV
2035
                    break;
×
2036
                case GridColumnDataType.Time:
UNCOV
2037
                    this.filters = IgxTimeFilteringOperand.instance();
×
UNCOV
2038
                    break;
×
2039
                case GridColumnDataType.DateTime:
UNCOV
2040
                    this.filters = IgxDateTimeFilteringOperand.instance();
×
UNCOV
2041
                    break;
×
2042
                case GridColumnDataType.Image:
UNCOV
2043
                    this.filterable = false;
×
UNCOV
2044
                    break;
×
2045
                case GridColumnDataType.String:
2046
                default:
UNCOV
2047
                    this.filters = IgxStringFilteringOperand.instance();
×
UNCOV
2048
                    break;
×
2049
            }
2050
        }
2051
    }
2052

2053
    /**
2054
     * @hidden
2055
     */
2056
    public getGridTemplate(isRow: boolean): string {
UNCOV
2057
        if (isRow) {
×
UNCOV
2058
            const rowsCount = this.grid.type !== 'pivot' ? this.grid.multiRowLayoutRowSize : this.children.length - 1;
×
UNCOV
2059
            return `repeat(${rowsCount},1fr)`;
×
2060
        } else {
UNCOV
2061
            return this.getColumnSizesString(this.children);
×
2062
        }
2063
    }
2064

2065
    /** @hidden @internal **/
2066
    public getInitialChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<MRLColumnSizeInfo> {
UNCOV
2067
        const columnSizes: MRLColumnSizeInfo[] = [];
×
2068
        // find the smallest col spans
UNCOV
2069
        children.forEach(col => {
×
UNCOV
2070
            if (!col.colStart) {
×
UNCOV
2071
                return;
×
2072
            }
UNCOV
2073
            const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
×
UNCOV
2074
            const newSpanSmaller = columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].colSpan > col.gridColumnSpan;
×
UNCOV
2075
            const bothWidthsSet = col.widthSetByUser && columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].widthSetByUser;
×
UNCOV
2076
            const bothWidthsNotSet = !col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
×
2077

UNCOV
2078
            if (columnSizes[col.colStart - 1] === undefined) {
×
2079
                // If nothing is defined yet take any column at first
2080
                // We use colEnd to know where the column actually ends, because not always it starts where we have it set in columnSizes.
UNCOV
2081
                columnSizes[col.colStart - 1] = {
×
2082
                    ref: col,
2083
                    width: col.width === 'fit-content' ? col.autoSize :
×
2084
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
×
2085
                    colSpan: col.gridColumnSpan,
2086
                    colEnd: col.colStart + col.gridColumnSpan,
2087
                    widthSetByUser: col.widthSetByUser
2088
                };
UNCOV
2089
            } else if (newWidthSet || (newSpanSmaller && ((bothWidthsSet) || (bothWidthsNotSet)))) {
×
2090
                // If a column is set already it should either not have width defined or have width with bigger span than the new one.
2091

2092
                /**
2093
                 *  If replaced column has bigger span, we want to fill the remaining columns
2094
                 *  that the replacing column does not fill with the old one.
2095
                 */
UNCOV
2096
                if (bothWidthsSet && newSpanSmaller) {
×
2097
                    // Start from where the new column set would end and apply the old column to the rest depending on how much it spans.
2098
                    // We have not yet replaced it so we can use it directly from the columnSizes collection.
2099
                    // This is where colEnd is used because the colStart of the old column is not actually i + 1.
UNCOV
2100
                    for (let i = col.colStart - 1 + col.gridColumnSpan; i < columnSizes[col.colStart - 1].colEnd - 1; i++) {
×
UNCOV
2101
                        if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
×
UNCOV
2102
                            columnSizes[i] = columnSizes[col.colStart - 1];
×
2103
                        } else {
UNCOV
2104
                            break;
×
2105
                        }
2106
                    }
2107
                }
2108

2109
                // Replace the old column with the new one.
UNCOV
2110
                columnSizes[col.colStart - 1] = {
×
2111
                    ref: col,
2112
                    width: col.width === 'fit-content' ? col.autoSize :
×
2113
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
×
2114
                    colSpan: col.gridColumnSpan,
2115
                    colEnd: col.colStart + col.gridColumnSpan,
2116
                    widthSetByUser: col.widthSetByUser
2117
                };
UNCOV
2118
            } else if (bothWidthsSet && columnSizes[col.colStart - 1].colSpan < col.gridColumnSpan) {
×
2119
                // If the column already in the columnSizes has smaller span, we still need to fill any empty places with the current col.
2120
                // Start from where the smaller column set would end and apply the bigger column to the rest depending on how much it spans.
2121
                // Since here we do not have it in columnSizes we set it as a new column keeping the same colSpan.
UNCOV
2122
                for (let i = col.colStart - 1 + columnSizes[col.colStart - 1].colSpan; i < col.colStart - 1 + col.gridColumnSpan; i++) {
×
UNCOV
2123
                    if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
×
UNCOV
2124
                        columnSizes[i] = {
×
2125
                            ref: col,
2126
                            width: col.width === 'fit-content' ? col.autoSize :
×
2127
                                col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null,
×
2128
                            colSpan: col.gridColumnSpan,
2129
                            colEnd: col.colStart + col.gridColumnSpan,
2130
                            widthSetByUser: col.widthSetByUser
2131
                        };
2132
                    } else {
UNCOV
2133
                        break;
×
2134
                    }
2135
                }
2136
            }
2137
        });
2138

2139
        // Flatten columnSizes so there are not columns with colSpan > 1
UNCOV
2140
        for (let i = 0; i < columnSizes.length; i++) {
×
UNCOV
2141
            if (columnSizes[i] && columnSizes[i].colSpan > 1) {
×
UNCOV
2142
                let j = 1;
×
2143

2144
                // Replace all empty places depending on how much the current column spans starting from next col.
UNCOV
2145
                for (; j < columnSizes[i].colSpan && i + j + 1 < columnSizes[i].colEnd; j++) {
×
UNCOV
2146
                    if (columnSizes[i + j] &&
×
2147
                        ((!columnSizes[i].width && columnSizes[i + j].width) ||
2148
                            (!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
2149
                            (!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
2150
                        // If we reach an already defined column that has width and the current doesn't have or
2151
                        // if the reached column has bigger colSpan we stop.
UNCOV
2152
                        break;
×
2153
                    } else {
UNCOV
2154
                        const width = columnSizes[i].widthSetByUser ?
×
2155
                            columnSizes[i].width / columnSizes[i].colSpan :
2156
                            columnSizes[i].width;
UNCOV
2157
                        columnSizes[i + j] = {
×
2158
                            ref: columnSizes[i].ref,
2159
                            width,
2160
                            colSpan: 1,
2161
                            colEnd: columnSizes[i].colEnd,
2162
                            widthSetByUser: columnSizes[i].widthSetByUser
2163
                        };
2164
                    }
2165
                }
2166

2167
                // Update the current column width so it is divided between all columns it spans and set it to 1.
UNCOV
2168
                columnSizes[i].width = columnSizes[i].widthSetByUser ?
×
2169
                    columnSizes[i].width / columnSizes[i].colSpan :
2170
                    columnSizes[i].width;
UNCOV
2171
                columnSizes[i].colSpan = 1;
×
2172

2173
                // Update the index based on how much we have replaced. Subtract 1 because we started from 1.
UNCOV
2174
                i += j - 1;
×
2175
            }
2176
        }
2177

UNCOV
2178
        return columnSizes;
×
2179
    }
2180

2181
    /** @hidden @internal **/
2182
    public getFilledChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<string> {
UNCOV
2183
        const columnSizes = this.getInitialChildColumnSizes(children);
×
2184

2185
        // fill the gaps if there are any
UNCOV
2186
        const result: string[] = [];
×
UNCOV
2187
        for (const size of columnSizes) {
×
UNCOV
2188
            if (size && !!size.width) {
×
UNCOV
2189
                result.push(size.width + 'px');
×
2190
            } else {
UNCOV
2191
                const currentWidth = parseFloat(this.grid.getPossibleColumnWidth());
×
UNCOV
2192
                const target = size && size.ref ? size.ref : this;
×
UNCOV
2193
                result.push((target as IgxColumnComponent).getConstrainedSizePx(currentWidth) + 'px');
×
2194
            }
2195
        }
UNCOV
2196
        return result;
×
2197
    }
2198

2199
    /** @hidden @internal **/
2200
    public getResizableColUnderEnd(): MRLResizeColumnInfo[] {
UNCOV
2201
        if (this.columnLayout || !this.columnLayoutChild || this.columnGroup) {
×
2202
            return [{ target: this, spanUsed: 1 }];
×
2203
        }
2204

UNCOV
2205
        const columnSized = this.getInitialChildColumnSizes(this.parent.children as QueryList<IgxColumnComponent>);
×
UNCOV
2206
        const targets: MRLResizeColumnInfo[] = [];
×
UNCOV
2207
        const colEnd = this.colEnd ? this.colEnd : this.colStart + 1;
×
2208

UNCOV
2209
        for (let i = 0; i < columnSized.length; i++) {
×
UNCOV
2210
            if (this.colStart <= i + 1 && i + 1 < colEnd) {
×
UNCOV
2211
                targets.push({ target: columnSized[i].ref, spanUsed: 1 });
×
2212
            }
2213
        }
2214

UNCOV
2215
        const targetsSquashed: MRLResizeColumnInfo[] = [];
×
UNCOV
2216
        for (const target of targets) {
×
UNCOV
2217
            if (targetsSquashed.length && targetsSquashed[targetsSquashed.length - 1].target.field === target.target.field) {
×
2218
                targetsSquashed[targetsSquashed.length - 1].spanUsed++;
×
2219
            } else {
UNCOV
2220
                targetsSquashed.push(target);
×
2221
            }
2222
        }
2223

UNCOV
2224
        return targetsSquashed;
×
2225
    }
2226

2227
    /**
2228
     * Pins the column in the specified position at the provided index in that pinned area.
2229
     * Defaults to index `0` if not provided, or to the initial index in the pinned area.
2230
     * Returns `true` if the column is successfully pinned. Returns `false` if the column cannot be pinned.
2231
     * Column cannot be pinned if:
2232
     * - Is already pinned
2233
     * - index argument is out of range
2234
     * ```typescript
2235
     * let success = this.column.pin();
2236
     * ```
2237
     *
2238
     * @memberof IgxColumnComponent
2239
     */
2240
    public pin(index?: number, pinningPosition?: ColumnPinningPosition): boolean {
2241
        // TODO: Probably should the return type of the old functions
2242
        // should be moved as a event parameter.
UNCOV
2243
        const grid = (this.grid as any);
×
UNCOV
2244
        if (this._pinned) {
×
UNCOV
2245
            return false;
×
2246
        }
2247

UNCOV
2248
        if (this.parent && !this.parent.pinned) {
×
UNCOV
2249
            return this.topLevelParent.pin(index, pinningPosition);
×
2250
        }
UNCOV
2251
        const targetPinPosition = pinningPosition !== null && pinningPosition !== undefined ?  pinningPosition : this.pinningPosition;
×
UNCOV
2252
        const pinningVisibleCollection = targetPinPosition === ColumnPinningPosition.Start ?
×
2253
        grid.pinnedStartColumns : grid.pinnedEndColumns;
UNCOV
2254
        const pinningCollection = targetPinPosition === ColumnPinningPosition.Start ?
×
2255
        grid._pinnedStartColumns : grid._pinnedEndColumns;
UNCOV
2256
        const hasIndex = index !== undefined && index !== null;
×
UNCOV
2257
        if (hasIndex && (index < 0 || index > pinningVisibleCollection.length)) {
×
UNCOV
2258
            return false;
×
2259
        }
2260

UNCOV
2261
        if (!this.parent && !this.pinnable) {
×
2262
            return false;
×
2263
        }
2264

UNCOV
2265
        const rootPinnedCols = pinningCollection.filter((c) => c.level === 0);
×
UNCOV
2266
        index = hasIndex ? index : rootPinnedCols.length;
×
UNCOV
2267
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: false, cancel: false };
×
UNCOV
2268
        this.grid.columnPin.emit(args);
×
2269

UNCOV
2270
        if (args.cancel) {
×
2271
            return;
×
2272
        }
2273

UNCOV
2274
        this.grid.crudService.endEdit(false);
×
2275

UNCOV
2276
        this._pinned = true;
×
UNCOV
2277
        if (pinningPosition !== null && pinningPosition !== undefined) {
×
2278
            // if user has set some position in the params, overwrite the column's position.
UNCOV
2279
            this._pinningPosition = pinningPosition;
×
2280
        }
2281

UNCOV
2282
        this.pinnedChange.emit(this._pinned);
×
2283
        // it is possible that index is the last position, so will need to find target column by [index-1]
UNCOV
2284
        const targetColumn = args.insertAtIndex === pinningCollection.length ?
×
2285
        pinningCollection[args.insertAtIndex - 1] : pinningCollection[args.insertAtIndex];
2286

UNCOV
2287
        if (pinningCollection.indexOf(this) === -1) {
×
UNCOV
2288
            if (!grid.hasColumnGroups) {
×
UNCOV
2289
                pinningCollection.splice(args.insertAtIndex, 0, this);
×
UNCOV
2290
                grid._pinnedColumns = grid._pinnedStartColumns.concat(grid._pinnedEndColumns);
×
2291
            } else {
2292
                // insert based only on root collection
UNCOV
2293
                if (this.level === 0) {
×
UNCOV
2294
                    rootPinnedCols.splice(args.insertAtIndex, 0, this);
×
2295
                }
UNCOV
2296
                let allPinned = [];
×
2297
                // FIX: this is duplicated on every step in the hierarchy....
2298
                // re-create hierarchy
UNCOV
2299
                rootPinnedCols.forEach(group => {
×
UNCOV
2300
                    allPinned.push(group);
×
UNCOV
2301
                    allPinned = allPinned.concat(group.allChildren);
×
2302
                });
UNCOV
2303
                grid._pinnedColumns = allPinned;
×
UNCOV
2304
                if (this.pinningPosition === ColumnPinningPosition.Start) {
×
UNCOV
2305
                    grid._pinnedStartColumns = allPinned;
×
2306
                } else {
UNCOV
2307
                    grid._pinnedEndColumns = allPinned;
×
2308
                }
2309
            }
2310

UNCOV
2311
            if (grid._unpinnedColumns.indexOf(this) !== -1) {
×
UNCOV
2312
                const childrenCount = this.allChildren.length;
×
UNCOV
2313
                grid._unpinnedColumns.splice(grid._unpinnedColumns.indexOf(this), 1 + childrenCount);
×
2314
            }
2315
        }
2316

UNCOV
2317
        if (hasIndex) {
×
UNCOV
2318
            index === pinningCollection.length - 1 ?
×
2319
                grid._moveColumns(this, targetColumn, DropPosition.AfterDropTarget) : grid._moveColumns(this, targetColumn, DropPosition.BeforeDropTarget);
2320
        }
2321

UNCOV
2322
        if (this.columnGroup) {
×
UNCOV
2323
            this.allChildren.forEach(child => child.pin(null, targetPinPosition));
×
UNCOV
2324
            grid.reinitPinStates();
×
2325
        }
2326

UNCOV
2327
        grid.resetCaches();
×
UNCOV
2328
        grid.notifyChanges();
×
UNCOV
2329
        if (this.columnLayoutChild) {
×
UNCOV
2330
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
×
2331
        }
UNCOV
2332
        this.grid.filteringService.refreshExpressions();
×
UNCOV
2333
        const eventArgs: IPinColumnEventArgs = { column: this, insertAtIndex: index, isPinned: true };
×
UNCOV
2334
        this.grid.columnPinned.emit(eventArgs);
×
UNCOV
2335
        return true;
×
2336
    }
2337
    /**
2338
     * Unpins the column and place it at the provided index in the unpinned area.
2339
     * Defaults to index `0` if not provided, or to the initial index in the unpinned area.
2340
     * Returns `true` if the column is successfully unpinned. Returns `false` if the column cannot be unpinned.
2341
     * Column cannot be unpinned if:
2342
     * - Is already unpinned
2343
     * - index argument is out of range
2344
     * ```typescript
2345
     * let success = this.column.unpin();
2346
     * ```
2347
     *
2348
     * @memberof IgxColumnComponent
2349
     */
2350
    public unpin(index?: number): boolean {
UNCOV
2351
        const grid = (this.grid as any);
×
UNCOV
2352
        if (!this._pinned) {
×
UNCOV
2353
            return false;
×
2354
        }
2355

UNCOV
2356
        if (this.parent && this.parent.pinned) {
×
UNCOV
2357
            return this.topLevelParent.unpin(index);
×
2358
        }
UNCOV
2359
        const hasIndex = index !== undefined && index !== null;
×
UNCOV
2360
        if (hasIndex && (index < 0 || index > grid._unpinnedColumns.length)) {
×
UNCOV
2361
            return false;
×
2362
        }
2363

2364
        // estimate the exact index at which column will be inserted
2365
        // takes into account initial unpinned index of the column
UNCOV
2366
        if (!hasIndex) {
×
UNCOV
2367
            const indices = grid._unpinnedColumns.map(col => col.index);
×
UNCOV
2368
            indices.push(this.index);
×
UNCOV
2369
            indices.sort((a, b) => a - b);
×
UNCOV
2370
            index = indices.indexOf(this.index);
×
2371
        }
2372

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

UNCOV
2376
        if (args.cancel) {
×
2377
            return;
×
2378
        }
2379

UNCOV
2380
        this.grid.crudService.endEdit(false);
×
2381

UNCOV
2382
        this._pinned = false;
×
UNCOV
2383
        this.pinnedChange.emit(this._pinned);
×
2384

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

UNCOV
2389
        if (!hasIndex) {
×
UNCOV
2390
            grid._unpinnedColumns.splice(index, 0, this);
×
UNCOV
2391
            if (grid._pinnedColumns.indexOf(this) !== -1) {
×
UNCOV
2392
                grid._pinnedColumns.splice(grid._pinnedColumns.indexOf(this), 1);
×
2393
            }
UNCOV
2394
            if (this.pinningPosition === ColumnPinningPosition.Start && grid._pinnedStartColumns.indexOf(this) !== -1) {
×
UNCOV
2395
                grid._pinnedStartColumns.splice(grid._pinnedStartColumns.indexOf(this), 1);
×
2396
            }
UNCOV
2397
            if (this.pinningPosition === ColumnPinningPosition.End && grid._pinnedEndColumns.indexOf(this) !== -1) {
×
UNCOV
2398
                grid._pinnedEndColumns.splice(grid._pinnedEndColumns.indexOf(this), 1);
×
2399
            }
2400
        }
2401

UNCOV
2402
        if (hasIndex) {
×
UNCOV
2403
            grid.moveColumn(this, targetColumn);
×
2404
        }
2405

UNCOV
2406
        if (this.columnGroup) {
×
UNCOV
2407
            this.allChildren.forEach(child => child.unpin());
×
2408
        }
2409

UNCOV
2410
        grid.reinitPinStates();
×
UNCOV
2411
        grid.resetCaches();
×
2412

UNCOV
2413
        grid.notifyChanges();
×
UNCOV
2414
        if (this.columnLayoutChild) {
×
UNCOV
2415
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
×
2416
        }
UNCOV
2417
        this.grid.filteringService.refreshExpressions();
×
2418

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

UNCOV
2421
        return true;
×
2422
    }
2423

2424
    /**
2425
     * Moves a column to the specified visible index.
2426
     * If passed index is invalid, or if column would receive a different visible index after moving, moving is not performed.
2427
     * If passed index would move the column to a different column group. moving is not performed.
2428
     *
2429
     * @example
2430
     * ```typescript
2431
     * column.move(index);
2432
     * ```
2433
     * @memberof IgxColumnComponent
2434
     */
2435
    public move(index: number) {
2436
        let target;
UNCOV
2437
        let columns = this.grid.columns.filter(c => c.visibleIndex > -1);
×
2438
        // grid last visible index
UNCOV
2439
        const li = columns.map(c => c.visibleIndex).reduce((a, b) => Math.max(a, b));
×
UNCOV
2440
        const parent = this.parent;
×
UNCOV
2441
        const isPreceding = this.visibleIndex < index;
×
2442

UNCOV
2443
        if (index === this.visibleIndex || index < 0 || index > li) {
×
UNCOV
2444
            return;
×
2445
        }
2446

UNCOV
2447
        if (parent) {
×
UNCOV
2448
            columns = columns.filter(c => c.level >= this.level && c !== this && c.parent !== this &&
×
2449
                c.topLevelParent === this.topLevelParent);
2450
        }
2451

2452
        // 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.
2453
        // 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.
2454

UNCOV
2455
        if (isPreceding) {
×
UNCOV
2456
            columns = columns.filter(c => c.visibleIndex > this.visibleIndex);
×
UNCOV
2457
            target = columns.find(c => c.level === this.level && c.visibleIndex + (c as any).calcChildren() - this.calcChildren() === index);
×
2458
        } else {
UNCOV
2459
            columns = columns.filter(c => c.visibleIndex < this.visibleIndex);
×
UNCOV
2460
            target = columns.find(c => c.level === this.level && c.visibleIndex === index);
×
2461
        }
2462

UNCOV
2463
        if (!target || (target.pinned && this.disablePinning)) {
×
UNCOV
2464
            return;
×
2465
        }
2466

UNCOV
2467
        const pos = isPreceding ? DropPosition.AfterDropTarget : DropPosition.BeforeDropTarget;
×
UNCOV
2468
        this.grid.moveColumn(this, target as IgxColumnComponent, pos);
×
2469
    }
2470

2471
    /**
2472
     * No children for the column, so will returns 1 or 0, if the column is hidden.
2473
     *
2474
     * @hidden
2475
     */
2476
    public calcChildren(): number {
UNCOV
2477
        const children = this.hidden ? 0 : 1;
×
UNCOV
2478
        return children;
×
2479
    }
2480

2481
    /**
2482
     * Toggles column vibisility and emits the respective event.
2483
     *
2484
     * @hidden
2485
     */
2486
    public toggleVisibility(value?: boolean) {
UNCOV
2487
        const newValue = value ?? !this.hidden;
×
UNCOV
2488
        const eventArgs: IColumnVisibilityChangingEventArgs = { column: this, newValue, cancel: false };
×
UNCOV
2489
        this.grid.columnVisibilityChanging.emit(eventArgs);
×
2490

UNCOV
2491
        if (eventArgs.cancel) {
×
2492
            return;
×
2493
        }
UNCOV
2494
        this.hidden = newValue;
×
UNCOV
2495
        this.grid.columnVisibilityChanged.emit({ column: this, newValue });
×
2496
    }
2497

2498
    /**
2499
     * Returns a reference to the top level parent column.
2500
     * ```typescript
2501
     * let topLevelParent =  this.column.topLevelParent;
2502
     * ```
2503
     */
2504
    public get topLevelParent(): ColumnType | undefined {
UNCOV
2505
        let parent = this.parent;
×
UNCOV
2506
        while (parent && parent.parent) {
×
UNCOV
2507
            parent = parent.parent;
×
2508
        }
UNCOV
2509
        return parent ?? undefined;
×
2510
    }
2511

2512
    /**
2513
     * @hidden @internal
2514
     */
2515
    public get headerCell(): IgxGridHeaderComponent {
UNCOV
2516
        return this.grid.headerCellList.find((header) => header.column === this);
×
2517
    }
2518

2519
    /**
2520
     * @hidden @internal
2521
     */
2522
    public get filterCell(): IgxGridFilteringCellComponent {
UNCOV
2523
        return this.grid.filterCellList.find((filterCell) => filterCell.column === this);
×
2524
    }
2525

2526
    /**
2527
     * @hidden @internal
2528
     */
2529
    public get headerGroup(): IgxGridHeaderGroupComponent {
UNCOV
2530
        return this.grid.headerGroupsList.find(group => group.column === this);
×
2531
    }
2532

2533
    /**
2534
     * Autosize the column to the longest currently visible cell value, including the header cell.
2535
     * ```typescript
2536
     * @ViewChild('grid') grid: IgxGridComponent;
2537
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2538
     * column.autosize();
2539
     * ```
2540
     *
2541
     * @memberof IgxColumnComponent
2542
     * @param byHeaderOnly Set if column should be autosized based only on the header content.
2543
     */
2544
    public autosize(byHeaderOnly = false) {
×
UNCOV
2545
        if (!this.columnGroup) {
×
UNCOV
2546
            this.width = this.getAutoSize(byHeaderOnly);
×
UNCOV
2547
            this.grid.reflow();
×
2548
        }
2549
    }
2550

2551
    /**
2552
     * @hidden
2553
     */
2554
    public getAutoSize(byHeader = false): string {
×
UNCOV
2555
        const size = !byHeader ? this.getLargestCellWidth() :
×
UNCOV
2556
            (Object.values(this.getHeaderCellWidths()).reduce((a, b) => a + b) + 'px');
×
UNCOV
2557
        const isPercentageWidth = this.width && typeof this.width === 'string' && this.width.indexOf('%') !== -1;
×
2558

2559
        let newWidth;
UNCOV
2560
        if (isPercentageWidth) {
×
UNCOV
2561
            const gridAvailableSize = this.grid.calcWidth;
×
UNCOV
2562
            const percentageSize = parseFloat(size) / gridAvailableSize * 100;
×
UNCOV
2563
            newWidth = percentageSize + '%';
×
2564
        } else {
UNCOV
2565
            newWidth = size;
×
2566
        }
2567

UNCOV
2568
        const maxWidth = isPercentageWidth ? this.maxWidthPercent : this.maxWidthPx;
×
UNCOV
2569
        const minWidth = isPercentageWidth ? this.minWidthPercent : this.minWidthPx;
×
UNCOV
2570
        if (this.maxWidth && (parseFloat(newWidth) > maxWidth)) {
×
UNCOV
2571
            newWidth = isPercentageWidth ? maxWidth + '%' : maxWidth + 'px';
×
UNCOV
2572
        } else if (parseFloat(newWidth) < minWidth) {
×
UNCOV
2573
            newWidth = isPercentageWidth ? minWidth + '%' : minWidth + 'px';
×
2574
        }
2575

UNCOV
2576
        return newWidth;
×
2577
    }
2578

2579
    /**
2580
     * @hidden
2581
     */
2582
    public getCalcWidth(): any {
UNCOV
2583
        if (this._calcWidth && !isNaN(this.calcPixelWidth)) {
×
UNCOV
2584
            return this._calcWidth;
×
2585
        }
UNCOV
2586
        this.cacheCalcWidth();
×
UNCOV
2587
        return this._calcWidth;
×
2588
    }
2589

2590

2591
    /**
2592
     * @hidden
2593
     * Returns the width and padding of a header cell.
2594
     */
2595
    public getHeaderCellWidths() {
UNCOV
2596
        return this.grid.getHeaderCellWidth(this.headerCell.nativeElement);
×
2597
    }
2598

2599
    /**
2600
     * @hidden
2601
     * Returns the size (in pixels) of the longest currently visible cell, including the header cell.
2602
     * ```typescript
2603
     * @ViewChild('grid') grid: IgxGridComponent;
2604
     *
2605
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2606
     * let size = column.getLargestCellWidth();
2607
     * ```
2608
     * @memberof IgxColumnComponent
2609
     */
2610
    public getLargestCellWidth(): string {
UNCOV
2611
        const range = this.grid.document.createRange();
×
UNCOV
2612
        const largest = new Map<number, number>();
×
2613

UNCOV
2614
        if (this._cells.length > 0) {
×
UNCOV
2615
            const cellsContentWidths = [];
×
UNCOV
2616
            this._cells.forEach((cell) => cellsContentWidths.push(cell.calculateSizeToFit(range)));
×
2617

UNCOV
2618
            const index = cellsContentWidths.indexOf(Math.max(...cellsContentWidths));
×
UNCOV
2619
            const cellStyle = this.grid.document.defaultView.getComputedStyle(this._cells[index].nativeElement);
×
UNCOV
2620
            const cellPadding = parseFloat(cellStyle.paddingLeft) + parseFloat(cellStyle.paddingRight) +
×
2621
                parseFloat(cellStyle.borderLeftWidth) + parseFloat(cellStyle.borderRightWidth);
2622

UNCOV
2623
            largest.set(Math.max(...cellsContentWidths), cellPadding);
×
2624
        }
2625

UNCOV
2626
        if (this.headerCell && this.autosizeHeader) {
×
UNCOV
2627
            const headerCellWidths = this.getHeaderCellWidths();
×
UNCOV
2628
            largest.set(headerCellWidths.width, headerCellWidths.padding);
×
2629
        }
2630

UNCOV
2631
        const largestCell = Math.max(...Array.from(largest.keys()));
×
UNCOV
2632
        const width = Math.ceil(largestCell + largest.get(largestCell));
×
2633

UNCOV
2634
        if (Number.isNaN(width)) {
×
2635
            return this.width;
×
2636
        } else {
UNCOV
2637
            return width + 'px';
×
2638
        }
2639
    }
2640

2641
    /**
2642
     * @hidden
2643
     */
2644
    public getCellWidth() {
UNCOV
2645
        const colWidth = this.width;
×
UNCOV
2646
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
×
2647

UNCOV
2648
        if (this.columnLayoutChild) {
×
2649
            return '';
×
2650
        }
2651

UNCOV
2652
        if (colWidth && !isPercentageWidth) {
×
2653

UNCOV
2654
            let cellWidth = colWidth;
×
UNCOV
2655
            if (typeof cellWidth !== 'string' || cellWidth.endsWith('px') === false) {
×
UNCOV
2656
                cellWidth += 'px';
×
2657
            }
2658

UNCOV
2659
            return cellWidth;
×
2660
        } else {
UNCOV
2661
            return colWidth;
×
2662
        }
2663
    }
2664

2665
    /**
2666
     * @hidden
2667
     */
2668
    public populateVisibleIndexes() { }
2669

2670
    protected getColumnSizesString(children: QueryList<IgxColumnComponent>): string {
UNCOV
2671
        const res = this.getFilledChildColumnSizes(children);
×
UNCOV
2672
        return res.join(' ');
×
2673
    }
2674

2675
    /**
2676
     * @hidden
2677
     * @internal
2678
     */
2679
    public getConstrainedSizePx(newSize) {
UNCOV
2680
        if (this.maxWidth && newSize >= this.maxWidthPx) {
×
UNCOV
2681
            this.widthConstrained = true;
×
UNCOV
2682
            return this.maxWidthPx;
×
UNCOV
2683
        } else if (this.minWidth && newSize <= this.userSetMinWidthPx) {
×
UNCOV
2684
            this.widthConstrained = true;
×
UNCOV
2685
            return this.userSetMinWidthPx;
×
UNCOV
2686
        } else if (!this.columnGroup && !this.minWidth && (!this.widthSetByUser || this.width === 'fit-content') && !this.grid.columnWidthSetByUser && (!newSize || newSize <= this.grid.minColumnWidth)) {
×
UNCOV
2687
            return this.grid.minColumnWidth;
×
2688
        } else {
UNCOV
2689
            this.widthConstrained = false;
×
UNCOV
2690
            return newSize;
×
2691
        }
2692
    }
2693

2694
    /**
2695
     * @hidden
2696
     * @internal
2697
     */
2698
    protected cacheCalcWidth(): any {
UNCOV
2699
        const colWidth = this.width;
×
UNCOV
2700
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
×
UNCOV
2701
        const isAutoWidth = colWidth && typeof colWidth === 'string' && colWidth === 'fit-content';
×
UNCOV
2702
        if (isPercentageWidth && this.grid.isColumnWidthSum) {
×
UNCOV
2703
            this._calcWidth = this.userSetMinWidthPx ? this.userSetMinWidthPx : this.grid.minColumnWidth;
×
UNCOV
2704
        } else if (isPercentageWidth) {
×
UNCOV
2705
            const currentCalcWidth = parseFloat(colWidth) / 100 * this.grid.calcWidth;
×
UNCOV
2706
            this._calcWidth = this.grid.calcWidth ? this.getConstrainedSizePx(currentCalcWidth) : 0;
×
UNCOV
2707
        } else if (!colWidth || isAutoWidth && !this.autoSize) {
×
2708
            // no width
UNCOV
2709
            const currentCalcWidth = this.defaultWidth || this.grid.getPossibleColumnWidth();
×
UNCOV
2710
            this._calcWidth = this.getConstrainedSizePx(parseFloat(currentCalcWidth));
×
2711
        } else {
UNCOV
2712
            let possibleColumnWidth = '';
×
UNCOV
2713
            if (!this.widthSetByUser && this.userSetMinWidthPx && this.userSetMinWidthPx < this.grid.minColumnWidth) {
×
UNCOV
2714
                possibleColumnWidth = this.defaultWidth = this.grid.getPossibleColumnWidth();
×
2715
            } else {
UNCOV
2716
                possibleColumnWidth = this.width;
×
2717
            }
2718

UNCOV
2719
            const currentCalcWidth = parseFloat(possibleColumnWidth);
×
UNCOV
2720
            this._calcWidth = this.getConstrainedSizePx(currentCalcWidth);
×
2721
        }
UNCOV
2722
        this.calcPixelWidth = parseFloat(this._calcWidth);
×
2723
    }
2724

2725
    /**
2726
     * @hidden
2727
     * @internal
2728
     */
2729
    protected setExpandCollapseState() {
UNCOV
2730
        this.children.filter(col => (col.visibleWhenCollapsed !== undefined)).forEach(c => {
×
UNCOV
2731
            if (!this.collapsible) {
×
UNCOV
2732
                c.hidden = this.hidden; return;
×
2733
            }
UNCOV
2734
            c.hidden = this._expanded ? c.visibleWhenCollapsed : !c.visibleWhenCollapsed;
×
2735
        });
2736
    }
2737
    /**
2738
     * @hidden
2739
     * @internal
2740
     */
2741
    protected checkCollapsibleState() {
UNCOV
2742
        if (!this.children) {
×
2743
            return false;
×
2744
        }
UNCOV
2745
        const cols = this.children.map(child => child.visibleWhenCollapsed);
×
UNCOV
2746
        return (cols.some(c => c === true) && cols.some(c => c === false));
×
2747
    }
2748

2749
    /**
2750
     * @hidden
2751
     */
2752
    public get pinnable() {
UNCOV
2753
        return (this.grid as any)._init || !this.pinned;
×
2754
    }
2755

2756
    /**
2757
     * @hidden
2758
     */
2759
    public get applySelectableClass(): boolean {
UNCOV
2760
        return this._applySelectableClass;
×
2761
    }
2762

2763
    /**
2764
     * @hidden
2765
     */
2766
    public set applySelectableClass(value: boolean) {
UNCOV
2767
        if (this.selectable) {
×
UNCOV
2768
            this._applySelectableClass = value;
×
2769
        }
2770
    }
2771
}
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