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

IgniteUI / igniteui-angular / 15049192859

15 May 2025 03:35PM UTC coverage: 91.662% (+0.06%) from 91.6%
15049192859

Pull #15744

github

web-flow
Fixed Pivot grid export to excel with hierarchical row dimensions. (#15802)

* fix(ExcelExport): Fixed hierarchical row dimensions export.
Pull Request #15744: Mass merging 19.2.x to master

13413 of 15685 branches covered (85.51%)

54 of 55 new or added lines in 7 files covered. (98.18%)

1 existing line in 1 file now uncovered.

26956 of 29408 relevant lines covered (91.66%)

34470.13 hits per line

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

96.1
/projects/igniteui-angular/src/lib/grids/filtering/base/grid-filtering-cell.component.ts
1
import {
2
    AfterViewInit,
3
    ChangeDetectionStrategy,
4
    ChangeDetectorRef,
5
    Component,
6
    DoCheck,
7
    ElementRef,
8
    HostBinding,
9
    Input,
10
    OnInit,
11
    TemplateRef,
12
    ViewChild
13
} from '@angular/core';
14
import { IFilteringExpression } from '../../../data-operations/filtering-expression.interface';
15
import { IgxFilteringService } from '../grid-filtering.service';
16
import { ExpressionUI } from '../excel-style/common';
17
import { IgxChipsAreaComponent } from '../../../chips/chips-area.component';
18
import { IBaseChipEventArgs, IgxChipComponent } from '../../../chips/chip.component';
19
import { ColumnType } from '../../common/grid.interface';
20
import { IgxBadgeComponent } from '../../../badge/badge.component';
21
import { NgClass, NgTemplateOutlet } from '@angular/common';
22
import { IgxPrefixDirective } from '../../../directives/prefix/prefix.directive';
23
import { IgxIconComponent } from '../../../icon/icon.component';
24
import { Size } from '../../common/enums';
25

26
/**
27
 * @hidden
28
 */
29
@Component({
30
    changeDetection: ChangeDetectionStrategy.OnPush,
31
    selector: 'igx-grid-filtering-cell',
32
    templateUrl: './grid-filtering-cell.component.html',
33
    imports: [
34
        IgxChipsAreaComponent,
35
        IgxChipComponent,
36
        IgxIconComponent,
37
        IgxPrefixDirective,
38
        NgClass,
39
        IgxBadgeComponent,
40
        NgTemplateOutlet
41
    ]
42
})
43
export class IgxGridFilteringCellComponent implements AfterViewInit, OnInit, DoCheck {
3✔
44
    @Input()
45
    public column: ColumnType;
46

47
    @ViewChild('emptyFilter', { read: TemplateRef, static: true })
48
    protected emptyFilter: TemplateRef<any>;
49

50
    @ViewChild('defaultFilter', { read: TemplateRef, static: true })
51
    protected defaultFilter: TemplateRef<any>;
52

53
    @ViewChild('complexFilter', { read: TemplateRef, static: true })
54
    protected complexFilter: TemplateRef<any>;
55

56
    @ViewChild('chipsArea', { read: IgxChipsAreaComponent })
57
    protected chipsArea: IgxChipsAreaComponent;
58

59
    @ViewChild('moreIcon', { read: ElementRef })
60
    protected moreIcon: ElementRef;
61

62
    @ViewChild('ghostChip', { read: IgxChipComponent })
63
    protected ghostChip: IgxChipComponent;
64

65
    @ViewChild('complexChip', { read: IgxChipComponent })
66
    protected complexChip: IgxChipComponent;
67

68

69
    @HostBinding('class')
70
    public get styleClasses(): string {
71
        return this.column && this.column.selected ?
35,634✔
72
            'igx-grid__filtering-cell--selected' :
73
            'igx-grid__filtering-cell';
74
    }
75

76
    public expressionsList: ExpressionUI[];
77
    public moreFiltersCount = 0;
3,236✔
78

79
    private baseClass = 'igx-grid__filtering-cell-indicator';
3,236✔
80

81
    constructor(
82
        public cdr: ChangeDetectorRef,
3,236✔
83
        public filteringService: IgxFilteringService,
3,236✔
84
    ) {
85
        this.filteringService.subscribeToEvents();
3,236✔
86
    }
87

88
    public ngOnInit(): void {
89
        this.filteringService.columnToMoreIconHidden.set(this.column.field, true);
3,236✔
90
    }
91

92
    public ngAfterViewInit(): void {
93
        this.updateFilterCellArea();
3,236✔
94
    }
95

96
    public ngDoCheck() {
97
        this.updateFilterCellArea();
35,634✔
98
    }
99

100
    /**
101
     * Returns whether a chip with a given index is visible or not.
102
     */
103
    public isChipVisible(index: number) {
104
        const expression = this.expressionsList[index];
2,219✔
105
        return !!(expression && expression.isVisible);
2,219✔
106
    }
107

108
    /**
109
     * Updates the filtering cell area.
110
     */
111
    public updateFilterCellArea() {
112
        this.expressionsList = this.filteringService.getExpressions(this.column.field);
40,495✔
113
        this.updateVisibleFilters();
40,495✔
114
    }
115

116
    public get template(): TemplateRef<any> {
117
        if (!this.column.filterable) {
40,645✔
118
            return null;
3,020✔
119
        }
120
        if (this.column.filterCellTemplate) {
37,625✔
121
            return this.column.filterCellTemplate;
140✔
122
        }
123
        const expressionTree = this.column.filteringExpressionsTree;
37,485✔
124
        if (!expressionTree || expressionTree.filteringOperands.length === 0) {
37,485✔
125
            return this.emptyFilter;
36,406✔
126
        }
127
        if (this.filteringService.isFilterComplex(this.column.field)) {
1,079!
128
            return this.complexFilter;
×
129
        }
130
        return this.defaultFilter;
1,079✔
131
    }
132

133
    /**
134
     * Gets the context passed to the filter template.
135
     *
136
     * @memberof IgxGridFilteringCellComponent
137
     */
138
    public get context() {
139
        return { $implicit: this.column, column: this.column};
40,645✔
140
    }
141

142
    /**
143
     * Chip clicked event handler.
144
     */
145
    public onChipClicked(expression?: IFilteringExpression) {
146
        if (expression) {
101✔
147
            this.expressionsList.forEach((item) => {
3✔
148
                item.isSelected = (item.expression === expression);
3✔
149
            });
150
        } else if (this.expressionsList.length > 0) {
98✔
151
            this.expressionsList.forEach((item) => {
24✔
152
                item.isSelected = false;
51✔
153
            });
154
            this.expressionsList[0].isSelected = true;
24✔
155
        }
156
        this.filteringService.grid.navigation.performHorizontalScrollToCell(this.column.visibleIndex);
101✔
157
        this.filteringService.filteredColumn = this.column;
101✔
158
        this.filteringService.isFilterRowVisible = true;
101✔
159
        this.filteringService.selectedExpression = expression;
101✔
160
    }
161

162
    /**
163
     * Chip removed event handler.
164
     */
165
    public onChipRemoved(eventArgs: IBaseChipEventArgs, item: ExpressionUI): void {
166
        const indexToRemove = this.expressionsList.indexOf(item);
7✔
167
        this.removeExpression(indexToRemove);
7✔
168
        this.filteringService.grid.theadRow.nativeElement.focus();
7✔
169
    }
170

171
    /**
172
     * Clears the filtering.
173
     */
174
    public clearFiltering(): void {
175
        this.filteringService.clearFilter(this.column.field);
6✔
176
        this.cdr.detectChanges();
6✔
177
    }
178

179
    /**
180
     * Returns the filtering indicator class.
181
     */
182
    public filteringIndicatorClass() {
183
        return {
1,079✔
184
            [this.baseClass]: !this.isMoreIconHidden(),
185
            [`${this.baseClass}--hidden`]: this.isMoreIconHidden()
186
        };
187
    }
188

189
    protected get filteringElementsSize(): Size {
190
        return this.column.grid.gridSize === Size.Large ? Size.Medium : this.column.grid.gridSize;
37,670✔
191
    }
192

193
    private removeExpression(indexToRemove: number) {
194
        if (indexToRemove === 0 && this.expressionsList.length === 1) {
7✔
195
            this.clearFiltering();
6✔
196
            return;
6✔
197
        }
198

199
        this.filteringService.removeExpression(this.column.field, indexToRemove);
1✔
200

201
        this.updateVisibleFilters();
1✔
202
        this.filteringService.filterInternal(this.column.field);
1✔
203
    }
204

205
    private isMoreIconHidden(): boolean {
206
        return this.filteringService.columnToMoreIconHidden.get(this.column.field);
2,158✔
207
    }
208

209
    private updateVisibleFilters() {
210
        this.expressionsList.forEach((ex) => ex.isVisible = true);
40,496✔
211

212
        if (this.moreIcon) {
40,496✔
213
            this.filteringService.columnToMoreIconHidden.set(this.column.field, true);
820✔
214
        }
215
        this.cdr.detectChanges();
40,496✔
216

217
        if (this.chipsArea && this.expressionsList.length > 1) {
40,496✔
218
            const areaWidth = this.chipsArea.element.nativeElement.offsetWidth;
143✔
219
            let viewWidth = 0;
143✔
220
            const chipsAreaElements = this.chipsArea.element.nativeElement.children;
143✔
221
            let visibleChipsCount = 0;
143✔
222
            const moreIconWidth = this.moreIcon.nativeElement.offsetWidth -
143✔
223
                parseInt(this.column?.grid.document.defaultView.getComputedStyle(this.moreIcon.nativeElement)['margin-left'], 10);
224

225
            for (let index = 0; index < chipsAreaElements.length - 1; index++) {
143✔
226
                if (viewWidth + chipsAreaElements[index].offsetWidth < areaWidth) {
194✔
227
                    viewWidth += chipsAreaElements[index].offsetWidth;
67✔
228
                    if (index % 2 === 0) {
67✔
229
                        visibleChipsCount++;
43✔
230
                    } else {
231
                        viewWidth += parseInt(this.column?.grid.document.defaultView.getComputedStyle(chipsAreaElements[index])['margin-left'], 10);
24✔
232
                        viewWidth += parseInt(this.column?.grid.document.defaultView.getComputedStyle(chipsAreaElements[index])['margin-right'], 10);
24✔
233
                    }
234
                } else {
235
                    if (index % 2 !== 0 && viewWidth + moreIconWidth > areaWidth) {
127!
236
                        visibleChipsCount--;
×
237
                    } else if (visibleChipsCount > 0 && viewWidth - chipsAreaElements[index - 1].offsetWidth + moreIconWidth > areaWidth) {
127!
UNCOV
238
                        visibleChipsCount--;
×
239
                    }
240
                    this.moreFiltersCount = this.expressionsList.length - visibleChipsCount;
127✔
241
                    this.filteringService.columnToMoreIconHidden.set(this.column.field, false);
127✔
242
                    break;
127✔
243
                }
244
            }
245

246
            for (let i = visibleChipsCount; i < this.expressionsList.length; i++) {
143✔
247
                this.expressionsList[i].isVisible = false;
385✔
248
            }
249
            this.cdr.detectChanges();
143✔
250
        }
251
    }
252
}
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