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

IgniteUI / igniteui-angular / 6037864297

31 Aug 2023 01:16PM CUT coverage: 92.263% (-0.003%) from 92.266%
6037864297

push

github

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

* 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

15310 of 17991 branches covered (0.0%)

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

26842 of 29093 relevant lines covered (92.26%)

29645.37 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/density';
25,895✔
33
import { IgxRowDirective } from '../row.directive';
25,895✔
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,870,662✔
37
import { IgxGridFilteringCellComponent } from '../filtering/base/grid-filtering-cell.component';
38
import { IgxGridHeaderGroupComponent } from '../headers/grid-header-group.component';
39
import {
100,673✔
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,116✔
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,794,171✔
64
/**
1,794,171✔
65
 * **Ignite UI for Angular Column** -
1,794,171✔
66
 * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid#columns-configuration)
74,022✔
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,720,149✔
69
 * filtering & editing are enabled at the column level.  You can also provide a template containing custom content inside
245,538✔
70
 * the column using `ng-template` which will be used for all cells within the column.
71
 */
72
@Component({
1,474,611✔
73
    changeDetection: ChangeDetectionStrategy.OnPush,
74
    selector: 'igx-column',
75
    template: ``,
76
    standalone: true
77
})
78
export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnType {
79
    /**
80
     * Sets/gets the `field` value.
81
     * ```typescript
82
     * let columnField = this.column.field;
83
     * ```
84
     * ```html
85
     * <igx-column [field] = "'ID'"></igx-column>
86
     * ```
87
     *
4,226✔
88
     * @memberof IgxColumnComponent
89
     */
90
    @Input()
1,830,729✔
91
    public set field(value: string) {
92
        this._field = value;
93
        this.hasNestedPath = value?.includes('.');
94
    }
95
    public get field(): string {
96
        return this._field;
97
    }
98

99

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

517
    /** @hidden @internal **/
518
    public autoSize: number;
519

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

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

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

3,859,627✔
572
    /**
380,429✔
573
     * Sets/gets the class selector of the column group header.
574
     * ```typescript
380,429✔
575
     * let columnHeaderClass = this.column.headerGroupClasses;
380,429✔
576
     * ```
380,429✔
577
     * ```html
23,419✔
578
     * <igx-column [headerGroupClasses] = "'column-group-header'"></igx-column>
579
     * ```
380,429✔
580
     *
694,970✔
581
     * @memberof IgxColumnComponent
582
     */
112,785✔
583
    @notifyChanges()
110,557✔
584
    @WatchColumnChanges()
110,557✔
585
    @Input()
586
    public headerGroupClasses = '';
110,176✔
587

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

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

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

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

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

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

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

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

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

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

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

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

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

13,060✔
909
    /** @hidden @internal **/
910
    public calcPixelWidth: number;
911

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

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

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

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

948

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

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

976
    /**
117,958✔
977
     * Gets the column index.
978
     * ```typescript
979
     * let columnIndex = this.column.index;
980
     * ```
981
     *
982
     * @memberof IgxColumnComponent
43,098✔
983
     */
984
    public get index(): number {
985
        return (this.grid as any)._columns.indexOf(this);
986
    }
4,187✔
987

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

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

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

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

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

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

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

17✔
1377

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

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

1409
        if (this.columnGroup) {
1410
            col = this.allChildren.filter(c => !c.columnGroup && !c.hidden)[0] as any;
1411
        }
1412
        if (this.columnLayoutChild) {
312,587✔
1413
            return this.parent.childrenVisibleIndexes.find(x => x.column === this).index;
301,426✔
1414
        }
1415

11,161✔
1416
        if (!this.pinned) {
11,161✔
1417
            const indexInCollection = unpinnedColumns.indexOf(col);
1418
            vIndex = indexInCollection === -1 ?
1419
                -1 :
1420
                (this.grid.isPinningToStart ?
1421
                    pinnedColumns.length + indexInCollection :
1422
                    indexInCollection);
1423
        } else {
25✔
1424
            const indexInCollection = pinnedColumns.indexOf(col);
1425
            vIndex = this.grid.isPinningToStart ?
1426
                indexInCollection :
1427
                unpinnedColumns.length + indexInCollection;
1428
        }
1429
        this._vIndex = vIndex;
1430
        return vIndex;
1431
    }
1432

1433
    /**
1434
     * Returns a boolean indicating if the column is a `ColumnGroup`.
1435
     * ```typescript
1436
     * let columnGroup =  this.column.columnGroup;
1437
     * ```
25✔
1438
     *
25✔
1439
     * @memberof IgxColumnComponent
25!
1440
     */
25✔
1441
    public get columnGroup() {
270✔
1442
        return false;
25✔
1443
    }
25✔
1444
    /**
25✔
1445
     * Returns a boolean indicating if the column is a `ColumnLayout` for multi-row layout.
1446
     * ```typescript
25✔
1447
     * let columnGroup =  this.column.columnGroup;
1448
     * ```
25✔
1449
     *
24✔
1450
     * @memberof IgxColumnComponent
24✔
1451
     */
1452
    public get columnLayout() {
25✔
1453
        return false;
25✔
1454
    }
25!
1455

×
1456
    /**
1457
     * Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
1458
     * ```typescript
25✔
1459
     * let columnLayoutChild =  this.column.columnLayoutChild;
1460
     * ```
1461
     *
1462
     * @memberof IgxColumnComponent
1463
     */
1464
    public get columnLayoutChild() {
1465
        return this.parent && this.parent.columnLayout;
1,039,561✔
1466
    }
1,039,561✔
1467

1,039,561!
1468
    /** @hidden @internal **/
×
1469
    public get allChildren(): IgxColumnComponent[] {
1470
        return [];
1,039,561✔
1471
    }
1,030,577✔
1472
    /**
1,030,577✔
1473
     * Returns the level of the column in a column group.
1,965✔
1474
     * Returns `0` if the column doesn't have a `parent`.
1475
     * ```typescript
1,030,577✔
1476
     * let columnLevel =  this.column.level;
1477
     * ```
1478
     *
8,984✔
1479
     * @memberof IgxColumnComponent
1480
     */
1481
    public get level() {
1482
        let ptr = this.parent;
1483
        let lvl = 0;
1484

1485
        while (ptr) {
1486
            lvl++;
10,688✔
1487
            ptr = ptr.parent;
10,688✔
1488
        }
1489
        return lvl;
1490
    }
1491

1492
    /** @hidden @internal **/
1493
    public get isLastPinned(): boolean {
1494
        return this.grid.isPinningToStart &&
289,039✔
1495
            this.grid.pinnedColumns[this.grid.pinnedColumns.length - 1] === this;
289,039✔
1496
    }
289,039✔
1497

289,039✔
1498
    /** @hidden @internal **/
805✔
1499
    public get isFirstPinned(): boolean {
1500
        const pinnedCols = this.grid.pinnedColumns.filter(x => !x.columnGroup);
288,234✔
1501
        return !this.grid.isPinningToStart && pinnedCols[0] === this;
1502
    }
29,295✔
1503

1504
    /** @hidden @internal **/
1505
    public get rightPinnedOffset(): string {
258,939✔
1506
        return this.pinned && !this.grid.isPinningToStart ?
1507
            - this.grid.pinnedWidth - this.grid.headerFeaturesWidth + 'px' :
289,039✔
1508
            null;
1509
    }
1510

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

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

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

1542
    /**
1543
     * @remarks
8,325✔
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
1549
     * const pipeArgs: IColumnPipeArgs = {
444✔
1550
     *      format: 'longDate',
442✔
1551
     *      timezone: 'UTC',
1552
     *      digitsInfo: '1.1-2'
1553
     * }
6✔
1554
     * ```
1555
     * ```html
1556
     * <igx-column dataType="date" [pipeArgs]="pipeArgs"></igx-column>
1557
     * <igx-column dataType="number" [pipeArgs]="pipeArgs"></igx-column>
1558
     * ```
1559
     * @memberof IgxColumnComponent
2✔
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
     *
1625
     * @memberof IgxColumnComponent
2✔
1626
     */
1627
    public get filteringExpressionsTree(): FilteringExpressionsTree {
1628
        return this.grid.filteringExpressionsTree.find(this.field) as FilteringExpressionsTree;
1629
    }
2✔
1630
    /**
1631
     * Sets/gets the parent column.
1632
     * ```typescript
1633
     * let parentColumn = this.column.parent;
2✔
1634
     * ```
1635
     * ```typescript
1636
     * this.column.parent = higherLevelColumn;
2✔
1637
     * ```
1638
     *
1639
     * @memberof IgxColumnComponent
2✔
1640
     */
1641
    public parent = null;
1642
    /**
1643
     * Sets/gets the children columns.
2✔
1644
     * ```typescript
1645
     * let columnChildren = this.column.children;
1646
     * ```
2✔
1647
     * ```typescript
1648
     * this.column.children = childrenColumns;
1649
     * ```
1650
     *
2✔
1651
     * @memberof IgxColumnComponent
1652
     */
1653
    public children: QueryList<IgxColumnComponent>;
2✔
1654
    /**
1655
     * @hidden
1656
     */
2✔
1657
    public destroy$ = new Subject<any>();
1658

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

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

2✔
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
        /** @hidden @internal **/
1772
        public cdr: ChangeDetectorRef,
1773
        protected platform: PlatformUtil,
1774
    ) {
1775
        this.validators  = _validators;
1776
     }
1777

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

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

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

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

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

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

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

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

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

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

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

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

2000
        return columnSizes;
2001
    }
2002

2003
    /** @hidden @internal **/
2004
    public getFilledChildColumnSizes(children: QueryList<IgxColumnComponent>): Array<string> {
2005
        const columnSizes = this.getInitialChildColumnSizes(children);
2006

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

2019
    /** @hidden @internal **/
2020
    public getResizableColUnderEnd(): MRLResizeColumnInfo[] {
2021
        if (this.columnLayout || !this.columnLayoutChild || this.columnGroup) {
2022
            return [{ target: this, spanUsed: 1 }];
2023
        }
2024

2025
        const columnSized = this.getInitialChildColumnSizes(this.parent.children);
2026
        const targets: MRLResizeColumnInfo[] = [];
2027
        const colEnd = this.colEnd ? this.colEnd : this.colStart + 1;
2028

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

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

2044
        return targetsSquashed;
2045
    }
2046

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

2069
        if (this.parent && !this.parent.pinned) {
2070
            return this.topLevelParent.pin(index);
2071
        }
2072

2073
        const hasIndex = index !== undefined;
2074
        if (hasIndex && (index < 0 || index > grid.pinnedColumns.length)) {
2075
            return false;
2076
        }
2077

2078
        if (!this.parent && !this.pinnable) {
2079
            return false;
2080
        }
2081

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

2087
        if (args.cancel) {
2088
            return;
2089
        }
2090

2091
        this.grid.crudService.endEdit(false);
2092

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

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

2114
            if (grid._unpinnedColumns.indexOf(this) !== -1) {
2115
                const childrenCount = this.allChildren.length;
2116
                grid._unpinnedColumns.splice(grid._unpinnedColumns.indexOf(this), 1 + childrenCount);
2117
            }
2118
        }
2119

2120
        if (hasIndex) {
2121
            index === grid._pinnedColumns.length - 1 ? 
2122
            grid._moveColumns(this, targetColumn, DropPosition.AfterDropTarget) : grid._moveColumns(this, targetColumn, DropPosition.BeforeDropTarget);
2123
        }
2124

2125
        if (this.columnGroup) {
2126
            this.allChildren.forEach(child => child.pin());
2127
            grid.reinitPinStates();
2128
        }
2129

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

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

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

2176
        const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: true, cancel: false };
2177
        this.grid.columnPin.emit(args);
2178

2179
        if (args.cancel) {
2180
            return;
2181
        }
2182

2183
        this.grid.crudService.endEdit(false);
2184

2185
        this._pinned = false;
2186
        this.pinnedChange.emit(this._pinned);
2187

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

2192
        if (!hasIndex) {
2193
            grid._unpinnedColumns.splice(index, 0, this);
2194
            if (grid._pinnedColumns.indexOf(this) !== -1) {
2195
                grid._pinnedColumns.splice(grid._pinnedColumns.indexOf(this), 1);
2196
            }
2197
        }
2198

2199
        if (hasIndex) {
2200
            grid.moveColumn(this, targetColumn);
2201
        }
2202

2203
        if (this.columnGroup) {
2204
            this.allChildren.forEach(child => child.unpin());
2205
        }
2206

2207
        grid.reinitPinStates();
2208
        grid.resetCaches();
2209

2210
        grid.notifyChanges();
2211
        if (this.columnLayoutChild) {
2212
            this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
2213
        }
2214
        this.grid.filteringService.refreshExpressions();
2215

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

2218
        return true;
2219
    }
2220

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

2240
        if (index === this.visibleIndex || index < 0 || index > li) {
2241
            return;
2242
        }
2243

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

2260
        if (!target || (target.pinned && this.disablePinning)) {
2261
            return;
2262
        }
2263

2264
        const pos = isPreceding ? DropPosition.AfterDropTarget : DropPosition.BeforeDropTarget;
2265
        this.grid.moveColumn(this, target as IgxColumnComponent, pos);
2266
    }
2267

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

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

2288
        if (eventArgs.cancel) {
2289
            return;
2290
        }
2291
        this.hidden = newValue;
2292
        this.grid.columnVisibilityChanged.emit({ column: this, newValue });
2293
    }
2294

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

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

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

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

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

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

2372
        let newWidth;
2373
        if (isPercentageWidth) {
2374
            const gridAvailableSize = this.grid.calcWidth;
2375
            const percentageSize = parseFloat(size) / gridAvailableSize * 100;
2376
            newWidth = percentageSize + '%';
2377
        } else {
2378
            newWidth = size;
2379
        }
2380

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

2389
        return newWidth;
2390
    }
2391

2392
    /**
2393
     * @hidden
2394
     */
2395
    public getCalcWidth(): any {
2396
        if (this._calcWidth && !isNaN(this.calcPixelWidth)) {
2397
            return this._calcWidth;
2398
        }
2399
        this.cacheCalcWidth();
2400
        return this._calcWidth;
2401
    }
2402

2403

2404
    /**
2405
     * @hidden
2406
     * Returns the width and padding of a header cell.
2407
     */
2408
    public getHeaderCellWidths() {
2409
        return this.grid.getHeaderCellWidth(this.headerCell.nativeElement);
2410
    }
2411

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

2427
        if (this._cells.length > 0) {
2428
            const cellsContentWidths = [];
2429
            this._cells.forEach((cell) => cellsContentWidths.push(cell.calculateSizeToFit(range)));
2430

2431
            const index = cellsContentWidths.indexOf(Math.max(...cellsContentWidths));
2432
            const cellStyle = this.grid.document.defaultView.getComputedStyle(this._cells[index].nativeElement);
2433
            const cellPadding = parseFloat(cellStyle.paddingLeft) + parseFloat(cellStyle.paddingRight) +
2434
                parseFloat(cellStyle.borderLeftWidth) + parseFloat(cellStyle.borderRightWidth);
2435

2436
            largest.set(Math.max(...cellsContentWidths), cellPadding);
2437
        }
2438

2439
        if (this.headerCell && this.autosizeHeader) {
2440
            const headerCellWidths = this.getHeaderCellWidths();
2441
            largest.set(headerCellWidths.width, headerCellWidths.padding);
2442
        }
2443

2444
        const largestCell = Math.max(...Array.from(largest.keys()));
2445
        const width = Math.ceil(largestCell + largest.get(largestCell));
2446

2447
        if (Number.isNaN(width)) {
2448
            return this.width;
2449
        } else {
2450
            return width + 'px';
2451
        }
2452
    }
2453

2454
    /**
2455
     * @hidden
2456
     */
2457
    public getCellWidth() {
2458
        const colWidth = this.width;
2459
        const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
2460

2461
        if (this.columnLayoutChild) {
2462
            return '';
2463
        }
2464

2465
        if (colWidth && !isPercentageWidth) {
2466

2467
            let cellWidth = colWidth;
2468
            if (typeof cellWidth !== 'string' || cellWidth.endsWith('px') === false) {
2469
                cellWidth += 'px';
2470
            }
2471

2472
            return cellWidth;
2473
        } else {
2474
            return colWidth;
2475
        }
2476
    }
2477

2478
    /**
2479
     * @hidden
2480
     */
2481
    public populateVisibleIndexes() { }
2482

2483
    protected getColumnSizesString(children: QueryList<IgxColumnComponent>): string {
2484
        const res = this.getFilledChildColumnSizes(children);
2485
        return res.join(' ');
2486
    }
2487

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

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

2531
    /**
2532
     * @hidden
2533
     */
2534
    public get pinnable() {
2535
        return (this.grid as any)._init || !this.pinned;
2536
    }
2537

2538
    /**
2539
     * @hidden
2540
     */
2541
    public get applySelectableClass(): boolean {
2542
        return this._applySelectableClass;
2543
    }
2544

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

© 2025 Coveralls, Inc