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

IgniteUI / igniteui-angular / 6037868074

31 Aug 2023 01:17PM UTC coverage: 92.29% (-0.003%) from 92.293%
6037868074

push

github

web-flow
fix(grid: column-pinning): working pinColumn with indexes for the last position (#13397)

* fix(grid: column-pinning): working pinColumn with indexes for the last position

* fix(grid-column-pinning): add the DropPosition and parse the string to number

* fix(grid-column-pinning): using parseInt instead of Number

* fix(grid-column-pinning): index of type number pinColumn and unpinColumn methods

15314 of 17988 branches covered (0.0%)

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

26849 of 29092 relevant lines covered (92.29%)

29752.7 hits per line

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

97.51
/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/displayDensity';
25,887✔
33
import { IgxRowDirective } from '../row.directive';
25,887✔
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';
17,990,472✔
37
import { IgxGridFilteringCellComponent } from '../filtering/base/grid-filtering-cell.component';
38
import { IgxGridHeaderGroupComponent } from '../headers/grid-header-group.component';
39
import {
100,793✔
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,475✔
52
import { MRLResizeColumnInfo, MRLColumnSizeInfo, IColumnPipeArgs } from './interfaces';
53
import { DropPosition } from '../moving/moving.service';
54
import { IColumnVisibilityChangingEventArgs, IPinColumnCancellableEventArgs, IPinColumnEventArgs } from '../common/events';
136,832✔
55
import { isConstructor, PlatformUtil } from '../../core/utils';
56
import { IgxGridCell } from '../grid-public-cell';
57
import { NG_VALIDATORS, Validator } from '@angular/forms';
3,246✔
58

3,246✔
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,809,047✔
64
/**
1,809,047✔
65
 * **Ignite UI for Angular Column** -
1,809,047✔
66
 * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid#columns-configuration)
74,280✔
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,734,767✔
69
 * filtering & editing are enabled at the column level.  You can also provide a template containing custom content inside
245,860✔
70
 * the column using `ng-template` which will be used for all cells within the column.
71
 */
72
@Component({
1,488,907✔
73
    changeDetection: ChangeDetectionStrategy.OnPush,
74
    selector: 'igx-column',
75
    template: ``
76
})
77
export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnType {
78
    /**
79
     * Sets/gets the `field` value.
80
     * ```typescript
81
     * let columnField = this.column.field;
82
     * ```
83
     * ```html
84
     * <igx-column [field] = "'ID'"></igx-column>
85
     * ```
86
     *
87
     * @memberof IgxColumnComponent
4,226✔
88
     */
89
    @Input()
90
    public set field(value: string) {
1,833,771✔
91
        this._field = value;
92
        this.hasNestedPath = value?.includes('.');
93
    }
94
    public get field(): string {
95
        return this._field;
96
    }
97

98

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

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

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

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

12,157✔
215
        if (this.isPrimaryColumn && (rowEditable || hasTransactions)) {
216
            return false;
217
        }
218

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

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

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

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

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

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

247,711✔
396
    /**
397
     * @hidden
398
     */
399
    @Output()
62,737✔
400
    public hiddenChange = new EventEmitter<boolean>();
401

402
    /** @hidden */
403
    @Output()
404
    public expandedChange = new EventEmitter<boolean>();
405

406
    /** @hidden */
407
    @Output()
408
    public collapsibleChange = new EventEmitter<boolean>();
409
    /** @hidden */
410
    @Output()
411
    public visibleWhenCollapsedChange = new EventEmitter<boolean>();
412

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

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

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

482
    public autoSize: number;
483

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

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

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

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

3,739,218✔
570
    /**
571
     * Sets/gets the class selector of the column group header.
3,875,442✔
572
     * ```typescript
383,306✔
573
     * let columnHeaderClass = this.column.headerGroupClasses;
383,306✔
574
     * ```
383,306✔
575
     * ```html
383,306✔
576
     * <igx-column [headerGroupClasses] = "'column-group-header'"></igx-column>
23,432✔
577
     * ```
578
     *
383,306✔
579
     * @memberof IgxColumnComponent
700,900✔
580
     */
581
    @notifyChanges()
113,290✔
582
    @WatchColumnChanges()
111,062✔
583
    @Input()
111,062✔
584
    public headerGroupClasses = '';
585

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

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

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

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

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

779
    /** @hidden */
780
    @Input()
781
    public collapsibleIndicatorTemplate: TemplateRef<IgxColumnTemplateContext>;
782

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

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

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

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

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

853
    /**
267,084✔
854
     * @hidden
267,084!
855
     */
267,084✔
856
    @Output()
857
    public widthChange = new EventEmitter<string>();
858

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

907
    public calcPixelWidth: number;
908

909
    /**
13,059✔
910
     * @hidden
13,059✔
911
     */
912
    public get maxWidthPx() {
913
        const gridAvailableSize = this.grid.calcWidth;
22,763✔
914
        const isPercentageWidth = this.maxWidth && typeof this.maxWidth === 'string' && this.maxWidth.indexOf('%') !== -1;
21,264✔
915
        return isPercentageWidth ? parseFloat(this.maxWidth) / 100 * gridAvailableSize : parseFloat(this.maxWidth);
916
    }
1,158✔
917

1,158✔
918
    /**
919
     * @hidden
920
     */
921
    public get maxWidthPercent() {
6,568✔
922
        const gridAvailableSize = this.grid.calcWidth;
6,568✔
923
        const isPercentageWidth = this.maxWidth && typeof this.maxWidth === 'string' && this.maxWidth.indexOf('%') !== -1;
924
        return isPercentageWidth ? parseFloat(this.maxWidth) : parseFloat(this.maxWidth) / gridAvailableSize * 100;
1,489✔
925
    }
1,489✔
926

927
    /**
216✔
928
     * @hidden
216✔
929
     */
930
    public get minWidthPx() {
243✔
931
        const gridAvailableSize = this.grid.calcWidth;
243✔
932
        const isPercentageWidth = this.minWidth && typeof this.minWidth === 'string' && this.minWidth.indexOf('%') !== -1;
933
        return isPercentageWidth ? parseFloat(this.minWidth) / 100 * gridAvailableSize : parseFloat(this.minWidth);
1✔
934
    }
1✔
935

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

945

946
    /**
21,556✔
947
     * Sets/gets the minimum `width` of the column.
10,779!
948
     * Default value is `88`;
10,779✔
949
     * ```typescript
950
     * let columnMinWidth = this.column.minWidth;
951
     * ```
10,777✔
952
     * ```html
953
     * <igx-column [minWidth] = "'100px'"></igx-column>
954
     * ```
955
     *
135,551✔
956
     * @memberof IgxColumnComponent
957
     */
135,551✔
958
    @notifyChanges()
420,069✔
959
    @WatchColumnChanges()
111,899✔
960
    @Input()
961
    public set minWidth(value: string) {
308,170✔
962
        const minVal = parseFloat(value);
308,170✔
963
        if (Number.isNaN(minVal)) {
308,170✔
964
            return;
308,170✔
965
        }
308,170✔
966
        this._defaultMinWidth = value;
967

968
    }
188,993✔
969
    public get minWidth(): string {
970
        return !this._defaultMinWidth ? this.defaultMinWidth : this._defaultMinWidth;
188,993!
971
    }
551,743✔
972

973
    /**
974
     * Gets the column index.
975
     * ```typescript
976
     * let columnIndex = this.column.index;
977
     * ```
119,177✔
978
     *
979
     * @memberof IgxColumnComponent
980
     */
981
    public get index(): number {
982
        return (this.grid as any)._columns.indexOf(this);
983
    }
43,370✔
984

985
    /**
986
     * Gets whether the column is `pinned`.
987
     * ```typescript
4,167✔
988
     * let isPinned = this.column.pinned;
2,413✔
989
     * ```
2,360✔
990
     *
991
     * @memberof IgxColumnComponent
992
     */
53✔
993
    @WatchColumnChanges()
994
    @Input()
995
    public get pinned(): boolean {
996
        return this._pinned;
997
    }
43,370✔
998
    /**
999
     * Sets whether the column is pinned.
43,370!
1000
     * Default value is `false`.
122,643✔
1001
     * ```html
1002
     * <igx-column [pinned] = "true"></igx-column>
1003
     * ```
1004
     *
1005
     * Two-way data binding.
1006
     * ```html
75,807✔
1007
     * <igx-column [(pinned)] = "model.columns[0].isPinned"></igx-column>
1008
     * ```
1009
     *
1010
     * @memberof IgxColumnComponent
2,987✔
1011
     */
2,987✔
1012
    public set pinned(value: boolean) {
37✔
1013
        if (this._pinned !== value) {
1014
            const isAutoWidth = this.width && typeof this.width === 'string' && this.width === 'fit-content';
37!
1015
            if (this.grid && this.width && (isAutoWidth || !isNaN(parseInt(this.width, 10)))) {
74!
1016
                if (value) {
1017
                    this.pin();
1018
                } else {
1019
                    this.unpin();
1020
                }
1021
                return;
1022
            }
2,950✔
1023
            /* No grid/width available at initialization. `initPinning` in the grid
1024
               will re-init the group (if present)
1025
            */
1026
            this._pinned = value;
1027
            this.pinnedChange.emit(this._pinned);
1028
        }
135,551✔
1029
    }
186,969✔
1030

10,216✔
1031
    /**
1032
     * Gets the column `summaries`.
10,216✔
1033
     * ```typescript
9,846✔
1034
     * let columnSummaries = this.column.summaries;
1035
     * ```
1036
     *
1037
     * @memberof IgxColumnComponent
1038
     */
1039
    @notifyChanges(true)
4,240✔
1040
    @WatchColumnChanges()
1041
    @Input()
1042
    public get summaries(): any {
5,606✔
1043
        return this._summaries;
1044
    }
1045
    /**
5,606✔
1046
     * Sets the column `summaries`.
1047
     * ```typescript
1048
     * this.column.summaries = IgxNumberSummaryOperand;
1049
     * ```
1050
     *
1051
     * @memberof IgxColumnComponent
1052
     */
1053
    public set summaries(classRef: any) {
1054
        if (isConstructor(classRef)) {
1055
            this._summaries = new classRef();
10,216✔
1056
        }
1057

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

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

24✔
1292
    /**
1293
     * Returns a reference to the validation error template.
1294
     * ```typescript
1295
     * let errorTemplate = this.column.errorTemplate;
1296
     * ```
1297
     */
1298
    @notifyChanges()
1299
    @WatchColumnChanges()
70✔
1300
    @Input('errorTemplate')
70✔
1301
    public get errorTemplate(): TemplateRef<IgxCellTemplateContext> {
1302
        return this._errorTemplate;
1303
    }
1304
    /**
1305
     * Sets the error template.
1306
     * ```html
1307
     * <ng-template igxCellValidationError let-cell="cell" #errorTemplate >
1308
     *     <div *ngIf="cell.validation.errors?.['forbiddenName']">
65✔
1309
     *      This name is forbidden.
65✔
1310
     *     </div>
65✔
1311
     * </ng-template>
65!
1312
     * ```
×
1313
     * ```typescript
1314
     * @ViewChild("'errorTemplate'", {read: TemplateRef })
65✔
1315
     * public errorTemplate: TemplateRef<any>;
65✔
1316
     * this.column.errorTemplate = this.errorTemplate;
1317
     * ```
1318
     */
1319
    public set errorTemplate(template: TemplateRef<IgxCellTemplateContext>) {
1320
        this._errorTemplate = template;
1321
    }
1322

1323
    /**
1324
     * Returns a reference to the `filterCellTemplate`.
1325
     * ```typescript
1326
     * let filterCellTemplate = this.column.filterCellTemplate;
486✔
1327
     * ```
486✔
1328
     *
34✔
1329
     * @memberof IgxColumnComponent
1330
     */
486✔
1331
    @notifyChanges()
1332
    @WatchColumnChanges()
1333
    @Input('filterCellTemplate')
1334
    public get filterCellTemplate(): TemplateRef<IgxColumnTemplateContext> {
1335
        return this._filterCellTemplate;
1336
    }
1337
    /**
1338
     * Sets the quick filter template.
1339
     * ```html
1340
     * <ng-template #filterCellTemplate IgxFilterCellTemplate let-column="column">
1341
     *    <input (input)="onInput()">
1342
     * </ng-template>
1,527✔
1343
     * ```
1344
     * ```typescript
1345
     * @ViewChild("'filterCellTemplate'", {read: TemplateRef })
1346
     * public filterCellTemplate: TemplateRef<any>;
1347
     * this.column.filterCellTemplate = this.filterCellTemplate;
1348
     * ```
1349
     *
1350
     * @memberof IgxColumnComponent
1351
     */
1352
    public set filterCellTemplate(template: TemplateRef<IgxColumnTemplateContext>) {
1353
        this._filterCellTemplate = template;
1354
    }
7,078✔
1355

1356
    /**
1357
     * Gets the cells of the column.
1358
     * ```typescript
1359
     * let columnCells = this.column.cells;
1360
     * ```
1361
     *
1362
     */
11,643✔
1363
    public get cells(): CellType[] {
1364
        return this.grid.dataView
1365
            .map((rec, index) => {
1366
                if (!this.grid.isGroupByRecord(rec) && !this.grid.isSummaryRow(rec)) {
1367
                    this.grid.pagingMode === 1 && this.grid.page !== 0 ? index = index + this.grid.perPage * this.grid.page : index = this.grid.dataRowList.first.index + index;
1368
                    const cell = new IgxGridCell(this.grid as any, index, this.field);
1369
                    return cell;
1370
                }
1371
            }).filter(cell => cell);
1372
    }
1373

1374

1375
    /**
17✔
1376
     * @hidden @internal
18!
1377
     */
18✔
1378
    public get _cells(): CellType[] {
18✔
1379
        return this.grid.rowList.filter((row) => row instanceof IgxRowDirective)
1380
            .map((row) => {
1381
                if (row._cells) {
1382
                    return row._cells.filter((cell) => cell.columnIndex === this.index);
1383
                }
1384
            }).reduce((a, b) => a.concat(b), []);
8✔
1385
    }
26✔
1386

1✔
1387
    /**
26✔
1388
     * Gets the column visible index.
1389
     * If the column is not visible, returns `-1`.
26✔
1390
     * ```typescript
2✔
1391
     * let visibleColumnIndex =  this.column.visibleIndex;
2✔
1392
     * ```
2✔
1393
     *
1394
     * @memberof IgxColumnComponent
1395
     */
24✔
1396
    public get visibleIndex(): number {
1397
        if (!isNaN(this._vIndex)) {
26✔
1398
            return this._vIndex;
26✔
1399
        }
26✔
1400
        const unpinnedColumns = this.grid.unpinnedColumns.filter(c => !c.columnGroup);
1!
1401
        const pinnedColumns = this.grid.pinnedColumns.filter(c => !c.columnGroup);
1402
        let col = this;
25✔
1403
        let vIndex = -1;
1!
1404

1405
        if (this.columnGroup) {
26✔
1406
            col = this.allChildren.filter(c => !c.columnGroup && !c.hidden)[0] as any;
1407
        }
1408
        if (this.columnLayoutChild) {
1409
            return this.parent.childrenVisibleIndexes.find(x => x.column === this).index;
1410
        }
1411

313,152✔
1412
        if (!this.pinned) {
301,991✔
1413
            const indexInCollection = unpinnedColumns.indexOf(col);
1414
            vIndex = indexInCollection === -1 ?
11,161✔
1415
                -1 :
11,161✔
1416
                (this.grid.isPinningToStart ?
1417
                    pinnedColumns.length + indexInCollection :
1418
                    indexInCollection);
1419
        } else {
1420
            const indexInCollection = pinnedColumns.indexOf(col);
1421
            vIndex = this.grid.isPinningToStart ?
1422
                indexInCollection :
25✔
1423
                unpinnedColumns.length + indexInCollection;
1424
        }
1425
        this._vIndex = vIndex;
1426
        return vIndex;
1427
    }
1428
    /**
1429
     * Returns a boolean indicating if the column is a `ColumnGroup`.
1430
     * ```typescript
1431
     * let columnGroup =  this.column.columnGroup;
1432
     * ```
1433
     *
1434
     * @memberof IgxColumnComponent
1435
     */
1436
    public get columnGroup() {
25✔
1437
        return false;
25✔
1438
    }
25!
1439
    /**
25✔
1440
     * Returns a boolean indicating if the column is a `ColumnLayout` for multi-row layout.
270✔
1441
     * ```typescript
25✔
1442
     * let columnGroup =  this.column.columnGroup;
25✔
1443
     * ```
25✔
1444
     *
1445
     * @memberof IgxColumnComponent
25✔
1446
     */
1447
    public get columnLayout() {
25✔
1448
        return false;
24✔
1449
    }
24✔
1450

1451
    /**
25✔
1452
     * Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
25✔
1453
     * ```typescript
25!
1454
     * let columnLayoutChild =  this.column.columnLayoutChild;
×
1455
     * ```
1456
     *
1457
     * @memberof IgxColumnComponent
25✔
1458
     */
1459
    public get columnLayoutChild() {
1460
        return this.parent && this.parent.columnLayout;
1461
    }
1462

1463
    /**
1464
     * Returns the children columns collection.
1,046,636✔
1465
     * Returns an empty array if the column does not contain children columns.
1,046,636✔
1466
     * ```typescript
1,046,636!
1467
     * let childrenColumns =  this.column.allChildren;
×
1468
     * ```
1469
     *
1,046,636✔
1470
     * @memberof IgxColumnComponent
1,037,646✔
1471
     */
1,037,646✔
1472
    public get allChildren(): IgxColumnComponent[] {
1,965✔
1473
        return [];
1474
    }
1,037,646✔
1475
    /**
1476
     * Returns the level of the column in a column group.
1477
     * Returns `0` if the column doesn't have a `parent`.
8,990✔
1478
     * ```typescript
1479
     * let columnLevel =  this.column.level;
1480
     * ```
1481
     *
1482
     * @memberof IgxColumnComponent
1483
     */
1484
    public get level() {
1485
        let ptr = this.parent;
10,777✔
1486
        let lvl = 0;
10,777✔
1487

1488
        while (ptr) {
1489
            lvl++;
1490
            ptr = ptr.parent;
1491
        }
1492
        return lvl;
1493
    }
290,402✔
1494

290,402✔
1495
    public get isLastPinned(): boolean {
290,402✔
1496
        return this.grid.isPinningToStart &&
290,402✔
1497
            this.grid.pinnedColumns[this.grid.pinnedColumns.length - 1] === this;
805✔
1498
    }
1499

289,597✔
1500
    public get isFirstPinned(): boolean {
1501
        const pinnedCols = this.grid.pinnedColumns.filter(x => !x.columnGroup);
29,295✔
1502
        return !this.grid.isPinningToStart && pinnedCols[0] === this;
1503
    }
1504

260,302✔
1505
    public get rightPinnedOffset(): string {
1506
        return this.pinned && !this.grid.isPinningToStart ?
290,402✔
1507
            - this.grid.pinnedWidth - this.grid.headerFeaturesWidth + 'px' :
1508
            null;
1509
    }
1510

1511
    public get gridRowSpan(): number {
1512
        return this.rowEnd && this.rowStart ? this.rowEnd - this.rowStart : 1;
1513
    }
245✔
1514
    public get gridColumnSpan(): number {
226✔
1515
        return this.colEnd && this.colStart ? this.colEnd - this.colStart : 1;
1✔
1516
    }
1✔
1517

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

1538
    public get visibleWhenCollapsed(): boolean {
1539
        return this._visibleWhenCollapsed;
1540
    }
1541

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

1573
    /**
1574
     * @hidden
1575
     * @internal
1576
     */
1577
    public get collapsible() {
1578
        return false;
1579
    }
1580
    public set collapsible(_value: boolean) { }
1581

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

1591
    /**
1592
     * hidden
1593
     */
1594
    public defaultWidth: string;
1595

1596
    /**
1597
     * hidden
1598
     */
1599
    public widthSetByUser: boolean;
1600

1601
    /**
1602
     * @hidden
1603
     */
1604
    public hasNestedPath: boolean;
1605

1606
    /**
1607
     * @hidden
1608
     * @internal
1609
     */
1610
    public defaultTimeFormat = 'hh:mm:ss tt';
1611

1612
    /**
1613
     * @hidden
1614
     * @internal
1615
     */
1616
    public defaultDateTimeFormat = 'dd/MM/yyyy HH:mm:ss tt';
1617

1618

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

1659
    /**
2✔
1660
     * @hidden
1661
     */
1662
    protected _applySelectableClass = false;
1663

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

1764
    private _field: string;
1765
    private _calcWidth = null;
1766
    private _columnPipeArgs: IColumnPipeArgs = { digitsInfo: DEFAULT_DIGITS_INFO };
1767

1768
    constructor(
1769
        @Inject(IGX_GRID_BASE) public grid: GridType,
1770
        @Optional() @Self() @Inject(NG_VALIDATORS) private _validators: Validator[],
1771
        public cdr: ChangeDetectorRef,
1772
        protected platform: PlatformUtil,
1773
    ) {
1774
        this.validators  = _validators;
1775
     }
1776

1777
    /**
1778
     * @hidden
1779
     * @internal
1780
     */
1781
    public resetCaches() {
1782
        this._vIndex = NaN;
1783
        if (this.grid) {
1784
            this.cacheCalcWidth();
1785
        }
1786
    }
1787

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

1837
                case GridColumnDataType.String:
1838
                case GridColumnDataType.Boolean:
1839
                default:
1840
                    this.summaries = IgxSummaryOperand;
1841
                    break;
1842
            }
1843
        }
1844
        if (!this.filters) {
1845
            switch (this.dataType) {
1846
                case GridColumnDataType.Boolean:
1847
                    this.filters = IgxBooleanFilteringOperand.instance();
1848
                    break;
1849
                case GridColumnDataType.Number:
1850
                case GridColumnDataType.Currency:
1851
                case GridColumnDataType.Percent:
1852
                    this.filters = IgxNumberFilteringOperand.instance();
1853
                    break;
1854
                case GridColumnDataType.Date:
1855
                    this.filters = IgxDateFilteringOperand.instance();
1856
                    break;
1857
                case GridColumnDataType.Time:
1858
                    this.filters = IgxTimeFilteringOperand.instance();
1859
                    break;
1860
                case GridColumnDataType.DateTime:
1861
                    this.filters = IgxDateTimeFilteringOperand.instance();
1862
                    break;
1863
                case GridColumnDataType.Image:
1864
                    this.filterable = false;
1865
                    break;
1866
                case GridColumnDataType.String:
1867
                default:
1868
                    this.filters = IgxStringFilteringOperand.instance();
1869
                    break;
1870
            }
1871
        }
1872
    }
1873

1874
    /**
1875
     * @hidden
1876
     */
1877
    public getGridTemplate(isRow: boolean): string {
1878
        if (isRow) {
1879
            const rowsCount = !this.grid.isPivot ? this.grid.multiRowLayoutRowSize : this.children.length - 1;
1880
            return `repeat(${rowsCount},1fr)`;
1881
        } else {
1882
            return this.getColumnSizesString(this.children);
1883
        }
1884
    }
1885

1886
    public getInitialChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<MRLColumnSizeInfo> {
1887
        const columnSizes: MRLColumnSizeInfo[] = [];
1888
        // find the smallest col spans
1889
        children.forEach(col => {
1890
            if (!col.colStart) {
1891
                return;
1892
            }
1893
            const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
1894
            const newSpanSmaller = columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].colSpan > col.gridColumnSpan;
1895
            const bothWidthsSet = col.widthSetByUser && columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].widthSetByUser;
1896
            const bothWidthsNotSet = !col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
1897

1898
            if (columnSizes[col.colStart - 1] === undefined) {
1899
                // If nothing is defined yet take any column at first
1900
                // We use colEnd to know where the column actually ends, because not always it starts where we have it set in columnSizes.
1901
                columnSizes[col.colStart - 1] = {
1902
                    ref: col,
1903
                    width: col.width === 'fit-content' ? col.autoSize :
1904
                        col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null,
1905
                    colSpan: col.gridColumnSpan,
1906
                    colEnd: col.colStart + col.gridColumnSpan,
1907
                    widthSetByUser: col.widthSetByUser
1908
                };
1909
            } else if (newWidthSet || (newSpanSmaller && ((bothWidthsSet) || (bothWidthsNotSet)))) {
1910
                // If a column is set already it should either not have width defined or have width with bigger span than the new one.
1911

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

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

1959
        // Flatten columnSizes so there are not columns with colSpan > 1
1960
        for (let i = 0; i < columnSizes.length; i++) {
1961
            if (columnSizes[i] && columnSizes[i].colSpan > 1) {
1962
                let j = 1;
1963

1964
                // Replace all empty places depending on how much the current column spans starting from next col.
1965
                for (; j < columnSizes[i].colSpan && i + j + 1 < columnSizes[i].colEnd; j++) {
1966
                    if (columnSizes[i + j] &&
1967
                        ((!columnSizes[i].width && columnSizes[i + j].width) ||
1968
                            (!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
1969
                            (!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
1970
                        // If we reach an already defined column that has width and the current doesn't have or
1971
                        // if the reached column has bigger colSpan we stop.
1972
                        break;
1973
                    } else {
1974
                        const width = columnSizes[i].widthSetByUser ?
1975
                            columnSizes[i].width / columnSizes[i].colSpan :
1976
                            columnSizes[i].width;
1977
                        columnSizes[i + j] = {
1978
                            ref: columnSizes[i].ref,
1979
                            width,
1980
                            colSpan: 1,
1981
                            colEnd: columnSizes[i].colEnd,
1982
                            widthSetByUser: columnSizes[i].widthSetByUser
1983
                        };
1984
                    }
1985
                }
1986

1987
                // Update the current column width so it is divided between all columns it spans and set it to 1.
1988
                columnSizes[i].width = columnSizes[i].widthSetByUser ?
1989
                    columnSizes[i].width / columnSizes[i].colSpan :
1990
                    columnSizes[i].width;
1991
                columnSizes[i].colSpan = 1;
1992

1993
                // Update the index based on how much we have replaced. Subtract 1 because we started from 1.
1994
                i += j - 1;
1995
            }
1996
        }
1997

1998
        return columnSizes;
1999
    }
2000

2001
    public getFilledChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<string> {
2002
        const columnSizes = this.getInitialChildColumnSizes(children);
2003

2004
        // fill the gaps if there are any
2005
        const result: string[] = [];
2006
        for (const size of columnSizes) {
2007
            if (size && !!size.width) {
2008
                result.push(size.width + 'px');
2009
            } else {
2010
                result.push(parseInt(this.grid.getPossibleColumnWidth(), 10) + 'px');
2011
            }
2012
        }
2013
        return result;
2014
    }
2015

2016
    public getResizableColUnderEnd(): MRLResizeColumnInfo[] {
2017
        if (this.columnLayout || !this.columnLayoutChild || this.columnGroup) {
2018
            return [{ target: this, spanUsed: 1 }];
2019
        }
2020

2021
        const columnSized = this.getInitialChildColumnSizes(this.parent.children);
2022
        const targets: MRLResizeColumnInfo[] = [];
2023
        const colEnd = this.colEnd ? this.colEnd : this.colStart + 1;
2024

2025
        for (let i = 0; i < columnSized.length; i++) {
2026
            if (this.colStart <= i + 1 && i + 1 < colEnd) {
2027
                targets.push({ target: columnSized[i].ref, spanUsed: 1 });
2028
            }
2029
        }
2030

2031
        const targetsSquashed: MRLResizeColumnInfo[] = [];
2032
        for (const target of targets) {
2033
            if (targetsSquashed.length && targetsSquashed[targetsSquashed.length - 1].target.field === target.target.field) {
2034
                targetsSquashed[targetsSquashed.length - 1].spanUsed++;
2035
            } else {
2036
                targetsSquashed.push(target);
2037
            }
2038
        }
2039

2040
        return targetsSquashed;
2041
    }
2042

2043
    /**
2044
     * Pins the column at the provided index in the pinned area.
2045
     * Defaults to index `0` if not provided, or to the initial index in the pinned area.
2046
     * Returns `true` if the column is successfully pinned. Returns `false` if the column cannot be pinned.
2047
     * Column cannot be pinned if:
2048
     * - Is already pinned
2049
     * - index argument is out of range
2050
     * - The pinned area exceeds 80% of the grid width
2051
     * ```typescript
2052
     * let success = this.column.pin();
2053
     * ```
2054
     *
2055
     * @memberof IgxColumnComponent
2056
     */
2057
    public pin(index?: number): boolean {
2058
        // TODO: Probably should the return type of the old functions
2059
        // should be moved as a event parameter.
2060
        const grid = (this.grid as any);
2061
        if (this._pinned) {
2062
            return false;
2063
        }
2064

2065
        if (this.parent && !this.parent.pinned) {
2066
            return this.topLevelParent.pin(index);
2067
        }
2068

2069
        const hasIndex = index !== undefined;
2070
        if (hasIndex && (index < 0 || index > grid.pinnedColumns.length)) {
2071
            return false;
2072
        }
2073

2074
        if (!this.parent && !this.pinnable) {
2075
            return false;
2076
        }
2077

2078
        const rootPinnedCols = grid._pinnedColumns.filter((c) => c.level === 0);
2079
        index = hasIndex ? index : rootPinnedCols.length;
2080
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: false, cancel: false };
2081
        this.grid.columnPin.emit(args);
2082

2083
        if (args.cancel) {
2084
            return;
2085
        }
2086

2087
        this.grid.crudService.endEdit(false);
2088

2089
        this._pinned = true;
2090
        this.pinnedChange.emit(this._pinned);
2091
        // it is possible that index is the last position, so will need to find target column by [index-1]
2092
        const targetColumn = args.insertAtIndex === grid._pinnedColumns.length ?
2093
            grid._pinnedColumns[args.insertAtIndex - 1] : grid._pinnedColumns[args.insertAtIndex];
2094

2095
        if (grid._pinnedColumns.indexOf(this) === -1) {
2096
            if (!grid.hasColumnGroups) {
2097
                grid._pinnedColumns.splice(args.insertAtIndex, 0, this);
2098
            } else {
2099
                // insert based only on root collection
2100
                rootPinnedCols.splice(args.insertAtIndex, 0, this);
2101
                let allPinned = [];
2102
                // re-create hierarchy
2103
                rootPinnedCols.forEach(group => {
2104
                    allPinned.push(group);
2105
                    allPinned = allPinned.concat(group.allChildren);
2106
                });
2107
                grid._pinnedColumns = allPinned;
2108
            }
2109

2110
            if (grid._unpinnedColumns.indexOf(this) !== -1) {
2111
                const childrenCount = this.allChildren.length;
2112
                grid._unpinnedColumns.splice(grid._unpinnedColumns.indexOf(this), 1 + childrenCount);
2113
            }
2114
        }
2115

2116
        if (hasIndex) {
2117
            index === grid._pinnedColumns.length - 1 ? 
2118
            grid._moveColumns(this, targetColumn, DropPosition.AfterDropTarget) : grid._moveColumns(this, targetColumn, DropPosition.BeforeDropTarget);
2119
        }
2120

2121
        if (this.columnGroup) {
2122
            this.allChildren.forEach(child => child.pin());
2123
            grid.reinitPinStates();
2124
        }
2125

2126
        grid.resetCaches();
2127
        grid.notifyChanges();
2128
        if (this.columnLayoutChild) {
2129
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
2130
        }
2131
        this.grid.filteringService.refreshExpressions();
2132
        const eventArgs: IPinColumnEventArgs = { column: this, insertAtIndex: index, isPinned: true };
2133
        this.grid.columnPinned.emit(eventArgs);
2134
        return true;
2135
    }
2136
    /**
2137
     * Unpins the column and place it at the provided index in the unpinned area.
2138
     * Defaults to index `0` if not provided, or to the initial index in the unpinned area.
2139
     * Returns `true` if the column is successfully unpinned. Returns `false` if the column cannot be unpinned.
2140
     * Column cannot be unpinned if:
2141
     * - Is already unpinned
2142
     * - index argument is out of range
2143
     * ```typescript
2144
     * let success = this.column.unpin();
2145
     * ```
2146
     *
2147
     * @memberof IgxColumnComponent
2148
     */
2149
    public unpin(index?: number): boolean {
2150
        const grid = (this.grid as any);
2151
        if (!this._pinned) {
2152
            return false;
2153
        }
2154

2155
        if (this.parent && this.parent.pinned) {
2156
            return this.topLevelParent.unpin(index);
2157
        }
2158
        const hasIndex = index !== undefined;
2159
        if (hasIndex && (index < 0 || index > grid._unpinnedColumns.length)) {
2160
            return false;
2161
        }
2162

2163
        // estimate the exact index at which column will be inserted
2164
        // takes into account initial unpinned index of the column
2165
        if (!hasIndex) {
2166
            const indices = grid.unpinnedColumns.map(col => col.index);
2167
            indices.push(this.index);
2168
            indices.sort((a, b) => a - b);
2169
            index = indices.indexOf(this.index);
2170
        }
2171

2172
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: true, cancel: false };
2173
        this.grid.columnPin.emit(args);
2174

2175
        if (args.cancel) {
2176
            return;
2177
        }
2178

2179
        this.grid.crudService.endEdit(false);
2180

2181
        this._pinned = false;
2182
        this.pinnedChange.emit(this._pinned);
2183

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

2188
        if (!hasIndex) {
2189
            grid._unpinnedColumns.splice(index, 0, this);
2190
            if (grid._pinnedColumns.indexOf(this) !== -1) {
2191
                grid._pinnedColumns.splice(grid._pinnedColumns.indexOf(this), 1);
2192
            }
2193
        }
2194

2195
        if (hasIndex) {
2196
            grid.moveColumn(this, targetColumn);
2197
        }
2198

2199
        if (this.columnGroup) {
2200
            this.allChildren.forEach(child => child.unpin());
2201
        }
2202

2203
        grid.reinitPinStates();
2204
        grid.resetCaches();
2205

2206
        grid.notifyChanges();
2207
        if (this.columnLayoutChild) {
2208
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
2209
        }
2210
        this.grid.filteringService.refreshExpressions();
2211

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

2214
        return true;
2215
    }
2216

2217
    /**
2218
     * Moves a column to the specified visible index.
2219
     * If passed index is invalid, or if column would receive a different visible index after moving, moving is not performed.
2220
     * If passed index would move the column to a different column group. moving is not performed.
2221
     *
2222
     * @example
2223
     * ```typescript
2224
     * column.move(index);
2225
     * ```
2226
     * @memberof IgxColumnComponent
2227
     */
2228
    public move(index: number) {
2229
        let target;
2230
        let columns = this.grid.columns.filter(c => c.visibleIndex > -1);
2231
        // grid last visible index
2232
        const li = columns.map(c => c.visibleIndex).reduce((a, b) => Math.max(a, b));
2233
        const parent = this.parent;
2234
        const isPreceding = this.visibleIndex < index;
2235

2236
        if (index === this.visibleIndex || index < 0 || index > li) {
2237
            return;
2238
        }
2239

2240
        if (parent) {
2241
            columns = columns.filter(c => c.level >= this.level && c !== this && c.parent !== this &&
2242
                c.topLevelParent === this.topLevelParent);
2243
        }
2244
        /* eslint-disable max-len */
2245
        // 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.
2246
        // 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.
2247
        /* eslint-enable max-len */
2248
        if (isPreceding) {
2249
            columns = columns.filter(c => c.visibleIndex > this.visibleIndex);
2250
            target = columns.find(c => c.level === this.level && c.visibleIndex + (c as any).calcChildren() - this.calcChildren() === index);
2251
        } else {
2252
            columns = columns.filter(c => c.visibleIndex < this.visibleIndex);
2253
            target = columns.find(c => c.level === this.level && c.visibleIndex === index);
2254
        }
2255

2256
        if (!target || (target.pinned && this.disablePinning)) {
2257
            return;
2258
        }
2259

2260
        const pos = isPreceding ? DropPosition.AfterDropTarget : DropPosition.BeforeDropTarget;
2261
        this.grid.moveColumn(this, target as IgxColumnComponent, pos);
2262
    }
2263

2264
    /**
2265
     * No children for the column, so will returns 1 or 0, if the column is hidden.
2266
     *
2267
     * @hidden
2268
     */
2269
    public calcChildren(): number {
2270
        const children = this.hidden ? 0 : 1;
2271
        return children;
2272
    }
2273

2274
    /**
2275
     * Toggles column vibisility and emits the respective event.
2276
     *
2277
     * @hidden
2278
     */
2279
    public toggleVisibility(value?: boolean) {
2280
        const newValue = value ?? !this.hidden;
2281
        const eventArgs: IColumnVisibilityChangingEventArgs = { column: this, newValue, cancel: false };
2282
        this.grid.columnVisibilityChanging.emit(eventArgs);
2283

2284
        if (eventArgs.cancel) {
2285
            return;
2286
        }
2287
        this.hidden = newValue;
2288
        this.grid.columnVisibilityChanged.emit({ column: this, newValue });
2289
    }
2290

2291
    /**
2292
     * Returns a reference to the top level parent column.
2293
     * ```typescript
2294
     * let topLevelParent =  this.column.topLevelParent;
2295
     * ```
2296
     *
2297
     * @memberof IgxColumnComponent
2298
     */
2299
    public get topLevelParent() {
2300
        let parent = this.parent;
2301
        while (parent && parent.parent) {
2302
            parent = parent.parent;
2303
        }
2304
        return parent;
2305
    }
2306

2307
    /**
2308
     * Returns a reference to the header of the column.
2309
     * ```typescript
2310
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2311
     * let headerCell = column.headerCell;
2312
     * ```
2313
     *
2314
     * @memberof IgxColumnComponent
2315
     */
2316
    public get headerCell(): IgxGridHeaderComponent {
2317
        return this.grid.headerCellList.find((header) => header.column === this);
2318
    }
2319

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

2333
    /**
2334
     * Returns a reference to the header group of the column.
2335
     *
2336
     * @memberof IgxColumnComponent
2337
     */
2338
    public get headerGroup(): IgxGridHeaderGroupComponent {
2339
        return this.grid.headerGroupsList.find(group => group.column === this);
2340
    }
2341

2342
    /**
2343
     * Autosize the column to the longest currently visible cell value, including the header cell.
2344
     * ```typescript
2345
     * @ViewChild('grid') grid: IgxGridComponent;
2346
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2347
     * column.autosize();
2348
     * ```
2349
     *
2350
     * @memberof IgxColumnComponent
2351
     * @param byHeaderOnly Set if column should be autosized based only on the header content.
2352
     */
2353
    public autosize(byHeaderOnly = false) {
2354
        if (!this.columnGroup) {
2355
            this.width = this.getAutoSize(byHeaderOnly);
2356
            this.grid.reflow();
2357
        }
2358
    }
2359

2360
    /**
2361
     * @hidden
2362
     */
2363
    public getAutoSize(byHeader = false): string {
2364
        const size = !byHeader ? this.getLargestCellWidth() :
2365
            (Object.values(this.getHeaderCellWidths()).reduce((a, b) => a + b) + 'px');
2366
        const isPercentageWidth = this.width && typeof this.width === 'string' && this.width.indexOf('%') !== -1;
2367

2368
        let newWidth;
2369
        if (isPercentageWidth) {
2370
            const gridAvailableSize = this.grid.calcWidth;
2371
            const percentageSize = parseFloat(size) / gridAvailableSize * 100;
2372
            newWidth = percentageSize + '%';
2373
        } else {
2374
            newWidth = size;
2375
        }
2376

2377
        const maxWidth = isPercentageWidth ? this.maxWidthPercent : this.maxWidthPx;
2378
        const minWidth = isPercentageWidth ? this.minWidthPercent : this.minWidthPx;
2379
        if (this.maxWidth && (parseFloat(newWidth) > maxWidth)) {
2380
            newWidth = isPercentageWidth ? maxWidth + '%' : maxWidth + 'px';
2381
        } else if (parseFloat(newWidth) < minWidth) {
2382
            newWidth = isPercentageWidth ? minWidth + '%' : minWidth + 'px';
2383
        }
2384

2385
        return newWidth;
2386
    }
2387

2388
    /**
2389
     * @hidden
2390
     */
2391
    public getCalcWidth(): any {
2392
        if (this._calcWidth && !isNaN(this.calcPixelWidth)) {
2393
            return this._calcWidth;
2394
        }
2395
        this.cacheCalcWidth();
2396
        return this._calcWidth;
2397
    }
2398

2399

2400
    /**
2401
     * @hidden
2402
     * Returns the width and padding of a header cell.
2403
     */
2404
    public getHeaderCellWidths() {
2405
        return this.grid.getHeaderCellWidth(this.headerCell.nativeElement);
2406
    }
2407

2408
    /**
2409
     * @hidden
2410
     * Returns the size (in pixels) of the longest currently visible cell, including the header cell.
2411
     * ```typescript
2412
     * @ViewChild('grid') grid: IgxGridComponent;
2413
     *
2414
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
2415
     * let size = column.getLargestCellWidth();
2416
     * ```
2417
     * @memberof IgxColumnComponent
2418
     */
2419
    public getLargestCellWidth(): string {
2420
        const range = this.grid.document.createRange();
2421
        const largest = new Map<number, number>();
2422

2423
        if (this._cells.length > 0) {
2424
            const cellsContentWidths = [];
2425
            this._cells.forEach((cell) => cellsContentWidths.push(cell.calculateSizeToFit(range)));
2426

2427
            const index = cellsContentWidths.indexOf(Math.max(...cellsContentWidths));
2428
            const cellStyle = this.grid.document.defaultView.getComputedStyle(this._cells[index].nativeElement);
2429
            const cellPadding = parseFloat(cellStyle.paddingLeft) + parseFloat(cellStyle.paddingRight) +
2430
                parseFloat(cellStyle.borderLeftWidth) + parseFloat(cellStyle.borderRightWidth);
2431

2432
            largest.set(Math.max(...cellsContentWidths), cellPadding);
2433
        }
2434

2435
        if (this.headerCell && this.autosizeHeader) {
2436
            const headerCellWidths = this.getHeaderCellWidths();
2437
            largest.set(headerCellWidths.width, headerCellWidths.padding);
2438
        }
2439

2440
        const largestCell = Math.max(...Array.from(largest.keys()));
2441
        const width = Math.ceil(largestCell + largest.get(largestCell));
2442

2443
        if (Number.isNaN(width)) {
2444
            return this.width;
2445
        } else {
2446
            return width + 'px';
2447
        }
2448
    }
2449

2450
    /**
2451
     * @hidden
2452
     */
2453
    public getCellWidth() {
2454
        const colWidth = this.width;
2455
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
2456

2457
        if (this.columnLayoutChild) {
2458
            return '';
2459
        }
2460

2461
        if (colWidth && !isPercentageWidth) {
2462

2463
            let cellWidth = colWidth;
2464
            if (typeof cellWidth !== 'string' || cellWidth.endsWith('px') === false) {
2465
                cellWidth += 'px';
2466
            }
2467

2468
            return cellWidth;
2469
        } else {
2470
            return colWidth;
2471
        }
2472
    }
2473

2474
    /**
2475
     * @hidden
2476
     */
2477
    public populateVisibleIndexes() { }
2478

2479
    protected getColumnSizesString(children: QueryList<IgxColumnComponent>): string {
2480
        const res = this.getFilledChildColumnSizes(children);
2481
        return res.join(' ');
2482
    }
2483

2484
    /**
2485
     * @hidden
2486
     * @internal
2487
     */
2488
    protected cacheCalcWidth(): any {
2489
        const colWidth = this.width;
2490
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
2491
        const isAutoWidth = colWidth && typeof colWidth === 'string' && colWidth === 'fit-content';
2492
        if (isPercentageWidth) {
2493
            this._calcWidth = parseFloat(colWidth) / 100 * this.grid.calcWidth;
2494
        } else if (!colWidth || isAutoWidth && !this.autoSize) {
2495
            // no width
2496
            this._calcWidth = this.defaultWidth || this.grid.getPossibleColumnWidth();
2497
        } else {
2498
            this._calcWidth = this.width;
2499
        }
2500
        this.calcPixelWidth = parseFloat(this._calcWidth);
2501
    }
2502

2503
    /**
2504
     * @hidden
2505
     * @internal
2506
     */
2507
    protected setExpandCollapseState() {
2508
        this.children.filter(col => (col.visibleWhenCollapsed !== undefined)).forEach(c => {
2509
            if (!this.collapsible) {
2510
                c.hidden = this.hidden; return;
2511
            }
2512
            c.hidden = this._expanded ? c.visibleWhenCollapsed : !c.visibleWhenCollapsed;
2513
        });
2514
    }
2515
    /**
2516
     * @hidden
2517
     * @internal
2518
     */
2519
    protected checkCollapsibleState() {
2520
        if (!this.children) {
2521
            return false;
2522
        }
2523
        const cols = this.children.map(child => child.visibleWhenCollapsed);
2524
        return (cols.some(c => c === true) && cols.some(c => c === false));
2525
    }
2526

2527
    /**
2528
     * @hidden
2529
     */
2530
    public get pinnable() {
2531
        return (this.grid as any)._init || !this.pinned;
2532
    }
2533

2534
    /**
2535
     * @hidden
2536
     */
2537
    public get applySelectableClass(): boolean {
2538
        return this._applySelectableClass;
2539
    }
2540

2541
    /**
2542
     * @hidden
2543
     */
2544
    public set applySelectableClass(value: boolean) {
2545
        if (this.selectable) {
2546
            this._applySelectableClass = value;
2547
        }
2548
    }
2549
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc