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

IgniteUI / igniteui-angular / 18007446973

25 Sep 2025 12:27PM UTC coverage: 91.592% (+0.01%) from 91.582%
18007446973

push

github

web-flow
Removing hardcoded values that limit widths and don't allow users to set custom styles that change size. (#16201)

13838 of 16230 branches covered (85.26%)

18 of 18 new or added lines in 6 files covered. (100.0%)

2 existing lines in 1 file now uncovered.

27790 of 30341 relevant lines covered (91.59%)

34634.99 hits per line

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

95.45
/projects/igniteui-angular/src/lib/grids/headers/grid-header-group.component.ts
1
import {
2
    ChangeDetectionStrategy,
3
    ChangeDetectorRef,
4
    Component,
5
    DoCheck,
6
    ElementRef,
7
    forwardRef,
8
    HostBinding,
9
    HostListener,
10
    Inject,
11
    Input,
12
    QueryList,
13
    ViewChild,
14
    ViewChildren
15
} from '@angular/core';
16
import { IgxFilteringService } from '../filtering/grid-filtering.service';
17
import { IgxColumnResizingService } from '../resizing/resizing.service';
18
import { IgxGridHeaderComponent } from './grid-header.component';
19
import { IgxGridFilteringCellComponent } from '../filtering/base/grid-filtering-cell.component';
20
import { ColumnType, GridType, IGX_GRID_BASE } from '../common/grid.interface';
21
import { GridSelectionMode } from '../common/enums';
22
import { PlatformUtil } from '../../core/utils';
23
import { IgxHeaderGroupStylePipe } from './pipes';
24
import { IgxResizeHandleDirective } from '../resizing/resize-handle.directive';
25
import { IgxIconComponent } from '../../icon/icon.component';
26
import { IgxColumnMovingDropDirective } from '../moving/moving.drop.directive';
27
import { IgxColumnMovingDragDirective } from '../moving/moving.drag.directive';
28
import { NgClass, NgStyle, NgTemplateOutlet } from '@angular/common';
29

30
const Z_INDEX = 9999;
3✔
31

32
/**
33
 * @hidden
34
 */
35
@Component({
36
    changeDetection: ChangeDetectionStrategy.OnPush,
37
    selector: 'igx-grid-header-group',
38
    templateUrl: './grid-header-group.component.html',
39
    imports: [NgClass, NgStyle, IgxColumnMovingDragDirective, IgxColumnMovingDropDirective, IgxIconComponent, NgTemplateOutlet, IgxGridHeaderComponent, IgxGridFilteringCellComponent, IgxResizeHandleDirective, IgxHeaderGroupStylePipe]
40
})
41
export class IgxGridHeaderGroupComponent implements DoCheck {
3✔
42

43
    @HostBinding('style.grid-row-end')
44
    public get rowEnd(): number {
45
        return this.column.rowEnd;
245,748✔
46
    }
47

48
    @HostBinding('style.grid-column-end')
49
    public get colEnd(): number {
50
        return this.column.colEnd;
245,748✔
51
    }
52

53
    @HostBinding('style.grid-row-start')
54
    public get rowStart(): number {
55
        return this.column.rowStart;
245,748✔
56
    }
57

58
    @HostBinding('style.grid-column-start')
59
    public get colStart(): number {
60
        return this.column.colStart;
245,748✔
61
    }
62

63
    @HostBinding('class.igx-grid-th--pinned')
64
    public get pinnedCss() {
65
        return this.column.pinned;
245,748✔
66
    }
67

68
    public get headerID() {
69
        return `${this.grid.id}_-1_${this.column.level}_${this.column.visibleIndex}`;
226,251✔
70
    }
71

72
    /**
73
     * Gets the column of the header group.
74
     *
75
     * @memberof IgxGridHeaderGroupComponent
76
     */
77
    @Input()
78
    public column: ColumnType;
79

80
    @HostBinding('class.igx-grid-th--active')
81
    public get active() {
82
        const node = this.grid.navigation.activeNode;
229,329✔
83
        return node && !this.column.columnGroup ?
229,329✔
84
            node.row === -1 && node.column === this.column.visibleIndex && node.level === this.column.level : false;
219,940✔
85
    }
86

87
    public get activeGroup() {
88
        const node = this.grid.navigation.activeNode;
13,743✔
89
        return node ? node.row === -1 && node.column === this.column.visibleIndex && node.level === this.column.level : false;
13,743!
90
    }
91

92
    /**
93
     * @hidden
94
     */
95
    @ViewChild(IgxGridHeaderComponent)
96
    public header: IgxGridHeaderComponent;
97

98
    /**
99
     * @hidden
100
     */
101
    @ViewChild(IgxGridFilteringCellComponent)
102
    public filter: IgxGridFilteringCellComponent;
103

104
    /**
105
     * @hidden
106
     */
107
    @ViewChildren(forwardRef(() => IgxGridHeaderGroupComponent), { read: IgxGridHeaderGroupComponent })
6✔
108
    public children: QueryList<IgxGridHeaderGroupComponent>;
109

110
    /**
111
     * Gets the width of the header group.
112
     *
113
     * @memberof IgxGridHeaderGroupComponent
114
     */
115
    public get width() {
116
        return this.grid.getHeaderGroupWidth(this.column);
8,742✔
117
    }
118

119
    @HostBinding('class.igx-grid-thead__item')
120
    public defaultCss = true;
22,537✔
121

122
    constructor(private cdr: ChangeDetectorRef,
22,537✔
123
        @Inject(IGX_GRID_BASE) public grid: GridType,
22,537✔
124
        private ref: ElementRef<HTMLElement>,
22,537✔
125
        public colResizingService: IgxColumnResizingService,
22,537✔
126
        public filteringService: IgxFilteringService,
22,537✔
127
        protected platform: PlatformUtil) { }
22,537✔
128

129
    @HostBinding('class.igx-grid__drag-col-header')
130
    public get headerDragCss() {
131
        return this.isHeaderDragged;
245,748✔
132
    }
133

134
    @HostBinding('class.igx-grid-th--filtering')
135
    public get filteringCss() {
136
        return this.isFiltered;
245,748✔
137
    }
138

139
    /**
140
     * @hidden
141
     */
142
    @HostBinding('style.z-index')
143
    public get zIndex() {
144
        if (!this.column.pinned) {
245,751✔
145
            return null;
240,880✔
146
        }
147
        return Z_INDEX - this.grid.pinnedColumns.indexOf(this.column);
4,871✔
148
    }
149

150
    /**
151
     * @hidden
152
     */
153
    public get ariaHidden(): boolean {
154
        return this.grid.hasColumnGroups && (this.column.hidden || this.grid.navigation.activeNode.row !== -1);
226,251✔
155
    }
156

157
    /**
158
     * Gets whether the header group belongs to a column that is filtered.
159
     *
160
     * @memberof IgxGridHeaderGroupComponent
161
     */
162
    public get isFiltered(): boolean {
163
        return this.filteringService.filteredColumn === this.column;
245,759✔
164
    }
165

166
    /**
167
     * Gets whether the header group is stored in the last column in the pinned area.
168
     *
169
     * @memberof IgxGridHeaderGroupComponent
170
     */
171
    public get isLastPinned(): boolean {
UNCOV
172
        return !this.grid.hasColumnLayouts ? this.column.isLastPinned : false;
×
173
    }
174

175
    /**
176
     * Gets whether the header group is stored in the first column of the right pinned area.
177
     */
178
    public get isFirstPinned(): boolean {
UNCOV
179
        return !this.grid.hasColumnLayouts ? this.column.isFirstPinned : false;
×
180
    }
181

182
    @HostBinding('style.display')
183
    public get groupDisplayStyle(): string {
184
        return this.grid.hasColumnLayouts && this.column.children ? 'flex' : '';
245,748✔
185
    }
186

187
    /**
188
     * Gets whether the header group is stored in a pinned column.
189
     *
190
     * @memberof IgxGridHeaderGroupComponent
191
     */
192
    public get isPinned(): boolean {
193
        return this.column.pinned;
25✔
194
    }
195

196
    /**
197
     * Gets whether the header group belongs to a column that is moved.
198
     *
199
     * @memberof IgxGridHeaderGroupComponent
200
     */
201
    public get isHeaderDragged(): boolean {
202
        return this.grid.columnInDrag === this.column;
245,748✔
203
    }
204

205
    /**
206
     * @hidden
207
     */
208
    public get hasLastPinnedChildColumn(): boolean {
209
        return this.column.allChildren.some(child => child.isLastPinned);
59,675✔
210
    }
211

212
    /**
213
     * @hidden
214
     */
215
    public get hasFirstPinnedChildColumn(): boolean {
216
        return this.column.allChildren.some(child => child.isFirstPinned);
56,570✔
217
    }
218

219
    /**
220
     * @hidden
221
     */
222
    public get selectable() {
223
        const selectableChildren = this.column.allChildren.filter(c => !c.hidden && c.selectable && !c.columnGroup);
45,558✔
224
        return this.grid.columnSelection !== GridSelectionMode.none &&
13,743✔
225
            this.column.applySelectableClass
226
            && !this.selected && selectableChildren.length > 0
227
            && !this.grid.filteringService.isFilterRowVisible;
228
    }
229

230
    /**
231
     * @hidden
232
     */
233
    public get selected() {
234
        return this.column.selected;
13,759✔
235
    }
236

237
    /**
238
     * @hidden
239
     */
240
    public get height() {
241
        return this.nativeElement.getBoundingClientRect().height;
12✔
242
    }
243

244
    /**
245
     * @hidden
246
     */
247
    public get title() {
248
        return this.column.title || this.column.header;
13,552✔
249
    }
250

251
    public get nativeElement() {
252
        return this.ref.nativeElement;
8,389✔
253
    }
254

255
    /**
256
     * @hidden
257
     */
258
    @HostListener('mousedown', ['$event'])
259
    public onMouseDown(event: MouseEvent): void {
260
        if (!this.grid.allowFiltering ||
53✔
261
            (event.composedPath().findIndex(el =>
262
                (el as Element).tagName?.toLowerCase() === 'igx-grid-filtering-cell') < 1)) {
116✔
263
                // Hack for preventing text selection in IE and Edge while dragging the resize element
264
                event.preventDefault();
52✔
265
        }
266
    }
267

268
    /**
269
     * @hidden
270
     */
271
    public groupClicked(event: MouseEvent): void {
272
        const columnsToSelect = this.column.allChildren.filter(c => !c.hidden && c.selectable && !c.columnGroup).map(c => c.field);
78✔
273
        if (this.grid.columnSelection !== GridSelectionMode.none
18✔
274
            && columnsToSelect.length > 0 && !this.grid.filteringService.isFilterRowVisible) {
275
            const clearSelection = this.grid.columnSelection === GridSelectionMode.single || !event.ctrlKey;
13✔
276
            const rangeSelection = this.grid.columnSelection === GridSelectionMode.multiple && event.shiftKey;
13✔
277
            if (!this.selected) {
13✔
278
                this.grid.selectionService.selectColumns(columnsToSelect, clearSelection, rangeSelection, event);
10✔
279
            } else {
280
                const selectedFields = this.grid.selectionService.getSelectedColumns();
3✔
281
                if ((selectedFields.length === columnsToSelect.length) && selectedFields.every(el => columnsToSelect.includes(el))
3✔
282
                    || !clearSelection) {
283
                    this.grid.selectionService.deselectColumns(columnsToSelect, event);
2✔
284
                } else {
285
                    this.grid.selectionService.selectColumns(columnsToSelect, clearSelection, rangeSelection, event);
1✔
286
                }
287
            }
288
        }
289
    }
290

291
    /**
292
     * @hidden @internal
293
     */
294
    public onPointerDownIndicator(event) {
295
        // Stop propagation of pointer events to now allow column dragging using the header indicators.
296
        event.stopPropagation();
×
297
    }
298

299
    /**
300
     * @hidden @internal
301
     */
302
    public toggleExpandState(event: MouseEvent): void {
303
        event.stopPropagation();
7✔
304
        this.column.expanded = !this.column.expanded;
7✔
305
    }
306

307
    /**
308
     * @hidden @internal
309
     */
310
    public pointerdown(event: PointerEvent): void {
311
        event.stopPropagation();
14✔
312
        this.activate();
14✔
313
        this.grid.theadRow.nativeElement.focus();
14✔
314
    }
315

316
    /*
317
     * This method is necessary due to some specifics related with implementation of column moving
318
     * @hidden
319
     */
320
    public activate() {
321
        this.grid.navigation.setActiveNode(this.activeNode);
95✔
322
        this.grid.theadRow.nativeElement.focus();
95✔
323
    }
324

325
    public ngDoCheck() {
326
        this.cdr.markForCheck();
245,748✔
327
    }
328
    /**
329
     * @hidden
330
     */
331
    public onPinterEnter() {
332
        this.column.applySelectableClass = true;
3✔
333
    }
334

335
    /**
336
     * @hidden
337
     */
338
    public onPointerLeave() {
339
        this.column.applySelectableClass = false;
3✔
340
    }
341

342
    protected get activeNode() {
343
        return {
95✔
344
            row: -1, column: this.column.visibleIndex, level: this.column.level,
345
            mchCache: { level: this.column.level, visibleIndex: this.column.visibleIndex },
346
            layout: this.column.columnLayoutChild ? {
95✔
347
                rowStart: this.column.rowStart,
348
                colStart: this.column.colStart,
349
                rowEnd: this.column.rowEnd,
350
                colEnd: this.column.colEnd,
351
                columnVisibleIndex: this.column.visibleIndex
352
            } : null
353
        };
354
    }
355
}
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