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

IgniteUI / igniteui-angular / 23354069329

20 Mar 2026 05:11PM UTC coverage: 9.846% (-79.6%) from 89.462%
23354069329

Pull #17071

github

web-flow
Merge 742ad5a5c into 0018afe92
Pull Request #17071: fix(IgxGrid): Do not apply width constraint to groups.

905 of 16404 branches covered (5.52%)

Branch coverage included in aggregate %.

1 of 3 new or added lines in 1 file covered. (33.33%)

24265 existing lines in 328 files now uncovered.

3714 of 30509 relevant lines covered (12.17%)

6.21 hits per line

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

31.88
/projects/igniteui-angular/src/lib/grids/headers/grid-header.component.ts
1
import {
2
    ChangeDetectionStrategy,
3
    ChangeDetectorRef,
4
    Component,
5
    DoCheck,
6
    ElementRef,
7
    HostBinding,
8
    HostListener,
9
    Inject,
10
    Input,
11
    OnDestroy,
12
    TemplateRef,
13
    ViewChild
14
} from '@angular/core';
15
import { GridColumnDataType } from '../../data-operations/data-util';
16
import { IgxColumnResizingService } from '../resizing/resizing.service';
17
import { Subject } from 'rxjs';
18
import { ColumnType, GridType, IGX_GRID_BASE } from '../common/grid.interface';
19
import { GridSelectionMode } from '../common/enums';
20
import { SortingDirection } from '../../data-operations/sorting-strategy';
21
import { SortingIndexPipe } from './pipes';
22
import { NgTemplateOutlet, NgClass } from '@angular/common';
23
import { IgxIconComponent } from '../../icon/icon.component';
24
import { ExpressionsTreeUtil } from '../../data-operations/expressions-tree-util';
25

26
/**
27
 * @hidden
28
 */
29
@Component({
30
    changeDetection: ChangeDetectionStrategy.OnPush,
31
    selector: 'igx-grid-header',
32
    templateUrl: 'grid-header.component.html',
33
    imports: [IgxIconComponent, NgTemplateOutlet, NgClass, SortingIndexPipe]
34
})
35
export class IgxGridHeaderComponent implements DoCheck, OnDestroy {
3✔
36

37
    @Input()
38
    public column: ColumnType;
39

40
    /**
41
     * @hidden
42
     */
43
    @ViewChild('defaultESFHeaderIconTemplate', { read: TemplateRef, static: true })
44
    protected defaultESFHeaderIconTemplate: TemplateRef<any>;
45

46
    /**
47
     * @hidden
48
     */
49
    @ViewChild('defaultSortHeaderIconTemplate', { read: TemplateRef, static: true })
50
    protected defaultSortHeaderIconTemplate;
51

52
    /**
53
     * @hidden
54
     */
55
    @ViewChild('sortIconContainer', { read: ElementRef })
56
    protected sortIconContainer: ElementRef;
57

58
    @HostBinding('class.igx-grid-th--pinned')
59
    public get pinnedCss() {
60
        return this.isPinned;
56✔
61
    }
62

63
    @HostBinding('class.igx-grid-th--pinned-last')
64
    public get pinnedLastCss() {
65
        return this.isLastPinned;
56✔
66
    }
67

68
    @HostBinding('class.igx-grid-th--pinned-first')
69
    public get pinnedFirstCSS() {
70
        return this.isFirstPinned;
56✔
71
    }
72

73
    /**
74
     * Gets whether the header group is stored in the last column in the pinned area.
75
     */
76
    public get isLastPinned(): boolean {
77
        return !this.grid.hasColumnLayouts ? this.column.isLastPinned : false;
56!
78
    }
79

80
    /**
81
     * Gets whether the header group is stored in the first column of the right pinned area.
82
     */
83
    public get isFirstPinned(): boolean {
84
        return !this.grid.hasColumnLayouts ? this.column.isFirstPinned : false;
56!
85
    }
86

87
    /**
88
     * Gets whether the header group is stored in a pinned column.
89
     *
90
     * @memberof IgxGridHeaderGroupComponent
91
     */
92
    public get isPinned(): boolean {
93
        return this.column.pinned;
56✔
94
    }
95
    /**
96
     * @hidden
97
     */
98
    @Input()
99
    @HostBinding('attr.id')
100
    public id: string;
101

102
    /**
103
     * Returns the `aria-selected` of the header.
104
     */
105
    @HostBinding('attr.aria-selected')
106
    public get ariaSelected(): boolean {
107
        return this.column.selected;
56✔
108
    }
109

110
    /**
111
     * Returns the `aria-sort` of the header.
112
     */
113
    @HostBinding('attr.aria-sort')
114
    public get ariaSort() {
115
        return this.sortDirection === SortingDirection.Asc ? 'ascending'
56!
116
            : this.sortDirection === SortingDirection.Desc ? 'descending' : null;
56!
117
    }
118

119
    /**
120
     * @hidden
121
     */
122
    @HostBinding('attr.aria-colindex')
123
    public get ariaColIndx() {
124
        return this.column.index + 1;
56✔
125
    }
126

127
    /**
128
     * @hidden
129
     */
130
    @HostBinding('attr.aria-rowindex')
131
    public get ariaRowIndx() {
132
        return 1;
56✔
133
    }
134

135
    @HostBinding('class.igx-grid-th')
136
    public get columnGroupStyle() {
137
        return !this.column.columnGroup;
56✔
138
    }
139

140
    @HostBinding('class.asc')
141
    public get sortAscendingStyle() {
142
        return this.sortDirection === SortingDirection.Asc;
56✔
143
    }
144

145
    @HostBinding('class.desc')
146
    public get sortDescendingStyle() {
147
        return this.sortDirection === SortingDirection.Desc;
56✔
148
    }
149

150
    @HostBinding('class.igx-grid-th--number')
151
    public get numberStyle() {
152
        return this.column.dataType === GridColumnDataType.Number
56✔
153
            || this.column.dataType === GridColumnDataType.Currency
154
            || this.column.dataType === GridColumnDataType.Percent;
155
    }
156

157
    @HostBinding('class.igx-grid-th--sortable')
158
    public get sortableStyle() {
159
        return this.column.sortable;
56✔
160
    }
161

162
    @HostBinding('class.igx-grid-th--selectable')
163
    public get selectableStyle() {
164
        return this.selectable;
56✔
165
    }
166

167
    @HostBinding('class.igx-grid-th--filtrable')
168
    public get filterableStyle() {
169
        return this.column.filterable && this.grid.filteringService.isFilterRowVisible;
56✔
170
    }
171

172
    @HostBinding('class.igx-grid-th--sorted')
173
    public get sortedStyle() {
174
        return this.sorted;
56✔
175
    }
176

177
    @HostBinding('class.igx-grid-th--selected')
178
    public get selectedStyle() {
179
        return this.selected;
56✔
180
    }
181

182
    /**
183
     * @hidden
184
     */
185
    public get esfIconTemplate() {
UNCOV
186
        return this.grid.excelStyleHeaderIconTemplate || this.defaultESFHeaderIconTemplate;
×
187
    }
188

189
    /**
190
     * @hidden
191
     */
192
    public get sortIconTemplate() {
UNCOV
193
        if (this.sortDirection === SortingDirection.None && this.grid.sortHeaderIconTemplate) {
×
UNCOV
194
            return this.grid.sortHeaderIconTemplate;
×
UNCOV
195
        } else if (this.sortDirection === SortingDirection.Asc && this.grid.sortAscendingHeaderIconTemplate) {
×
UNCOV
196
            return this.grid.sortAscendingHeaderIconTemplate;
×
UNCOV
197
        } else if (this.sortDirection === SortingDirection.Desc && this.grid.sortDescendingHeaderIconTemplate) {
×
UNCOV
198
            return this.grid.sortDescendingHeaderIconTemplate;
×
199
        } else {
UNCOV
200
            return this.defaultSortHeaderIconTemplate;
×
201
        }
202
    }
203
    /**
204
     * @hidden
205
     */
206
    public get disabled() {
UNCOV
207
        const groupArea = this.grid.groupArea || this.grid.treeGroupArea;
×
UNCOV
208
        if (groupArea?.expressions && groupArea.expressions.length && groupArea.expressions.map(g => g.fieldName).includes(this.column.field)) {
×
UNCOV
209
            return true;
×
210
        }
UNCOV
211
        return false;
×
212
    }
213

214
    public get sorted() {
215
        return this.sortDirection !== SortingDirection.None;
56✔
216
    }
217

218
    public get filterIconClassName() {
UNCOV
219
        return this.column.filteringExpressionsTree || this.isAdvancedFilterApplied() ? 'igx-excel-filter__icon--filtered' : 'igx-excel-filter__icon';
×
220
    }
221

222
    public get selectable() {
223
        return this.grid.columnSelection !== GridSelectionMode.none &&
56!
224
            this.column.applySelectableClass &&
225
            !this.column.selected &&
226
            !this.grid.filteringService.isFilterRowVisible;
227
    }
228

229
    public get selected() {
230
        return this.column.selected
56!
231
            && (!this.grid.filteringService.isFilterRowVisible || this.grid.filteringService.filteredColumn !== this.column);
232
    }
233

234
    public get title() {
235
        return this.column.title || this.column.header || this.column.field;
56✔
236
    }
237

238
    public get nativeElement() {
UNCOV
239
        return this.ref.nativeElement;
×
240
    }
241

242
    public sortDirection = SortingDirection.None;
11✔
243
    protected _destroy$ = new Subject<boolean>();
11✔
244

245
    constructor(
246
        @Inject(IGX_GRID_BASE) public grid: GridType,
11✔
247
        public colResizingService: IgxColumnResizingService,
11✔
248
        public cdr: ChangeDetectorRef,
11✔
249
        private ref: ElementRef<HTMLElement>
11✔
250
    ) { }
251

252
    @HostListener('click', ['$event'])
253
    public onClick(event: MouseEvent) {
UNCOV
254
        if (!this.colResizingService.isColumnResizing) {
×
255

UNCOV
256
            if (this.grid.filteringService.isFilterRowVisible) {
×
UNCOV
257
                if (this.column.filterCellTemplate) {
×
UNCOV
258
                    this.grid.filteringRow.close();
×
UNCOV
259
                    return;
×
260
                }
261

UNCOV
262
                if (this.column.filterable && !this.column.columnGroup &&
×
263
                    !this.grid.filteringService.isFilterComplex(this.column.field)) {
UNCOV
264
                    this.grid.filteringService.filteredColumn = this.column;
×
265
                }
UNCOV
266
            } else if (this.grid.columnSelection !== GridSelectionMode.none && this.column.selectable) {
×
UNCOV
267
                const clearSelection = this.grid.columnSelection === GridSelectionMode.single || !event.ctrlKey;
×
UNCOV
268
                const rangeSelection = this.grid.columnSelection === GridSelectionMode.multiple && event.shiftKey;
×
269

UNCOV
270
                if (!this.column.selected || (this.grid.selectionService.getSelectedColumns().length > 1 && clearSelection)) {
×
UNCOV
271
                    this.grid.selectionService.selectColumn(this.column.field, clearSelection, rangeSelection, event);
×
272
                } else {
UNCOV
273
                    this.grid.selectionService.deselectColumn(this.column.field, event);
×
274
                }
275
            }
276
        }
UNCOV
277
        this.grid.theadRow.nativeElement.focus();
×
278
    }
279

280
    /**
281
     * @hidden
282
     */
283
    @HostListener('pointerenter')
284
    public onPinterEnter() {
UNCOV
285
        this.column.applySelectableClass = true;
×
286
    }
287

288
    /**
289
     * @hidden
290
     */
291
    @HostListener('pointerleave')
292
    public onPointerLeave() {
UNCOV
293
        this.column.applySelectableClass = false;
×
294
    }
295

296
    /**
297
     * @hidden @internal
298
     */
299
    public ngDoCheck() {
300
        this.getSortDirection();
56✔
301
        this.cdr.markForCheck();
56✔
302
    }
303

304
    /**
305
     * @hidden @internal
306
     */
307
    public ngOnDestroy(): void {
308
        this._destroy$.next(true);
11✔
309
        this._destroy$.complete();
11✔
310
    }
311

312
    /**
313
     * @hidden @internal
314
     */
315
    public onPointerDownIndicator(event) {
316
        // Stop propagation of pointer events to now allow column dragging using the header indicators.
UNCOV
317
        event.stopPropagation();
×
318
    }
319

320
    /**
321
     * @hidden @internal
322
     */
323
    public onFilteringIconClick(event) {
UNCOV
324
        event.stopPropagation();
×
UNCOV
325
        this.grid.filteringService.toggleFilterDropdown(this.nativeElement, this.column);
×
326
    }
327

328
    /**
329
     * @hidden @internal
330
     */
331
    public onSortingIconClick(event) {
UNCOV
332
        event.stopPropagation();
×
UNCOV
333
        this.triggerSort();
×
334
    }
335

336
    protected getSortDirection() {
337
        const expr = this.grid.sortingExpressions.find((x) => x.fieldName === this.column.field);
56✔
338
        this.sortDirection = expr ? expr.dir : SortingDirection.None;
56!
339
    }
340

341
    protected isAdvancedFilterApplied() {
UNCOV
342
        if (!this.grid.advancedFilteringExpressionsTree) {
×
UNCOV
343
            return false;
×
344
        }
345
        return !!ExpressionsTreeUtil.find(this.grid.advancedFilteringExpressionsTree, this.column.field);
×
346
    }
347

348
    private triggerSort() {
UNCOV
349
        const groupingExpr = this.grid.groupingExpressions ?
×
350
            this.grid.groupingExpressions.find((expr) => expr.fieldName === this.column.field) :
×
351
            this.grid.groupArea?.expressions ? this.grid.groupArea?.expressions.find((expr) => expr.fieldName === this.column.field) : null;
×
UNCOV
352
        const sortDir = groupingExpr ?
×
353
            this.sortDirection + 1 > SortingDirection.Desc ? SortingDirection.Asc : SortingDirection.Desc
×
354
            : this.sortDirection + 1 > SortingDirection.Desc ? SortingDirection.None : this.sortDirection + 1;
×
UNCOV
355
        this.sortDirection = sortDir;
×
UNCOV
356
        this.grid.sort({
×
357
            fieldName: this.column.field, dir: this.sortDirection, ignoreCase: this.column.sortingIgnoreCase,
358
            strategy: this.column.sortStrategy
359
        });
360
    }
361
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc