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

IgniteUI / igniteui-angular / 6457997058

09 Oct 2023 02:26PM CUT coverage: 92.261% (+0.001%) from 92.26%
6457997058

push

github

web-flow
fix(grids): refactor cell width - 16.0.x (#13501)

15310 of 17990 branches covered (0.0%)

1 of 1 new or added line in 1 file covered. (100.0%)

26848 of 29100 relevant lines covered (92.26%)

29627.7 hits per line

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

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

3,251✔
59
const DEFAULT_DATE_FORMAT = 'mediumDate';
60
const DEFAULT_TIME_FORMAT = 'mediumTime';
61
const DEFAULT_DATE_TIME_FORMAT = 'medium';
62
const DEFAULT_DIGITS_INFO = '1.0-3';
63

1,806,760✔
64
/**
1,806,760✔
65
 * **Ignite UI for Angular Column** -
1,806,760✔
66
 * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid#columns-configuration)
74,578✔
67
 *
68
 * The Ignite UI Column is used within an `igx-grid` element to define what data the column will show. Features such as sorting,
1,732,182✔
69
 * filtering & editing are enabled at the column level.  You can also provide a template containing custom content inside
251,266✔
70
 * the column using `ng-template` which will be used for all cells within the column.
71
 */
72
@Component({
1,480,916✔
73
    changeDetection: ChangeDetectionStrategy.OnPush,
74
    selector: 'igx-column',
75
    template: ``,
76
    standalone: true
77
})
78
export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnType {
79
    /**
80
     * Sets/gets the `field` value.
81
     * ```typescript
82
     * let columnField = this.column.field;
83
     * ```
84
     * ```html
85
     * <igx-column [field] = "'ID'"></igx-column>
86
     * ```
87
     *
4,231✔
88
     * @memberof IgxColumnComponent
89
     */
90
    @Input()
1,840,593✔
91
    public set field(value: string) {
92
        this._field = value;
93
        this.hasNestedPath = value?.includes('.');
94
    }
95
    public get field(): string {
96
        return this._field;
97
    }
98

99

100
    /**
101
     * @hidden @internal
102
     */
3,161✔
103
    public validators: Validator[] = [];
3,161!
104

3,161✔
105
    /**
106
     * Sets/gets the `header` value.
107
     * ```typescript
108
     * let columnHeader = this.column.header;
1,158,716✔
109
     * ```
110
     * ```html
111
     * <igx-column [header] = "'ID'"></igx-column>
112
     * ```
113
     *
114
     * @memberof IgxColumnComponent
115
     */
116
    @notifyChanges()
117
    @WatchColumnChanges()
118
    @Input()
119
    public header = '';
120
    /**
121
     * Sets/gets the `title` value.
122
     * ```typescript
123
     * let title = this.column.title;
124
     * ```
125
     * ```html
5,489✔
126
     * <igx-column [title] = "'Some column tooltip'"></igx-column>
1,216✔
127
     * ```
1,216✔
128
     *
1,216✔
129
     * @memberof IgxColumnComponent
5✔
130
     */
5✔
131
    @notifyChanges()
132
    @WatchColumnChanges()
1,211!
133
    @Input()
1,211✔
134
    public title = '';
1,211✔
135
    /**
1,211✔
136
     * Sets/gets whether the column is sortable.
1,211✔
137
     * Default value is `false`.
1,211✔
138
     * ```typescript
139
     * let isSortable = this.column.sortable;
140
     * ```
141
     * ```html
142
     * <igx-column [sortable] = "true"></igx-column>
143
     * ```
144
     *
145
     * @memberof IgxColumnComponent
146
     */
147
    @WatchColumnChanges()
148
    @Input()
149
    public sortable = false;
150
    /**
1,290,509✔
151
     * Returns if the column is selectable.
152
     * ```typescript
153
     * let columnSelectable = this.column.selectable;
154
     * ```
155
     *
156
     * @memberof IgxColumnComponent
157
     */
158
    @WatchColumnChanges()
159
    @Input()
160
    public get selectable(): boolean {
161
        return this._selectable;
162
    }
46✔
163

42✔
164
    /**
37✔
165
     * Sets if the column is selectable.
166
     * Default value is `true`.
167
     * ```html
5✔
168
     * <igx-column [selectable] = "false"></igx-column>
169
     * ```
42✔
170
     *
171
     * @memberof IgxColumnComponent
172
     */
173
    public set selectable(value: boolean) {
1,770,620✔
174
        this._selectable = value;
1,770,620✔
175
    }
17,472✔
176

9,518✔
177
    /**
178
     * Sets/gets whether the column is groupable.
179
     * Default value is `false`.
7,954✔
180
     * ```typescript
181
     * let isGroupable = this.column.groupable;
182
     * ```
1,753,148✔
183
     * ```html
184
     * <igx-column [groupable] = "true"></igx-column>
185
     * ```
186
     *
187
     * @memberof IgxColumnComponent
188
     */
189
    @notifyChanges(true)
190
    @WatchColumnChanges()
191
    @Input()
192
    public get groupable(): boolean {
193
        return this._groupable;
194
    }
195
    public set groupable(value: boolean) {
196
        this._groupable = value;
197
        this.grid.groupablePipeTrigger++;
198
    }
13,992✔
199
    /**
12,185✔
200
     * Gets whether the column is editable.
12,185✔
201
     * Default value is `false`.
12,185✔
202
     * ```typescript
203
     * let isEditable = this.column.editable;
204
     * ```
12,185✔
205
     *
877✔
206
     * @memberof IgxColumnComponent
207
     */
12,185!
208
    @WatchColumnChanges()
×
209
    @Input()
210
    public get editable(): boolean {
12,185✔
211
        // Updating the primary key when grid has transactions (incl. row edit)
12,185!
212
        // should not be allowed, as that can corrupt transaction state.
12,185✔
213
        const rowEditable = this.grid && this.grid.rowEditable;
214
        const hasTransactions = this.grid && this.grid.transactions.enabled;
12,185✔
215

216
        if (this.isPrimaryColumn && (rowEditable || hasTransactions)) {
217
            return false;
218
        }
219

220
        if (this._editable !== undefined) {
221
            return this._editable;
296,309✔
222
        } else {
223
            return rowEditable;
224
        }
225
    }
226
    /**
227
     * Sets whether the column is editable.
65,894✔
228
     * ```typescript
65,894✔
229
     * this.column.editable = true;
65,894✔
230
     * ```
231
     * ```html
232
     * <igx-column [editable] = "true"></igx-column>
233
     * ```
234
     *
235
     * @memberof IgxColumnComponent
17✔
236
     */
17✔
237
    public set editable(editable: boolean) {
17✔
238
        this._editable = editable;
239
    }
240
    /**
241
     * Sets/gets whether the column is filterable.
242
     * Default value is `true`.
243
     * ```typescript
65,999✔
244
     * let isFilterable = this.column.filterable;
65,999✔
245
     * ```
65,999✔
246
     * ```html
247
     * <igx-column [filterable] = "false"></igx-column>
248
     * ```
249
     *
250
     * @memberof IgxColumnComponent
251
     */
17✔
252
    @notifyChanges()
17✔
253
    @WatchColumnChanges()
17✔
254
    @Input()
255
    public filterable = true;
256
    /**
1,376✔
257
     * Sets/gets whether the column is resizable.
1,376✔
258
     * Default value is `false`.
45✔
259
     * ```typescript
260
     * let isResizable = this.column.resizable;
1,331✔
261
     * ```
262
     * ```html
263
     * <igx-column [resizable] = "true"></igx-column>
268,012✔
264
     * ```
265
     *
266
     * @memberof IgxColumnComponent
267
     */
3,075,861!
268
    @WatchColumnChanges()
×
269
    @Input()
270
    public resizable = false;
3,075,861✔
271

3,075,861✔
272
    /**
273
     * Sets/gets whether the column header is included in autosize logic.
274
     * Useful when template for a column header is sized based on parent, for example a default `div`.
275
     * Default value is `false`.
276
     * ```typescript
277
     * let isResizable = this.column.resizable;
278
     * ```
279
     * ```html
280
     * <igx-column [resizable] = "true"></igx-column>
281
     * ```
282
     *
194,773✔
283
     * @memberof IgxColumnComponent
284
     */
285
    @WatchColumnChanges()
1,796,040✔
286
    @Input()
287
    public autosizeHeader = true;
288

289
    /**
290
     * Gets a value indicating whether the summary for the column is enabled.
291
     * ```typescript
292
     * let hasSummary = this.column.hasSummary;
293
     * ```
294
     *
295
     * @memberof IgxColumnComponent
296
     */
297
    @notifyChanges(true)
298
    @WatchColumnChanges()
299
    @Input()
300
    public get hasSummary() {
301
        return this._hasSummary;
302
    }
2,465✔
303
    /**
848✔
304
     * Sets a value indicating whether the summary for the column is enabled.
848✔
305
     * Default value is `false`.
613✔
306
     * ```html
420✔
307
     * <igx-column [hasSummary] = "true"></igx-column>
308
     * ```
309
     *
193✔
310
     * @memberof IgxColumnComponent
311
     */
613✔
312
    public set hasSummary(value) {
313
        this._hasSummary = value;
314

315
        if (this.grid) {
316
            this.grid.summaryService.resetSummaryHeight();
235✔
317
        }
235✔
318
    }
319
    /**
320
     * Gets whether the column is hidden.
321
     * ```typescript
55,813✔
322
     * let isHidden = this.column.hidden;
323
     * ```
324
     *
325
     * @memberof IgxColumnComponent
326
     */
327
    @notifyChanges(true)
328
    @WatchColumnChanges()
329
    @Input()
330
    public get hidden(): boolean {
331
        return this._hidden;
332
    }
22,882✔
333
    /**
22,876✔
334
     * Sets the column hidden property.
335
     * Default value is `false`.
22,882!
336
     * ```html
22,882✔
337
     * <igx-column [hidden] = "true"></igx-column>
22,882✔
338
     * ```
22,882✔
339
     *
340
     * Two-way data binding.
341
     * ```html
342
     * <igx-column [(hidden)] = "model.isHidden"></igx-column>
87,439✔
343
     * ```
344
     *
345
     * @memberof IgxColumnComponent
346
     */
347
    public set hidden(value: boolean) {
348
        if (this._hidden !== value) {
349
            this._hidden = value;
350
            this.hiddenChange.emit(this._hidden);
351
            if (this.columnLayoutChild && this.parent.hidden !== value) {
352
                this.parent.hidden = value;
353
                return;
22,869✔
354
            }
355
            if (this.grid) {
356
                this.grid.crudService.endEdit(false);
2,642✔
357
                this.grid.summaryService.resetSummaryHeight();
358
                this.grid.filteringService.refreshExpressions();
359
                this.grid.filteringService.hideFilteringRowOnColumnVisibilityChange(this);
360
                this.grid.notifyChanges();
361
            }
362
        }
363
    }
364

365
    /**
366
     * Returns if the column is selected.
367
     * ```typescript
368
     * let isSelected = this.column.selected;
1,309✔
369
     * ```
370
     *
371
     * @memberof IgxColumnComponent
3,069✔
372
     */
373
    public get selected(): boolean {
374
        return this.grid.selectionService.isColumnSelected(this.field);
375
    }
376

377
    /**
378
     * Select/deselect a column.
379
     * Default value is `false`.
380
     * ```typescript
381
     * this.column.selected = true;
382
     * ```
383
     *
1,311✔
384
     * @memberof IgxColumnComponent
385
     */
386
    public set selected(value: boolean) {
387
        if (this.selectable && value !== this.selected) {
388
            if (value) {
389
                this.grid.selectionService.selectColumnsWithNoEvent([this.field]);
390
            } else {
391
                this.grid.selectionService.deselectColumnsWithNoEvent([this.field]);
392
            }
393
            this.grid.notifyChanges();
394
        }
249,076!
395
    }
×
396

397
    /**
249,076✔
398
     * @hidden
399
     */
717✔
400
    @Output()
401
    public hiddenChange = new EventEmitter<boolean>();
1,057✔
402

403
    /** @hidden */
247,302✔
404
    @Output()
405
    public expandedChange = new EventEmitter<boolean>();
406

407
    /** @hidden */
63,184✔
408
    @Output()
409
    public collapsibleChange = new EventEmitter<boolean>();
410
    /** @hidden */
411
    @Output()
412
    public visibleWhenCollapsedChange = new EventEmitter<boolean>();
413

414
    /** @hidden */
415
    @Output()
416
    public columnChange = new EventEmitter<void>();
417

418
    /**
419
     * Gets whether the hiding is disabled.
420
     * ```typescript
421
     * let isHidingDisabled =  this.column.disableHiding;
422
     * ```
423
     *
424
     * @memberof IgxColumnComponent
425
     */
426
    @notifyChanges()
1,314✔
427
    @WatchColumnChanges()
428
    @Input()
429
    public disableHiding = false;
902,651✔
430
    /**
431
     * Gets whether the pinning is disabled.
432
     * ```typescript
433
     * let isPinningDisabled =  this.column.disablePinning;
434
     * ```
435
     *
436
     * @memberof IgxColumnComponent
437
     */
438
    @notifyChanges()
439
    @WatchColumnChanges()
440
    @Input()
441
    public disablePinning = false;
442
    /**
443
     * @deprecated in version 13.1.0. Use `IgxGridComponent.moving` instead.
444
     *
445
     * Sets/gets whether the column is movable.
446
     * Default value is `false`.
447
     *
448
     * ```typescript
449
     * let isMovable = this.column.movable;
1,277✔
450
     * ```
451
     * ```html
452
     * <igx-column [movable] = "true"></igx-column>
206,424✔
453
     * ```
454
     *
455
     * @memberof IgxColumnComponent
456
     */
457
    @Input()
458
    public movable = false;
459
    /**
460
     * Gets the `width` of the column.
461
     * ```typescript
462
     * let columnWidth = this.column.width;
463
     * ```
464
     *
465
     * @memberof IgxColumnComponent
466
     */
467
    @notifyChanges(true)
468
    @WatchColumnChanges()
469
    @Input()
470
    public get width(): string {
471
        const isAutoWidth = this._width && typeof this._width === 'string' && this._width === 'auto';
472
        if (isAutoWidth) {
473
            if (!this.autoSize) {
3,429✔
474
                return 'fit-content';
475
            } else {
476
                return this.autoSize + 'px';
5,055✔
477
            }
478

479
        }
480
        return this.widthSetByUser ? this._width : this.defaultWidth;
481
    }
482

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

517
    /** @hidden @internal **/
518
    public autoSize: number;
32,165✔
519

520
    /**
521
     * Sets/gets the maximum `width` of the column.
522
     * ```typescript
523
     * let columnMaxWidth = this.column.width;
524
     * ```
525
     * ```html
526
     * <igx-column [maxWidth] = "'150px'"></igx-column>
527
     * ```
528
     *
529
     * @memberof IgxColumnComponent
530
     */
531
    @WatchColumnChanges()
532
    @Input()
533
    public maxWidth: string;
534

535
    /**
536
     * Sets/gets the class selector of the column header.
1,316✔
537
     * ```typescript
538
     * let columnHeaderClass = this.column.headerClasses;
539
     * ```
540
     * ```html
541
     * <igx-column [headerClasses] = "'column-header'"></igx-column>
542
     * ```
543
     *
544
     * @memberof IgxColumnComponent
545
     */
546
    @notifyChanges()
23✔
547
    @WatchColumnChanges()
548
    @Input()
1,273!
549
    public headerClasses = '';
1,273!
550

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

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

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

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

631
    /**
632
     * Sets conditional style properties on the column cells.
633
     * Similar to `ngStyle` it accepts an object literal where the keys are
634
     * the style properties and the value is the expression to be evaluated.
635
     * As with `cellClasses` it accepts a callback function.
636
     * ```typescript
637
     * styles = {
638
     *  background: 'royalblue',
12,707,525✔
639
     *  color: (rowData, columnKey, cellValue, rowIndex) => value.startsWith('Important') ? 'red': 'inherit'
640
     * }
641
     * ```
642
     * ```html
358✔
643
     * <igx-column [cellStyles]="styles"></igx-column>
644
     * ```
645
     *
646
     * @memberof IgxColumnComponent
647
     */
648
    @notifyChanges()
649
    @WatchColumnChanges()
650
    @Input()
651
    public cellStyles = null;
652
    /**
653
     * Applies display format to cell values in the column. Does not modify the underlying data.
654
     *
533,462✔
655
     * @remark
533,462✔
656
     * Note: As the formatter is used in places like the Excel style filtering dialog, in certain
533,462✔
657
     * scenarios (remote filtering for example), the row data argument can be `undefined`.
176,372✔
658
     *
176,372✔
659
     *
660
     * In this example, we check to see if the column name is Salary, and then provide a method as the column formatter
533,462✔
661
     * to format the value into a currency string.
662
     *
663
     * @example
664
     * ```typescript
815,498✔
665
     * columnInit(column: IgxColumnComponent) {
666
     *   if (column.field == "Salary") {
667
     *     column.formatter = (salary => this.format(salary));
668
     *   }
669
     * }
748,863✔
670
     *
748,863✔
671
     * format(value: number) : string {
672
     *   return formatCurrency(value, "en-us", "$");
673
     * }
674
     * ```
522,403✔
675
     *
676
     * @example
677
     * ```typescript
678
     * const column = this.grid.getColumnByName('Address');
679
     * const addressFormatter = (address: string, rowData: any) => data.privacyEnabled ? 'unknown' : address;
1,277✔
680
     * column.formatter = addressFormatter;
681
     * ```
682
     *
590,718✔
683
     * @memberof IgxColumnComponent
684
     */
685
    @notifyChanges()
1,619✔
686
    @WatchColumnChanges()
1,619✔
687
    @Input()
1,619✔
688
    public formatter: (value: any, rowData?: any) => any;
19✔
689

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

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

26,969✔
781
    /** @hidden */
782
    @Input()
783
    public collapsibleIndicatorTemplate: TemplateRef<IgxColumnTemplateContext>;
784

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

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

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

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

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

855
    /**
856
     * @hidden
857
     */
858
    @Output()
859
    public widthChange = new EventEmitter<string>();
267,639✔
860

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

1,732✔
909
    /** @hidden @internal **/
910
    public calcPixelWidth: number;
217✔
911

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

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

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

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

948

949
    /**
950
     * Sets/gets the minimum `width` of the column.
951
     * Default value is `88`;
952
     * ```typescript
21,416✔
953
     * let columnMinWidth = this.column.minWidth;
10,709!
954
     * ```
10,709✔
955
     * ```html
956
     * <igx-column [minWidth] = "'100px'"></igx-column>
957
     * ```
10,707✔
958
     *
959
     * @memberof IgxColumnComponent
960
     */
961
    @notifyChanges()
962
    @WatchColumnChanges()
134,813✔
963
    @Input()
964
    public set minWidth(value: string) {
134,813✔
965
        const minVal = parseFloat(value);
417,128✔
966
        if (Number.isNaN(minVal)) {
111,984✔
967
            return;
968
        }
305,144✔
969
        this._defaultMinWidth = value;
305,144✔
970

305,144✔
971
    }
305,144✔
972
    public get minWidth(): string {
305,144✔
973
        return !this._defaultMinWidth ? this.defaultMinWidth : this._defaultMinWidth;
974
    }
975

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

118,245✔
985
    /**
986
     * Gets the column index.
987
     * ```typescript
988
     * let columnIndex = this.column.index;
989
     * ```
990
     *
43,190✔
991
     * @memberof IgxColumnComponent
992
     */
993
    public get index(): number {
994
        return (this.grid as any)._columns.indexOf(this);
4,187✔
995
    }
2,425✔
996

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

1043
    /**
1044
     * Gets the column `summaries`.
1045
     * ```typescript
1046
     * let columnSummaries = this.column.summaries;
4,260✔
1047
     * ```
1048
     *
1049
     * @memberof IgxColumnComponent
5,634✔
1050
     */
1051
    @notifyChanges(true)
1052
    @WatchColumnChanges()
5,634✔
1053
    @Input()
1054
    public get summaries(): any {
1055
        return this._summaries;
1056
    }
1057
    /**
1058
     * Sets the column `summaries`.
1059
     * ```typescript
1060
     * this.column.summaries = IgxNumberSummaryOperand;
1061
     * ```
1062
     *
10,254✔
1063
     * @memberof IgxColumnComponent
1064
     */
1065
    public set summaries(classRef: any) {
10,254✔
1066
        if (isConstructor(classRef)) {
1067
            this._summaries = new classRef();
10,254✔
1068
        }
1069

1070
        if (this.grid) {
134,813✔
1071
            this.grid.summaryService.removeSummariesCachePerColumn(this.field);
1072
            this.grid.summaryPipeTrigger++;
1073
            this.grid.summaryService.resetSummaryHeight();
1074
        }
22,467✔
1075
    }
1076
    /**
22,467✔
1077
     * Gets the column `filters`.
22,467✔
1078
     * ```typescript
49,730✔
1079
     * let columnFilters = this.column.filters'
20,569✔
1080
     * ```
1081
     *
1082
     * @memberof IgxColumnComponent
29,161✔
1083
     */
1084
    @Input()
1085
    public get filters(): IgxFilteringOperand {
22,467✔
1086
        return this._filters;
1087
    }
1088
    /**
1089
     * Sets the column `filters`.
6!
1090
     * ```typescript
×
1091
     * this.column.filters = IgxBooleanFilteringOperand.instance().
1092
     * ```
6✔
1093
     *
6✔
1094
     * @memberof IgxColumnComponent
6!
1095
     */
6✔
1096
    public set filters(instance: IgxFilteringOperand) {
36✔
1097
        this._filters = instance;
10✔
1098
    }
1099
    /**
1100
     * Gets the column `sortStrategy`.
6✔
1101
     * ```typescript
6✔
1102
     * let sortStrategy = this.column.sortStrategy
10!
1103
     * ```
×
1104
     *
1105
     * @memberof IgxColumnComponent
1106
     */
10✔
1107
    @Input()
1108
    public get sortStrategy(): ISortingStrategy {
1109
        return this._sortStrategy;
6✔
1110
    }
1111
    /**
1112
     * Sets the column `sortStrategy`.
1113
     * ```typescript
1114
     * this.column.sortStrategy = new CustomSortingStrategy().
1115
     * class CustomSortingStrategy extends SortingStrategy {...}
1116
     * ```
1117
     *
1118
     * @memberof IgxColumnComponent
1119
     */
1120
    public set sortStrategy(classRef: ISortingStrategy) {
1121
        this._sortStrategy = classRef;
1122
    }
1123
    /**
1124
     * Gets the function that compares values for grouping.
1125
     * ```typescript
1126
     * let groupingComparer = this.column.groupingComparer'
1127
     * ```
1128
     *
674✔
1129
     * @memberof IgxColumnComponent
674✔
1130
     */
56✔
1131
    @Input()
1132
    public get groupingComparer(): (a: any, b: any, currRec?: any, groupRec?: any) => number {
618✔
1133
        return this._groupingComparer;
10✔
1134
    }
1135
    /**
608✔
1136
     * Sets a custom function to compare values for grouping.
608✔
1137
     * Subsequent values in the sorted data that the function returns 0 for are grouped.
2✔
1138
     * ```typescript
1139
     * this.column.groupingComparer = (a: any, b: any, currRec?: any, groupRec?: any) => { return a === b ? 0 : -1; }
606!
1140
     * ```
×
1141
     *
1142
     * @memberof IgxColumnComponent
1,502✔
1143
     */
606✔
1144
    public set groupingComparer(funcRef: (a: any, b: any, currRec?: any, groupRec?: any) => number) {
606✔
1145
        this._groupingComparer = funcRef;
606✔
1146
    }
606!
1147
    /**
×
1148
     * Gets the default minimum `width` of the column.
1149
     * ```typescript
606✔
1150
     * let defaultMinWidth =  this.column.defaultMinWidth;
606✔
1151
     * ```
606✔
1152
     *
1153
     * @memberof IgxColumnComponent
606✔
1154
     */
1155
    public get defaultMinWidth(): string {
606✔
1156
        if (!this.grid) {
413✔
1157
            return '80';
339✔
1158
        }
1159
        switch (this.grid.displayDensity) {
1160
            case DisplayDensity.cosy:
1161
                return '64';
74✔
1162
            case DisplayDensity.compact:
74✔
1163
                return '56';
1164
            default:
74✔
1165
                return '80';
138✔
1166
        }
138✔
1167
    }
1168
    /**
74✔
1169
     * Returns a reference to the `summaryTemplate`.
1170
     * ```typescript
413✔
1171
     * let summaryTemplate = this.column.summaryTemplate;
206✔
1172
     * ```
206✔
1173
     *
1174
     * @memberof IgxColumnComponent
1175
     */
606✔
1176
    @notifyChanges()
10✔
1177
    @WatchColumnChanges()
1178
    @Input()
1179
    public get summaryTemplate(): TemplateRef<IgxSummaryTemplateContext> {
606✔
1180
        return this._summaryTemplate;
182✔
1181
    }
58✔
1182
    /**
1183
     * Sets the summary template.
606✔
1184
     * ```html
606✔
1185
     * <ng-template #summaryTemplate igxSummary let-summaryResults>
606✔
1186
     *    <p>{{ summaryResults[0].label }}: {{ summaryResults[0].summaryResult }}</p>
1,379✔
1187
     *    <p>{{ summaryResults[1].label }}: {{ summaryResults[1].summaryResult }}</p>
1188
     * </ng-template>
606✔
1189
     * ```
606✔
1190
     * ```typescript
606✔
1191
     * @ViewChild("'summaryTemplate'", {read: TemplateRef })
606✔
1192
     * public summaryTemplate: TemplateRef<any>;
1193
     * this.column.summaryTemplate = this.summaryTemplate;
1194
     * ```
1195
     *
1196
     * @memberof IgxColumnComponent
1197
     */
1198
    public set summaryTemplate(template: TemplateRef<IgxSummaryTemplateContext>) {
1199
        this._summaryTemplate = template;
1200
    }
1201

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

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

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

1368
    /**
1369
     * Gets the cells of the column.
1370
     * ```typescript
1371
     * let columnCells = this.column.cells;
9,887✔
1372
     * ```
1373
     *
1374
     */
1375
    public get cells(): CellType[] {
1376
        return this.grid.dataView
1377
            .map((rec, index) => {
1378
                if (!this.grid.isGroupByRecord(rec) && !this.grid.isSummaryRow(rec)) {
1379
                    this.grid.pagingMode === 1 && this.grid.page !== 0 ? index = index + this.grid.perPage * this.grid.page : index = this.grid.dataRowList.first.index + index;
1380
                    const cell = new IgxGridCell(this.grid as any, index, this);
1381
                    return cell;
1382
                }
1383
            }).filter(cell => cell);
1384
    }
17✔
1385

18!
1386

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

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

1418
        if (this.columnGroup) {
1419
            col = this.allChildren.filter(c => !c.columnGroup && !c.hidden)[0] as any;
1420
        }
296,309✔
1421
        if (this.columnLayoutChild) {
285,110✔
1422
            return this.parent.childrenVisibleIndexes.find(x => x.column === this).index;
1423
        }
11,199✔
1424

11,199✔
1425
        if (!this.pinned) {
1426
            const indexInCollection = unpinnedColumns.indexOf(col);
1427
            vIndex = indexInCollection === -1 ?
1428
                -1 :
1429
                (this.grid.isPinningToStart ?
1430
                    pinnedColumns.length + indexInCollection :
1431
                    indexInCollection);
25✔
1432
        } else {
1433
            const indexInCollection = pinnedColumns.indexOf(col);
1434
            vIndex = this.grid.isPinningToStart ?
1435
                indexInCollection :
1436
                unpinnedColumns.length + indexInCollection;
1437
        }
1438
        this._vIndex = vIndex;
1439
        return vIndex;
1440
    }
1441

1442
    /**
1443
     * Returns a boolean indicating if the column is a `ColumnGroup`.
1444
     * ```typescript
1445
     * let columnGroup =  this.column.columnGroup;
25✔
1446
     * ```
25✔
1447
     *
25!
1448
     * @memberof IgxColumnComponent
25✔
1449
     */
270✔
1450
    public get columnGroup() {
25✔
1451
        return false;
25✔
1452
    }
25✔
1453
    /**
1454
     * Returns a boolean indicating if the column is a `ColumnLayout` for multi-row layout.
25✔
1455
     * ```typescript
1456
     * let columnGroup =  this.column.columnGroup;
25✔
1457
     * ```
24✔
1458
     *
24✔
1459
     * @memberof IgxColumnComponent
1460
     */
25✔
1461
    public get columnLayout() {
25✔
1462
        return false;
25!
1463
    }
×
1464

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

×
1477
    /** @hidden @internal **/
1478
    public get allChildren(): IgxColumnComponent[] {
869,147✔
1479
        return [];
861,306✔
1480
    }
861,306✔
1481
    /**
1,877✔
1482
     * Returns the level of the column in a column group.
1483
     * Returns `0` if the column doesn't have a `parent`.
861,306✔
1484
     * ```typescript
1485
     * let columnLevel =  this.column.level;
1486
     * ```
7,841✔
1487
     *
1488
     * @memberof IgxColumnComponent
1489
     */
1490
    public get level() {
1491
        let ptr = this.parent;
1492
        let lvl = 0;
1493

1494
        while (ptr) {
10,707✔
1495
            lvl++;
10,707✔
1496
            ptr = ptr.parent;
1497
        }
1498
        return lvl;
1499
    }
1500

1501
    /** @hidden @internal **/
1502
    public get isLastPinned(): boolean {
291,023✔
1503
        return this.grid.isPinningToStart &&
291,023✔
1504
            this.grid.pinnedColumns[this.grid.pinnedColumns.length - 1] === this;
291,023✔
1505
    }
291,023✔
1506

846✔
1507
    /** @hidden @internal **/
1508
    public get isFirstPinned(): boolean {
290,177✔
1509
        const pinnedCols = this.grid.pinnedColumns.filter(x => !x.columnGroup);
1510
        return !this.grid.isPinningToStart && pinnedCols[0] === this;
29,352✔
1511
    }
1512

1513
    /** @hidden @internal **/
260,825✔
1514
    public get rightPinnedOffset(): string {
1515
        return this.pinned && !this.grid.isPinningToStart ?
291,023✔
1516
            - this.grid.pinnedWidth - this.grid.headerFeaturesWidth + 'px' :
1517
            null;
1518
    }
1519

1520
    public get gridRowSpan(): number {
1521
        return this.rowEnd && this.rowStart ? this.rowEnd - this.rowStart : 1;
1522
    }
245✔
1523
    public get gridColumnSpan(): number {
226✔
1524
        return this.colEnd && this.colStart ? this.colEnd - this.colStart : 1;
1✔
1525
    }
1✔
1526

1527
    /**
225✔
1528
     * Indicates whether the column will be visible when its parent is collapsed.
1529
     * ```html
1530
     * <igx-column-group>
1531
     *   <igx-column [visibleWhenCollapsed]="true"></igx-column>
1532
     * </igx-column-group>
1533
     * ```
1534
     *
1535
     * @memberof IgxColumnComponent
2,069!
1536
     */
×
1537
    @notifyChanges(true)
1538
    @Input()
5,014✔
1539
    public set visibleWhenCollapsed(value: boolean) {
3,135✔
1540
        this._visibleWhenCollapsed = value;
1541
        this.visibleWhenCollapsedChange.emit(this._visibleWhenCollapsed);
1542
        if (this.parent) {
1543
            this.parent.setExpandCollapseState();
1544
        }
1545
    }
380✔
1546

1547
    public get visibleWhenCollapsed(): boolean {
1548
        return this._visibleWhenCollapsed;
1549
    }
1550

1551
    /**
8,344✔
1552
     * @remarks
1553
     * Pass optional parameters for DatePipe and/or DecimalPipe to format the display value for date and numeric columns.
1554
     * Accepts an `IColumnPipeArgs` object with any of the `format`, `timezone` and `digitsInfo` properties.
1555
     * For more details see https://angular.io/api/common/DatePipe and https://angular.io/api/common/DecimalPipe
1556
     * @example
1557
     * ```typescript
440✔
1558
     * const pipeArgs: IColumnPipeArgs = {
438✔
1559
     *      format: 'longDate',
1560
     *      timezone: 'UTC',
1561
     *      digitsInfo: '1.1-2'
6✔
1562
     * }
1563
     * ```
1564
     * ```html
1565
     * <igx-column dataType="date" [pipeArgs]="pipeArgs"></igx-column>
1566
     * <igx-column dataType="number" [pipeArgs]="pipeArgs"></igx-column>
1567
     * ```
2✔
1568
     * @memberof IgxColumnComponent
1569
     */
1570
    @notifyChanges()
1571
    @WatchColumnChanges()
1572
    @Input()
1573
    public set pipeArgs(value: IColumnPipeArgs) {
1574
        this._columnPipeArgs = Object.assign(this._columnPipeArgs, value);
1575
        this.grid.summaryService.clearSummaryCache();
1576
        this.grid.pipeTrigger++;
1577
    }
1578
    public get pipeArgs(): IColumnPipeArgs {
1579
        return this._columnPipeArgs;
1580
    }
1581

1582
    /**
1583
     * @hidden
1584
     * @internal
1585
     */
1586
    public get collapsible() {
1587
        return false;
1588
    }
1589
    public set collapsible(_value: boolean) { }
1590

1591
    /**
1592
     * @hidden
1593
     * @internal
1594
     */
1595
    public get expanded() {
1596
        return true;
1597
    }
1598
    public set expanded(_value: boolean) { }
1599

1600
    /**
1601
     * @hidden
1602
     */
1603
    public defaultWidth: string;
1604

1605
    /**
1606
     * @hidden
1607
     */
1608
    public widthSetByUser: boolean;
1609

1610
    /**
1611
     * @hidden
1612
     */
1613
    public hasNestedPath: boolean;
1614

1615
    /**
1616
     * @hidden
1617
     * @internal
1618
     */
1619
    public defaultTimeFormat = 'hh:mm:ss tt';
1620

1621
    /**
1622
     * @hidden
1623
     * @internal
1624
     */
1625
    public defaultDateTimeFormat = 'dd/MM/yyyy HH:mm:ss tt';
1626

1627

1628
    /**
1629
     * Returns the filteringExpressionsTree of the column.
1630
     * ```typescript
1631
     * let tree =  this.column.filteringExpressionsTree;
1632
     * ```
1633
     *
2✔
1634
     * @memberof IgxColumnComponent
1635
     */
1636
    public get filteringExpressionsTree(): FilteringExpressionsTree {
1637
        return this.grid.filteringExpressionsTree.find(this.field) as FilteringExpressionsTree;
2✔
1638
    }
1639
    /**
1640
     * Sets/gets the parent column.
1641
     * ```typescript
2✔
1642
     * let parentColumn = this.column.parent;
1643
     * ```
1644
     * ```typescript
2✔
1645
     * this.column.parent = higherLevelColumn;
1646
     * ```
1647
     *
2✔
1648
     * @memberof IgxColumnComponent
1649
     */
1650
    public parent = null;
1651
    /**
2✔
1652
     * Sets/gets the children columns.
1653
     * ```typescript
1654
     * let columnChildren = this.column.children;
2✔
1655
     * ```
1656
     * ```typescript
1657
     * this.column.children = childrenColumns;
1658
     * ```
2✔
1659
     *
1660
     * @memberof IgxColumnComponent
1661
     */
2✔
1662
    public children: QueryList<IgxColumnComponent>;
1663
    /**
1664
     * @hidden
2✔
1665
     */
1666
    public destroy$ = new Subject<any>();
1667

1668
    /**
2✔
1669
     * @hidden
1670
     */
1671
    protected _applySelectableClass = false;
1672

2✔
1673
    protected _vIndex = NaN;
1674
    /**
1675
     * @hidden
1676
     */
2✔
1677
    protected _pinned = false;
1678
    /**
1679
     * @hidden
1680
     */
2✔
1681
    protected _bodyTemplate: TemplateRef<IgxCellTemplateContext>;
1682
    /**
1683
     * @hidden
1684
     */
2✔
1685
    protected _errorTemplate: TemplateRef<IgxCellTemplateContext>;
1686
    /**
1687
     * @hidden
2✔
1688
     */
1689
    protected _headerTemplate: TemplateRef<IgxColumnTemplateContext>;
1690
    /**
1691
     * @hidden
2✔
1692
     */
1693
    protected _summaryTemplate: TemplateRef<IgxSummaryTemplateContext>;
1694
    /**
1695
     * @hidden
2✔
1696
     */
1697
    protected _inlineEditorTemplate: TemplateRef<IgxCellTemplateContext>;
1698
    /**
1699
     * @hidden
2✔
1700
     */
1701
    protected _filterCellTemplate: TemplateRef<IgxColumnTemplateContext>;
1702
    /**
1703
     * @hidden
2✔
1704
     */
1705
    protected _summaries = null;
1706
    /**
1707
     * @hidden
2✔
1708
     */
1709
    protected _filters = null;
1710
    /**
1711
     * @hidden
2✔
1712
     */
1713
    protected _sortStrategy: ISortingStrategy = DefaultSortingStrategy.instance();
1714
    /**
1715
     * @hidden
2✔
1716
     */
1717
    protected _groupingComparer: (a: any, b: any, currRec?: any, groupRec?: any) => number;
1718
    /**
1719
     * @hidden
2✔
1720
     */
1721
    protected _hidden = false;
1722
    /**
2✔
1723
     * @hidden
1724
     */
1725
    protected _index: number;
2✔
1726
    /**
1727
     * @hidden
1728
     */
1729
    protected _disablePinning = false;
2✔
1730
    /**
1731
     * @hidden
1732
     */
1733
    protected _width: string;
2✔
1734
    /**
1735
     * @hidden
1736
     */
2✔
1737
    protected _defaultMinWidth = '';
1738
    /**
1739
     * @hidden
1740
     */
2✔
1741
    protected _hasSummary = false;
1742
    /**
1743
     * @hidden
1744
     */
2✔
1745
    protected _editable: boolean;
1746
    /**
1747
     * @hidden
1748
     */
2✔
1749
    protected _groupable = false;
1750
    /**
1751
     *  @hidden
1752
     */
2✔
1753
    protected _visibleWhenCollapsed;
1754
    /**
1755
     * @hidden
1756
     */
2✔
1757
    protected _collapsible = false;
1758
    /**
1759
     * @hidden
1760
     */
2✔
1761
    protected _expanded = true;
1762
    /**
1763
     * @hidden
1764
     */
2✔
1765
    protected _selectable = true;
1766
    /**
1767
     * @hidden
2✔
1768
     */
1769
    protected get isPrimaryColumn(): boolean {
1770
        return this.field !== undefined && this.grid !== undefined && this.field === this.grid.primaryKey;
1771
    }
2✔
1772

1773
    private _field: string;
1774
    private _calcWidth = null;
1775
    private _columnPipeArgs: IColumnPipeArgs = { digitsInfo: DEFAULT_DIGITS_INFO };
1776

1777
    constructor(
1778
        @Inject(IGX_GRID_BASE) public grid: GridType,
1779
        @Optional() @Self() @Inject(NG_VALIDATORS) private _validators: Validator[],
1780
        /** @hidden @internal **/
1781
        public cdr: ChangeDetectorRef,
1782
        protected platform: PlatformUtil,
1783
    ) {
1784
        this.validators  = _validators;
1785
     }
1786

1787
    /**
1788
     * @hidden
1789
     * @internal
1790
     */
1791
    public resetCaches() {
1792
        this._vIndex = NaN;
1793
        if (this.grid) {
1794
            this.cacheCalcWidth();
1795
        }
1796
    }
1797

1798
    /**
1799
     * @hidden
1800
     */
1801
    public ngOnDestroy() {
1802
        this.destroy$.next(true);
1803
        this.destroy$.complete();
1804
    }
1805
    /**
1806
     * @hidden
1807
     */
1808
    public ngAfterContentInit(): void {
1809
        if (this.summaryTemplateDirective) {
1810
            this._summaryTemplate = this.summaryTemplateDirective.template;
1811
        }
1812
        if (this.cellTemplate) {
1813
            this._bodyTemplate = this.cellTemplate.template;
1814
        }
1815
        if (this.cellValidationErrorTemplate) {
1816
            this._errorTemplate = this.cellValidationErrorTemplate.template;
1817
        }
1818
        if (this.headTemplate && this.headTemplate.length) {
1819
            this._headerTemplate = this.headTemplate.toArray()[0].template;
1820
        }
1821
        if (this.editorTemplate) {
1822
            this._inlineEditorTemplate = this.editorTemplate.template;
1823
        }
1824
        if (this.filterCellTemplateDirective) {
1825
            this._filterCellTemplate = this.filterCellTemplateDirective.template;
1826
        }
1827
        if (!this._columnPipeArgs.format) {
1828
            this._columnPipeArgs.format = this.dataType === GridColumnDataType.Time ?
1829
                DEFAULT_TIME_FORMAT : this.dataType === GridColumnDataType.DateTime ?
1830
                    DEFAULT_DATE_TIME_FORMAT : DEFAULT_DATE_FORMAT;
1831
        }
1832
        if (!this.summaries) {
1833
            switch (this.dataType) {
1834
                case GridColumnDataType.Number:
1835
                case GridColumnDataType.Currency:
1836
                case GridColumnDataType.Percent:
1837
                    this.summaries = IgxNumberSummaryOperand;
1838
                    break;
1839
                case GridColumnDataType.Date:
1840
                case GridColumnDataType.DateTime:
1841
                    this.summaries = IgxDateSummaryOperand;
1842
                    break;
1843
                case GridColumnDataType.Time:
1844
                    this.summaries = IgxTimeSummaryOperand;
1845
                    break;
1846

1847
                case GridColumnDataType.String:
1848
                case GridColumnDataType.Boolean:
1849
                default:
1850
                    this.summaries = IgxSummaryOperand;
1851
                    break;
1852
            }
1853
        }
1854
        if (!this.filters) {
1855
            switch (this.dataType) {
1856
                case GridColumnDataType.Boolean:
1857
                    this.filters = IgxBooleanFilteringOperand.instance();
1858
                    break;
1859
                case GridColumnDataType.Number:
1860
                case GridColumnDataType.Currency:
1861
                case GridColumnDataType.Percent:
1862
                    this.filters = IgxNumberFilteringOperand.instance();
1863
                    break;
1864
                case GridColumnDataType.Date:
1865
                    this.filters = IgxDateFilteringOperand.instance();
1866
                    break;
1867
                case GridColumnDataType.Time:
1868
                    this.filters = IgxTimeFilteringOperand.instance();
1869
                    break;
1870
                case GridColumnDataType.DateTime:
1871
                    this.filters = IgxDateTimeFilteringOperand.instance();
1872
                    break;
1873
                case GridColumnDataType.Image:
1874
                    this.filterable = false;
1875
                    break;
1876
                case GridColumnDataType.String:
1877
                default:
1878
                    this.filters = IgxStringFilteringOperand.instance();
1879
                    break;
1880
            }
1881
        }
1882
    }
1883

1884
    /**
1885
     * @hidden
1886
     */
1887
    public getGridTemplate(isRow: boolean): string {
1888
        if (isRow) {
1889
            const rowsCount = !this.grid.isPivot ? this.grid.multiRowLayoutRowSize : this.children.length - 1;
1890
            return `repeat(${rowsCount},1fr)`;
1891
        } else {
1892
            return this.getColumnSizesString(this.children);
1893
        }
1894
    }
1895

1896
    /** @hidden @internal **/
1897
    public getInitialChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<MRLColumnSizeInfo> {
1898
        const columnSizes: MRLColumnSizeInfo[] = [];
1899
        // find the smallest col spans
1900
        children.forEach(col => {
1901
            if (!col.colStart) {
1902
                return;
1903
            }
1904
            const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
1905
            const newSpanSmaller = columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].colSpan > col.gridColumnSpan;
1906
            const bothWidthsSet = col.widthSetByUser && columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].widthSetByUser;
1907
            const bothWidthsNotSet = !col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
1908

1909
            if (columnSizes[col.colStart - 1] === undefined) {
1910
                // If nothing is defined yet take any column at first
1911
                // We use colEnd to know where the column actually ends, because not always it starts where we have it set in columnSizes.
1912
                columnSizes[col.colStart - 1] = {
1913
                    ref: col,
1914
                    width: col.width === 'fit-content' ? col.autoSize :
1915
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null,
1916
                    colSpan: col.gridColumnSpan,
1917
                    colEnd: col.colStart + col.gridColumnSpan,
1918
                    widthSetByUser: col.widthSetByUser
1919
                };
1920
            } else if (newWidthSet || (newSpanSmaller && ((bothWidthsSet) || (bothWidthsNotSet)))) {
1921
                // If a column is set already it should either not have width defined or have width with bigger span than the new one.
1922

1923
                /**
1924
                 *  If replaced column has bigger span, we want to fill the remaining columns
1925
                 *  that the replacing column does not fill with the old one.
1926
                 */
1927
                if (bothWidthsSet && newSpanSmaller) {
1928
                    // Start from where the new column set would end and apply the old column to the rest depending on how much it spans.
1929
                    // We have not yet replaced it so we can use it directly from the columnSizes collection.
1930
                    // This is where colEnd is used because the colStart of the old column is not actually i + 1.
1931
                    for (let i = col.colStart - 1 + col.gridColumnSpan; i < columnSizes[col.colStart - 1].colEnd - 1; i++) {
1932
                        if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
1933
                            columnSizes[i] = columnSizes[col.colStart - 1];
1934
                        } else {
1935
                            break;
1936
                        }
1937
                    }
1938
                }
1939

1940
                // Replace the old column with the new one.
1941
                columnSizes[col.colStart - 1] = {
1942
                    ref: col,
1943
                    width: col.width === 'fit-content' ? col.autoSize :
1944
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null,
1945
                    colSpan: col.gridColumnSpan,
1946
                    colEnd: col.colStart + col.gridColumnSpan,
1947
                    widthSetByUser: col.widthSetByUser
1948
                };
1949
            } else if (bothWidthsSet && columnSizes[col.colStart - 1].colSpan < col.gridColumnSpan) {
1950
                // If the column already in the columnSizes has smaller span, we still need to fill any empty places with the current col.
1951
                // Start from where the smaller column set would end and apply the bigger column to the rest depending on how much it spans.
1952
                // Since here we do not have it in columnSizes we set it as a new column keeping the same colSpan.
1953
                for (let i = col.colStart - 1 + columnSizes[col.colStart - 1].colSpan; i < col.colStart - 1 + col.gridColumnSpan; i++) {
1954
                    if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
1955
                        columnSizes[i] = {
1956
                            ref: col,
1957
                            width: col.width === 'fit-content' ? col.autoSize :
1958
                                col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null,
1959
                            colSpan: col.gridColumnSpan,
1960
                            colEnd: col.colStart + col.gridColumnSpan,
1961
                            widthSetByUser: col.widthSetByUser
1962
                        };
1963
                    } else {
1964
                        break;
1965
                    }
1966
                }
1967
            }
1968
        });
1969

1970
        // Flatten columnSizes so there are not columns with colSpan > 1
1971
        for (let i = 0; i < columnSizes.length; i++) {
1972
            if (columnSizes[i] && columnSizes[i].colSpan > 1) {
1973
                let j = 1;
1974

1975
                // Replace all empty places depending on how much the current column spans starting from next col.
1976
                for (; j < columnSizes[i].colSpan && i + j + 1 < columnSizes[i].colEnd; j++) {
1977
                    if (columnSizes[i + j] &&
1978
                        ((!columnSizes[i].width && columnSizes[i + j].width) ||
1979
                            (!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
1980
                            (!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
1981
                        // If we reach an already defined column that has width and the current doesn't have or
1982
                        // if the reached column has bigger colSpan we stop.
1983
                        break;
1984
                    } else {
1985
                        const width = columnSizes[i].widthSetByUser ?
1986
                            columnSizes[i].width / columnSizes[i].colSpan :
1987
                            columnSizes[i].width;
1988
                        columnSizes[i + j] = {
1989
                            ref: columnSizes[i].ref,
1990
                            width,
1991
                            colSpan: 1,
1992
                            colEnd: columnSizes[i].colEnd,
1993
                            widthSetByUser: columnSizes[i].widthSetByUser
1994
                        };
1995
                    }
1996
                }
1997

1998
                // Update the current column width so it is divided between all columns it spans and set it to 1.
1999
                columnSizes[i].width = columnSizes[i].widthSetByUser ?
2000
                    columnSizes[i].width / columnSizes[i].colSpan :
2001
                    columnSizes[i].width;
2002
                columnSizes[i].colSpan = 1;
2003

2004
                // Update the index based on how much we have replaced. Subtract 1 because we started from 1.
2005
                i += j - 1;
2006
            }
2007
        }
2008

2009
        return columnSizes;
2010
    }
2011

2012
    /** @hidden @internal **/
2013
    public getFilledChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<string> {
2014
        const columnSizes = this.getInitialChildColumnSizes(children);
2015

2016
        // fill the gaps if there are any
2017
        const result: string[] = [];
2018
        for (const size of columnSizes) {
2019
            if (size && !!size.width) {
2020
                result.push(size.width + 'px');
2021
            } else {
2022
                result.push(parseInt(this.grid.getPossibleColumnWidth(), 10) + 'px');
2023
            }
2024
        }
2025
        return result;
2026
    }
2027

2028
    /** @hidden @internal **/
2029
    public getResizableColUnderEnd(): MRLResizeColumnInfo[] {
2030
        if (this.columnLayout || !this.columnLayoutChild || this.columnGroup) {
2031
            return [{ target: this, spanUsed: 1 }];
2032
        }
2033

2034
        const columnSized = this.getInitialChildColumnSizes(this.parent.children);
2035
        const targets: MRLResizeColumnInfo[] = [];
2036
        const colEnd = this.colEnd ? this.colEnd : this.colStart + 1;
2037

2038
        for (let i = 0; i < columnSized.length; i++) {
2039
            if (this.colStart <= i + 1 && i + 1 < colEnd) {
2040
                targets.push({ target: columnSized[i].ref, spanUsed: 1 });
2041
            }
2042
        }
2043

2044
        const targetsSquashed: MRLResizeColumnInfo[] = [];
2045
        for (const target of targets) {
2046
            if (targetsSquashed.length && targetsSquashed[targetsSquashed.length - 1].target.field === target.target.field) {
2047
                targetsSquashed[targetsSquashed.length - 1].spanUsed++;
2048
            } else {
2049
                targetsSquashed.push(target);
2050
            }
2051
        }
2052

2053
        return targetsSquashed;
2054
    }
2055

2056
    /**
2057
     * Pins the column at the provided index in the pinned area.
2058
     * Defaults to index `0` if not provided, or to the initial index in the pinned area.
2059
     * Returns `true` if the column is successfully pinned. Returns `false` if the column cannot be pinned.
2060
     * Column cannot be pinned if:
2061
     * - Is already pinned
2062
     * - index argument is out of range
2063
     * - The pinned area exceeds 80% of the grid width
2064
     * ```typescript
2065
     * let success = this.column.pin();
2066
     * ```
2067
     *
2068
     * @memberof IgxColumnComponent
2069
     */
2070
    public pin(index?: number): boolean {
2071
        // TODO: Probably should the return type of the old functions
2072
        // should be moved as a event parameter.
2073
        const grid = (this.grid as any);
2074
        if (this._pinned) {
2075
            return false;
2076
        }
2077

2078
        if (this.parent && !this.parent.pinned) {
2079
            return this.topLevelParent.pin(index);
2080
        }
2081

2082
        const hasIndex = index !== undefined;
2083
        if (hasIndex && (index < 0 || index > grid.pinnedColumns.length)) {
2084
            return false;
2085
        }
2086

2087
        if (!this.parent && !this.pinnable) {
2088
            return false;
2089
        }
2090

2091
        const rootPinnedCols = grid._pinnedColumns.filter((c) => c.level === 0);
2092
        index = hasIndex ? index : rootPinnedCols.length;
2093
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: false, cancel: false };
2094
        this.grid.columnPin.emit(args);
2095

2096
        if (args.cancel) {
2097
            return;
2098
        }
2099

2100
        this.grid.crudService.endEdit(false);
2101

2102
        this._pinned = true;
2103
        this.pinnedChange.emit(this._pinned);
2104
        // it is possible that index is the last position, so will need to find target column by [index-1]
2105
        const targetColumn = args.insertAtIndex === grid._pinnedColumns.length ?
2106
            grid._pinnedColumns[args.insertAtIndex - 1] : grid._pinnedColumns[args.insertAtIndex];
2107

2108
        if (grid._pinnedColumns.indexOf(this) === -1) {
2109
            if (!grid.hasColumnGroups) {
2110
                grid._pinnedColumns.splice(args.insertAtIndex, 0, this);
2111
            } else {
2112
                // insert based only on root collection
2113
                rootPinnedCols.splice(args.insertAtIndex, 0, this);
2114
                let allPinned = [];
2115
                // re-create hierarchy
2116
                rootPinnedCols.forEach(group => {
2117
                    allPinned.push(group);
2118
                    allPinned = allPinned.concat(group.allChildren);
2119
                });
2120
                grid._pinnedColumns = allPinned;
2121
            }
2122

2123
            if (grid._unpinnedColumns.indexOf(this) !== -1) {
2124
                const childrenCount = this.allChildren.length;
2125
                grid._unpinnedColumns.splice(grid._unpinnedColumns.indexOf(this), 1 + childrenCount);
2126
            }
2127
        }
2128

2129
        if (hasIndex) {
2130
            index === grid._pinnedColumns.length - 1 ? 
2131
            grid._moveColumns(this, targetColumn, DropPosition.AfterDropTarget) : grid._moveColumns(this, targetColumn, DropPosition.BeforeDropTarget);
2132
        }
2133

2134
        if (this.columnGroup) {
2135
            this.allChildren.forEach(child => child.pin());
2136
            grid.reinitPinStates();
2137
        }
2138

2139
        grid.resetCaches();
2140
        grid.notifyChanges();
2141
        if (this.columnLayoutChild) {
2142
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
2143
        }
2144
        this.grid.filteringService.refreshExpressions();
2145
        const eventArgs: IPinColumnEventArgs = { column: this, insertAtIndex: index, isPinned: true };
2146
        this.grid.columnPinned.emit(eventArgs);
2147
        return true;
2148
    }
2149
    /**
2150
     * Unpins the column and place it at the provided index in the unpinned area.
2151
     * Defaults to index `0` if not provided, or to the initial index in the unpinned area.
2152
     * Returns `true` if the column is successfully unpinned. Returns `false` if the column cannot be unpinned.
2153
     * Column cannot be unpinned if:
2154
     * - Is already unpinned
2155
     * - index argument is out of range
2156
     * ```typescript
2157
     * let success = this.column.unpin();
2158
     * ```
2159
     *
2160
     * @memberof IgxColumnComponent
2161
     */
2162
    public unpin(index?: number): boolean {
2163
        const grid = (this.grid as any);
2164
        if (!this._pinned) {
2165
            return false;
2166
        }
2167

2168
        if (this.parent && this.parent.pinned) {
2169
            return this.topLevelParent.unpin(index);
2170
        }
2171
        const hasIndex = index !== undefined;
2172
        if (hasIndex && (index < 0 || index > grid._unpinnedColumns.length)) {
2173
            return false;
2174
        }
2175

2176
        // estimate the exact index at which column will be inserted
2177
        // takes into account initial unpinned index of the column
2178
        if (!hasIndex) {
2179
            const indices = grid.unpinnedColumns.map(col => col.index);
2180
            indices.push(this.index);
2181
            indices.sort((a, b) => a - b);
2182
            index = indices.indexOf(this.index);
2183
        }
2184

2185
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: true, cancel: false };
2186
        this.grid.columnPin.emit(args);
2187

2188
        if (args.cancel) {
2189
            return;
2190
        }
2191

2192
        this.grid.crudService.endEdit(false);
2193

2194
        this._pinned = false;
2195
        this.pinnedChange.emit(this._pinned);
2196

2197
        // it is possible that index is the last position, so will need to find target column by [index-1]
2198
        const targetColumn = args.insertAtIndex === grid._unpinnedColumns.length ?
2199
            grid._unpinnedColumns[args.insertAtIndex - 1] : grid._unpinnedColumns[args.insertAtIndex];
2200

2201
        if (!hasIndex) {
2202
            grid._unpinnedColumns.splice(index, 0, this);
2203
            if (grid._pinnedColumns.indexOf(this) !== -1) {
2204
                grid._pinnedColumns.splice(grid._pinnedColumns.indexOf(this), 1);
2205
            }
2206
        }
2207

2208
        if (hasIndex) {
2209
            grid.moveColumn(this, targetColumn);
2210
        }
2211

2212
        if (this.columnGroup) {
2213
            this.allChildren.forEach(child => child.unpin());
2214
        }
2215

2216
        grid.reinitPinStates();
2217
        grid.resetCaches();
2218

2219
        grid.notifyChanges();
2220
        if (this.columnLayoutChild) {
2221
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
2222
        }
2223
        this.grid.filteringService.refreshExpressions();
2224

2225
        this.grid.columnPinned.emit({ column: this, insertAtIndex: index, isPinned: false });
2226

2227
        return true;
2228
    }
2229

2230
    /**
2231
     * Moves a column to the specified visible index.
2232
     * If passed index is invalid, or if column would receive a different visible index after moving, moving is not performed.
2233
     * If passed index would move the column to a different column group. moving is not performed.
2234
     *
2235
     * @example
2236
     * ```typescript
2237
     * column.move(index);
2238
     * ```
2239
     * @memberof IgxColumnComponent
2240
     */
2241
    public move(index: number) {
2242
        let target;
2243
        let columns = this.grid.columns.filter(c => c.visibleIndex > -1);
2244
        // grid last visible index
2245
        const li = columns.map(c => c.visibleIndex).reduce((a, b) => Math.max(a, b));
2246
        const parent = this.parent;
2247
        const isPreceding = this.visibleIndex < index;
2248

2249
        if (index === this.visibleIndex || index < 0 || index > li) {
2250
            return;
2251
        }
2252

2253
        if (parent) {
2254
            columns = columns.filter(c => c.level >= this.level && c !== this && c.parent !== this &&
2255
                c.topLevelParent === this.topLevelParent);
2256
        }
2257
        /* eslint-disable max-len */
2258
        // 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.
2259
        // 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.
2260
        /* eslint-enable max-len */
2261
        if (isPreceding) {
2262
            columns = columns.filter(c => c.visibleIndex > this.visibleIndex);
2263
            target = columns.find(c => c.level === this.level && c.visibleIndex + (c as any).calcChildren() - this.calcChildren() === index);
2264
        } else {
2265
            columns = columns.filter(c => c.visibleIndex < this.visibleIndex);
2266
            target = columns.find(c => c.level === this.level && c.visibleIndex === index);
2267
        }
2268

2269
        if (!target || (target.pinned && this.disablePinning)) {
2270
            return;
2271
        }
2272

2273
        const pos = isPreceding ? DropPosition.AfterDropTarget : DropPosition.BeforeDropTarget;
2274
        this.grid.moveColumn(this, target as IgxColumnComponent, pos);
2275
    }
2276

2277
    /**
2278
     * No children for the column, so will returns 1 or 0, if the column is hidden.
2279
     *
2280
     * @hidden
2281
     */
2282
    public calcChildren(): number {
2283
        const children = this.hidden ? 0 : 1;
2284
        return children;
2285
    }
2286

2287
    /**
2288
     * Toggles column vibisility and emits the respective event.
2289
     *
2290
     * @hidden
2291
     */
2292
    public toggleVisibility(value?: boolean) {
2293
        const newValue = value ?? !this.hidden;
2294
        const eventArgs: IColumnVisibilityChangingEventArgs = { column: this, newValue, cancel: false };
2295
        this.grid.columnVisibilityChanging.emit(eventArgs);
2296

2297
        if (eventArgs.cancel) {
2298
            return;
2299
        }
2300
        this.hidden = newValue;
2301
        this.grid.columnVisibilityChanged.emit({ column: this, newValue });
2302
    }
2303

2304
    /**
2305
     * Returns a reference to the top level parent column.
2306
     * ```typescript
2307
     * let topLevelParent =  this.column.topLevelParent;
2308
     * ```
2309
     *
2310
     * @memberof IgxColumnComponent
2311
     */
2312
    public get topLevelParent() {
2313
        let parent = this.parent;
2314
        while (parent && parent.parent) {
2315
            parent = parent.parent;
2316
        }
2317
        return parent;
2318
    }
2319

2320
    /**
2321
     * Returns a reference to the header of the column.
2322
     * ```typescript
2323
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2324
     * let headerCell = column.headerCell;
2325
     * ```
2326
     *
2327
     * @memberof IgxColumnComponent
2328
     */
2329
    public get headerCell(): IgxGridHeaderComponent {
2330
        return this.grid.headerCellList.find((header) => header.column === this);
2331
    }
2332

2333
    /**
2334
     * Returns a reference to the filter cell of the column.
2335
     * ```typescript
2336
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2337
     * let filterell = column.filterell;
2338
     * ```
2339
     *
2340
     * @memberof IgxColumnComponent
2341
     */
2342
    public get filterCell(): IgxGridFilteringCellComponent {
2343
        return this.grid.filterCellList.find((filterCell) => filterCell.column === this);
2344
    }
2345

2346
    /**
2347
     * Returns a reference to the header group of the column.
2348
     *
2349
     * @memberof IgxColumnComponent
2350
     */
2351
    public get headerGroup(): IgxGridHeaderGroupComponent {
2352
        return this.grid.headerGroupsList.find(group => group.column === this);
2353
    }
2354

2355
    /**
2356
     * Autosize the column to the longest currently visible cell value, including the header cell.
2357
     * ```typescript
2358
     * @ViewChild('grid') grid: IgxGridComponent;
2359
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2360
     * column.autosize();
2361
     * ```
2362
     *
2363
     * @memberof IgxColumnComponent
2364
     * @param byHeaderOnly Set if column should be autosized based only on the header content.
2365
     */
2366
    public autosize(byHeaderOnly = false) {
2367
        if (!this.columnGroup) {
2368
            this.width = this.getAutoSize(byHeaderOnly);
2369
            this.grid.reflow();
2370
        }
2371
    }
2372

2373
    /**
2374
     * @hidden
2375
     */
2376
    public getAutoSize(byHeader = false): string {
2377
        const size = !byHeader ? this.getLargestCellWidth() :
2378
            (Object.values(this.getHeaderCellWidths()).reduce((a, b) => a + b) + 'px');
2379
        const isPercentageWidth = this.width && typeof this.width === 'string' && this.width.indexOf('%') !== -1;
2380

2381
        let newWidth;
2382
        if (isPercentageWidth) {
2383
            const gridAvailableSize = this.grid.calcWidth;
2384
            const percentageSize = parseFloat(size) / gridAvailableSize * 100;
2385
            newWidth = percentageSize + '%';
2386
        } else {
2387
            newWidth = size;
2388
        }
2389

2390
        const maxWidth = isPercentageWidth ? this.maxWidthPercent : this.maxWidthPx;
2391
        const minWidth = isPercentageWidth ? this.minWidthPercent : this.minWidthPx;
2392
        if (this.maxWidth && (parseFloat(newWidth) > maxWidth)) {
2393
            newWidth = isPercentageWidth ? maxWidth + '%' : maxWidth + 'px';
2394
        } else if (parseFloat(newWidth) < minWidth) {
2395
            newWidth = isPercentageWidth ? minWidth + '%' : minWidth + 'px';
2396
        }
2397

2398
        return newWidth;
2399
    }
2400

2401
    /**
2402
     * @hidden
2403
     */
2404
    public getCalcWidth(): any {
2405
        if (this._calcWidth && !isNaN(this.calcPixelWidth)) {
2406
            return this._calcWidth;
2407
        }
2408
        this.cacheCalcWidth();
2409
        return this._calcWidth;
2410
    }
2411

2412

2413
    /**
2414
     * @hidden
2415
     * Returns the width and padding of a header cell.
2416
     */
2417
    public getHeaderCellWidths() {
2418
        return this.grid.getHeaderCellWidth(this.headerCell.nativeElement);
2419
    }
2420

2421
    /**
2422
     * @hidden
2423
     * Returns the size (in pixels) of the longest currently visible cell, including the header cell.
2424
     * ```typescript
2425
     * @ViewChild('grid') grid: IgxGridComponent;
2426
     *
2427
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2428
     * let size = column.getLargestCellWidth();
2429
     * ```
2430
     * @memberof IgxColumnComponent
2431
     */
2432
    public getLargestCellWidth(): string {
2433
        const range = this.grid.document.createRange();
2434
        const largest = new Map<number, number>();
2435

2436
        if (this._cells.length > 0) {
2437
            const cellsContentWidths = [];
2438
            this._cells.forEach((cell) => cellsContentWidths.push(cell.calculateSizeToFit(range)));
2439

2440
            const index = cellsContentWidths.indexOf(Math.max(...cellsContentWidths));
2441
            const cellStyle = this.grid.document.defaultView.getComputedStyle(this._cells[index].nativeElement);
2442
            const cellPadding = parseFloat(cellStyle.paddingLeft) + parseFloat(cellStyle.paddingRight) +
2443
                parseFloat(cellStyle.borderLeftWidth) + parseFloat(cellStyle.borderRightWidth);
2444

2445
            largest.set(Math.max(...cellsContentWidths), cellPadding);
2446
        }
2447

2448
        if (this.headerCell && this.autosizeHeader) {
2449
            const headerCellWidths = this.getHeaderCellWidths();
2450
            largest.set(headerCellWidths.width, headerCellWidths.padding);
2451
        }
2452

2453
        const largestCell = Math.max(...Array.from(largest.keys()));
2454
        const width = Math.ceil(largestCell + largest.get(largestCell));
2455

2456
        if (Number.isNaN(width)) {
2457
            return this.width;
2458
        } else {
2459
            return width + 'px';
2460
        }
2461
    }
2462

2463
    /**
2464
     * @hidden
2465
     */
2466
    public getCellWidth() {
2467
        const colWidth = this.width;
2468
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
2469

2470
        if (this.columnLayoutChild) {
2471
            return '';
2472
        }
2473

2474
        if (colWidth && !isPercentageWidth) {
2475

2476
            let cellWidth = colWidth;
2477
            if (typeof cellWidth !== 'string' || cellWidth.endsWith('px') === false) {
2478
                cellWidth += 'px';
2479
            }
2480

2481
            return cellWidth;
2482
        } else {
2483
            return colWidth;
2484
        }
2485
    }
2486

2487
    /**
2488
     * @hidden
2489
     */
2490
    public populateVisibleIndexes() { }
2491

2492
    protected getColumnSizesString(children: QueryList<IgxColumnComponent>): string {
2493
        const res = this.getFilledChildColumnSizes(children);
2494
        return res.join(' ');
2495
    }
2496

2497
    /**
2498
     * @hidden
2499
     * @internal
2500
     */
2501
    protected cacheCalcWidth(): any {
2502
        const colWidth = this.width;
2503
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
2504
        const isAutoWidth = colWidth && typeof colWidth === 'string' && colWidth === 'fit-content';
2505
        if (isPercentageWidth) {
2506
            this._calcWidth = Math.floor(parseFloat(colWidth) / 100 * this.grid.calcWidth);
2507
        } else if (!colWidth || isAutoWidth && !this.autoSize) {
2508
            // no width
2509
            this._calcWidth = this.defaultWidth || this.grid.getPossibleColumnWidth();
2510
        } else {
2511
            this._calcWidth = this.width;
2512
        }
2513
        this.calcPixelWidth = parseInt(this._calcWidth, 10);
2514
    }
2515

2516
    /**
2517
     * @hidden
2518
     * @internal
2519
     */
2520
    protected setExpandCollapseState() {
2521
        this.children.filter(col => (col.visibleWhenCollapsed !== undefined)).forEach(c => {
2522
            if (!this.collapsible) {
2523
                c.hidden = this.hidden; return;
2524
            }
2525
            c.hidden = this._expanded ? c.visibleWhenCollapsed : !c.visibleWhenCollapsed;
2526
        });
2527
    }
2528
    /**
2529
     * @hidden
2530
     * @internal
2531
     */
2532
    protected checkCollapsibleState() {
2533
        if (!this.children) {
2534
            return false;
2535
        }
2536
        const cols = this.children.map(child => child.visibleWhenCollapsed);
2537
        return (cols.some(c => c === true) && cols.some(c => c === false));
2538
    }
2539

2540
    /**
2541
     * @hidden
2542
     */
2543
    public get pinnable() {
2544
        return (this.grid as any)._init || !this.pinned;
2545
    }
2546

2547
    /**
2548
     * @hidden
2549
     */
2550
    public get applySelectableClass(): boolean {
2551
        return this._applySelectableClass;
2552
    }
2553

2554
    /**
2555
     * @hidden
2556
     */
2557
    public set applySelectableClass(value: boolean) {
2558
        if (this.selectable) {
2559
            this._applySelectableClass = value;
2560
        }
2561
    }
2562
}
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

© 2025 Coveralls, Inc