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

IgniteUI / igniteui-angular / 12788818376

15 Jan 2025 12:57PM CUT coverage: 91.595% (+0.003%) from 91.592%
12788818376

Pull #15226

github

web-flow
Merge 8b5559bf4 into 58936f8fc
Pull Request #15226: feat(elements-grid): Add content children ready event.

12986 of 15228 branches covered (85.28%)

26329 of 28745 relevant lines covered (91.6%)

34037.86 hits per line

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

95.72
/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-filtering.component.ts
1
import {
2
    AfterViewInit,
3
    ChangeDetectionStrategy,
4
    ChangeDetectorRef,
5
    Component,
6
    ContentChild,
7
    Directive,
8
    ElementRef,
9
    EventEmitter,
10
    forwardRef,
11
    Host,
12
    HostBinding,
13
    Inject,
14
    Input,
15
    OnDestroy,
16
    Optional,
17
    Output,
18
    TemplateRef,
19
    ViewChild,
20
    ViewRef
21
} from '@angular/core';
22
import { FilteringExpressionsTree, IFilteringExpressionsTree } from '../../../data-operations/filtering-expressions-tree';
23
import { PlatformUtil, formatDate, formatCurrency } from '../../../core/utils';
24
import { GridColumnDataType } from '../../../data-operations/data-util';
25
import { Subscription } from 'rxjs';
26
import { GridSelectionMode } from '../../common/enums';
27
import { IgxFilterItem } from '../../../data-operations/filtering-strategy';
28
import { formatNumber, formatPercent, getLocaleCurrencyCode, NgIf, NgClass, DOCUMENT } from '@angular/common';
29
import { BaseFilteringComponent } from './base-filtering.component';
30
import { ExpressionUI, FilterListItem, generateExpressionsList } from './common';
31
import { ColumnType, GridType, IGX_GRID_BASE } from '../../common/grid.interface';
32
import { IgxOverlayService } from '../../../services/overlay/overlay';
33
import { SortingDirection } from '../../../data-operations/sorting-strategy';
34
import { IgxExcelStyleSearchComponent } from './excel-style-search.component';
35
import { IgxExcelStyleConditionalFilterComponent } from './excel-style-conditional-filter.component';
36
import { IgxExcelStyleClearFiltersComponent } from './excel-style-clear-filters.component';
37
import { IgxExcelStyleSelectingComponent } from './excel-style-selecting.component';
38
import { IgxExcelStyleHidingComponent } from './excel-style-hiding.component';
39
import { IgxExcelStylePinningComponent } from './excel-style-pinning.component';
40
import { IgxExcelStyleMovingComponent } from './excel-style-moving.component';
41
import { IgxExcelStyleSortingComponent } from './excel-style-sorting.component';
42
import { IgxExcelStyleHeaderComponent } from './excel-style-header.component';
43

44
@Directive({
45
    selector: 'igx-excel-style-column-operations,[igxExcelStyleColumnOperations]',
46
    standalone: true
47
})
48
export class IgxExcelStyleColumnOperationsTemplateDirective { }
2✔
49

50
@Directive({
51
    selector: 'igx-excel-style-filter-operations,[igxExcelStyleFilterOperations]',
52
    standalone: true
53
})
54
export class IgxExcelStyleFilterOperationsTemplateDirective { }
2✔
55

56
/**
57
 * A component used for presenting Excel style filtering UI for a specific column.
58
 * It is used internally in the Grid, but could also be hosted in a container outside of it.
59
 *
60
 * Example:
61
 * ```html
62
 * <igx-grid-excel-style-filtering
63
 *     [column]="grid1.columns[0]">
64
 * </igx-grid-excel-style-filtering>
65
 * ```
66
 */
67
@Component({
68
    changeDetection: ChangeDetectionStrategy.OnPush,
69
    providers: [{ provide: BaseFilteringComponent, useExisting: forwardRef(() => IgxGridExcelStyleFilteringComponent) }],
459✔
70
    selector: 'igx-grid-excel-style-filtering',
71
    templateUrl: './excel-style-filtering.component.html',
72
    imports: [IgxExcelStyleHeaderComponent, NgIf, IgxExcelStyleSortingComponent, IgxExcelStyleMovingComponent, IgxExcelStylePinningComponent, IgxExcelStyleHidingComponent, IgxExcelStyleSelectingComponent, IgxExcelStyleClearFiltersComponent, IgxExcelStyleConditionalFilterComponent, IgxExcelStyleSearchComponent, NgClass]
73
})
74
export class IgxGridExcelStyleFilteringComponent extends BaseFilteringComponent implements AfterViewInit, OnDestroy {
2✔
75

76
    /**
77
     * @hidden @internal
78
     */
79
    @HostBinding('class.igx-excel-filter')
80
    public defaultClass = true;
460✔
81

82
    @HostBinding('class.igx-excel-filter__sizing')
83
    protected get shouldApplySizes(): boolean {
84
        return !(this._minHeight || this._maxHeight);
6,378✔
85
    }
86

87
    /**
88
     * @hidden @internal
89
     */
90
    @HostBinding('class.igx-excel-filter--inline')
91
    public inline = true;
460✔
92

93
    /**
94
     * @hidden @internal
95
     */
96
    @Output()
97
    public loadingStart = new EventEmitter();
460✔
98

99
    /**
100
     * @hidden @internal
101
     */
102
    @Output()
103
    public loadingEnd = new EventEmitter();
460✔
104

105
    /**
106
     * @hidden @internal
107
     */
108
    @Output()
109
    public initialized = new EventEmitter();
460✔
110

111
    /**
112
     * @hidden @internal
113
     */
114
    @Output()
115
    public sortingChanged = new EventEmitter();
460✔
116

117
    /**
118
     * @hidden @internal
119
     */
120
    @Output()
121
    public columnChange = new EventEmitter<ColumnType>();
460✔
122

123
    /**
124
     * @hidden @internal
125
     */
126
    @Output()
127
    public listDataLoaded = new EventEmitter();
460✔
128

129
    @ViewChild('mainDropdown', { read: ElementRef })
130
    public mainDropdown: ElementRef<HTMLElement>;
131

132
    /**
133
     * @hidden @internal
134
     */
135
    @ContentChild(IgxExcelStyleColumnOperationsTemplateDirective, { read: IgxExcelStyleColumnOperationsTemplateDirective })
136
    public excelColumnOperationsDirective: IgxExcelStyleColumnOperationsTemplateDirective;
137

138
    /**
139
     * @hidden @internal
140
     */
141
    @ContentChild(IgxExcelStyleFilterOperationsTemplateDirective, { read: IgxExcelStyleFilterOperationsTemplateDirective })
142
    public excelFilterOperationsDirective: IgxExcelStyleFilterOperationsTemplateDirective;
143

144
    /**
145
     * @hidden @internal
146
     */
147
    @ViewChild('defaultExcelColumnOperations', { read: TemplateRef, static: true })
148
    protected defaultExcelColumnOperations: TemplateRef<any>;
149

150
    /**
151
     * @hidden @internal
152
     */
153
    @ViewChild('defaultExcelFilterOperations', { read: TemplateRef, static: true })
154
    protected defaultExcelFilterOperations: TemplateRef<any>;
155

156
    /**
157
     * Sets the column.
158
     */
159
    @Input()
160
    public set column(value: ColumnType) {
161
        this._column = value;
216✔
162
        this.listData = new Array<FilterListItem>();
216✔
163
        this.columnChange.emit(this._column);
216✔
164

165
        this.subscriptions?.unsubscribe();
216✔
166

167
        if (this._column) {
216✔
168
            this.grid.filteringService.registerSVGIcons();
215✔
169
            this.init();
215✔
170
            this.sortingChanged.emit();
215✔
171

172
            this.subscriptions = this.grid.columnPin.subscribe(() => {
215✔
173
                requestAnimationFrame(() => {
6✔
174
                    if (!(this.cdr as ViewRef).destroyed) {
6✔
175
                        this.cdr.detectChanges();
6✔
176
                    }
177
                });
178
            });
179

180
            this.subscriptions.add(this.grid.columnVisibilityChanged.subscribe(() => this.detectChanges()));
215✔
181
            this.subscriptions.add(this.grid.sortingExpressionsChange.subscribe(() => this.sortingChanged.emit()));
215✔
182
            this.subscriptions.add(this.grid.filteringExpressionsTreeChange.subscribe(() => this.init()));
215✔
183
            this.subscriptions.add(this.grid.columnMovingEnd.subscribe(() => this.cdr.markForCheck()));
215✔
184
        }
185
    }
186

187
    /**
188
     * Returns the current column.
189
     */
190
    public get column(): ColumnType {
191
        return this._column;
120,895✔
192
    }
193

194
    /**
195
     * @hidden @internal
196
     */
197
    public expressionsList = new Array<ExpressionUI>();
460✔
198
    /**
199
     * @hidden @internal
200
     */
201
    public listData = new Array<FilterListItem>();
460✔
202
    /**
203
     * @hidden @internal
204
     */
205
    public uniqueValues: IgxFilterItem[] = [];
460✔
206
    /**
207
     * @hidden @internal
208
     */
209
    public overlayService: IgxOverlayService;
210
    /**
211
     * @hidden @internal
212
     */
213
    public overlayComponentId: string;
214
    /**
215
     * @hidden @internal
216
     */
217
    public isHierarchical = false;
460✔
218

219
    private _minHeight;
220

221
    /**
222
     * Gets the minimum height.
223
     *
224
     * Setting value in template:
225
     * ```ts
226
     * [minHeight]="'<number><unit (px|rem|etc..)>'"
227
     * ```
228
     *
229
     * Example for setting a value:
230
     * ```ts
231
     * [minHeight]="'700px'"
232
     * ```
233
     */
234
    @Input()
235
    public get minHeight(): string {
236
        if (this._minHeight || this._minHeight === 0) {
1,338✔
237
            return this._minHeight;
444✔
238
        }
239
    }
240

241
    /**
242
     * Sets the minimum height.
243
     */
244
    public set minHeight(value: string) {
245
        this._minHeight = value;
381✔
246
    }
247

248

249
    private _maxHeight: string;
250
    private containsNullOrEmpty = false;
460✔
251
    private selectAllSelected = true;
460✔
252
    private selectAllIndeterminate = false;
460✔
253
    private filterValues = new Set<any>();
460✔
254
    private _column: ColumnType;
255
    private subscriptions: Subscription;
256
    private _originalDisplay: string;
257

258
    /**
259
     * Gets the maximum height.
260
     *
261
     * Setting value in template:
262
     * ```ts
263
     * [maxHeight]="'<number><unit (px|rem|etc..)>'"
264
     * ```
265
     *
266
     * Example for setting a value:
267
     * ```ts
268
     * [maxHeight]="'700px'"
269
     * ```
270
     */
271
    @Input()
272
    @HostBinding('style.max-height')
273
    public get maxHeight(): string {
274
        if (this._maxHeight) {
6,378✔
275
            return this._maxHeight;
4,837✔
276
        }
277
    }
278

279
    /**
280
     * Sets the maximum height.
281
     */
282
    public set maxHeight(value: string) {
283
        this._maxHeight = value;
381✔
284
    }
285

286
    /**
287
     * @hidden @internal
288
     */
289
    public get grid(): GridType {
290
        return this.column?.grid ?? this.gridAPI;
61,779✔
291
    }
292

293
    constructor(
294
        cdr: ChangeDetectorRef,
295
        element: ElementRef<HTMLElement>,
296
        platform: PlatformUtil,
297
        @Inject(DOCUMENT)
298
        private document: any,
460✔
299
        @Host() @Optional() @Inject(IGX_GRID_BASE) protected gridAPI?: GridType,
460✔
300
    ) {
301
        super(cdr, element, platform);
460✔
302
    }
303

304
    /**
305
     * @hidden @internal
306
     */
307
    public ngOnDestroy(): void {
308
        this.subscriptions?.unsubscribe();
460✔
309
        delete this.overlayComponentId;
460✔
310
    }
311

312
    /**
313
     * @hidden @internal
314
     */
315
    public ngAfterViewInit(): void {
316
        this.computedStyles = this.document.defaultView.getComputedStyle(this.element.nativeElement);
460✔
317
    }
318

319

320
    /**
321
     * @hidden @internal
322
     */
323
    public initialize(column: ColumnType, overlayService: IgxOverlayService) {
324
        this.inline = false;
209✔
325
        this.column = column;
209✔
326
        this.overlayService = overlayService;
209✔
327
        if (this._originalDisplay) {
209!
328
            this.element.nativeElement.style.display = this._originalDisplay;
×
329
        }
330

331
        this.initialized.emit();
209✔
332
        this.subscriptions.add(this.grid.columnMoving.subscribe(() => this.closeDropdown()));
209✔
333
    }
334

335
    /**
336
     * @hidden @internal
337
     */
338
    public onPin() {
339
        this.closeDropdown();
6✔
340
        this.column.pinned = !this.column.pinned;
6✔
341
    }
342

343
    /**
344
     * @hidden @internal
345
     */
346
    public onSelect() {
347
        if (!this.column.selected) {
6✔
348
            this.grid.selectionService.selectColumn(this.column.field, this.grid.columnSelection === GridSelectionMode.single);
4✔
349
        } else {
350
            this.grid.selectionService.deselectColumn(this.column.field);
2✔
351
        }
352
        this.grid.notifyChanges();
6✔
353
    }
354

355
    /**
356
     * @hidden @internal
357
     */
358
    public columnSelectable() {
359
        return this.grid?.columnSelection !== GridSelectionMode.none && this.column?.selectable;
1,132✔
360
    }
361

362
    /**
363
     * @hidden @internal
364
     */
365
    public onHideToggle() {
366
        this.column.toggleVisibility();
3✔
367
        this.closeDropdown();
3✔
368
    }
369

370
    /**
371
     * @hidden @internal
372
     */
373
    public cancel() {
374
        if (!this.overlayComponentId) {
6!
375
            this.init();
×
376
        }
377
        this.closeDropdown();
6✔
378
    }
379

380
    /**
381
     * @hidden @internal
382
     */
383
    public closeDropdown() {
384
        if (this.overlayComponentId) {
62✔
385
            this.overlayService.hide(this.overlayComponentId);
59✔
386
            this.overlayComponentId = null;
59✔
387
        }
388
    }
389

390
    /**
391
     * @hidden @internal
392
     */
393
    public onKeyDown(eventArgs: KeyboardEvent) {
394
        if (this.platform.isFilteringKeyCombo(eventArgs)) {
6✔
395
            eventArgs.preventDefault();
3✔
396
            this.closeDropdown();
3✔
397
        }
398
        eventArgs.stopPropagation();
6✔
399
    }
400

401
    /**
402
     * @hidden @internal
403
     */
404
    public hide() {
405
        this._originalDisplay = this.computedStyles.display;
34✔
406
        this.element.nativeElement.style.display = 'none';
34✔
407
    }
408

409
    /**
410
     * @hidden @internal
411
     */
412
    public detectChanges() {
413
        this.cdr.detectChanges();
7✔
414
    }
415

416
    protected computedStyles;
417

418
    protected get size(): string {
419
        return this.computedStyles?.getPropertyValue('--component-size');
16,224✔
420
    }
421

422
    private init() {
423
        this.expressionsList = new Array<ExpressionUI>();
282✔
424
        generateExpressionsList(this.column.filteringExpressionsTree, this.grid.filteringLogic, this.expressionsList);
282✔
425
        this.populateColumnData();
282✔
426
    }
427

428
    private areExpressionsSelectable() {
429
        if (this.expressionsList.length === 1 &&
282✔
430
            (this.expressionsList[0].expression.condition.name === 'equals' ||
431
                this.expressionsList[0].expression.condition.name === 'at' ||
432
                this.expressionsList[0].expression.condition.name === 'true' ||
433
                this.expressionsList[0].expression.condition.name === 'false' ||
434
                this.expressionsList[0].expression.condition.name === 'empty' ||
435
                this.expressionsList[0].expression.condition.name === 'in')) {
436
            return true;
42✔
437
        }
438

439
        const selectableExpressionsCount = this.expressionsList.filter(exp =>
240✔
440
            (exp.beforeOperator === 1 || exp.afterOperator === 1) &&
75✔
441
            (exp.expression.condition.name === 'equals' ||
442
                exp.expression.condition.name === 'at' ||
443
                exp.expression.condition.name === 'true' ||
444
                exp.expression.condition.name === 'false' ||
445
                exp.expression.condition.name === 'empty' ||
446
                exp.expression.condition.name === 'in')).length;
447

448
        return selectableExpressionsCount === this.expressionsList.length;
240✔
449
    }
450

451
    private populateColumnData() {
452
        this.cdr.detectChanges();
282✔
453

454
        if (this.grid.uniqueColumnValuesStrategy) {
282✔
455
            this.renderColumnValuesRemotely();
14✔
456
        } else {
457
            this.renderColumnValuesFromData();
268✔
458
        }
459
    }
460

461
    private renderColumnValuesRemotely() {
462
        this.loadingStart.emit();
14✔
463
        const expressionsTree: FilteringExpressionsTree = this.getColumnFilterExpressionsTree();
14✔
464

465
        const prevColumn = this.column;
14✔
466
        this.grid.uniqueColumnValuesStrategy(this.column, expressionsTree, (values: any[]) => {
14✔
467
            if (!this.column || this.column !== prevColumn) {
14!
468
                return;
×
469
            }
470

471
            const items = values.map(v => ({
112✔
472
                value: v
473
            }));
474

475
            this.uniqueValues = this.column.sortStrategy.sort(items, 'value', SortingDirection.Asc, this.column.sortingIgnoreCase,
14✔
476
                (obj, key) => {
477
                    let resolvedValue = obj[key];
426✔
478
                    if (this.column.dataType === GridColumnDataType.Time) {
426!
479
                        resolvedValue = new Date().setHours(
×
480
                            resolvedValue.getHours(),
481
                            resolvedValue.getMinutes(),
482
                            resolvedValue.getSeconds(),
483
                            resolvedValue.getMilliseconds());
484
                    }
485

486
                    return resolvedValue;
426✔
487
                });
488

489
            this.renderValues();
14✔
490
            this.loadingEnd.emit();
14✔
491
        });
492
    }
493

494
    private renderColumnValuesFromData() {
495
        this.loadingStart.emit();
268✔
496

497
        const expressionsTree = this.getColumnFilterExpressionsTree();
268✔
498
        const promise = this.grid.filterStrategy.getFilterItems(this.column, expressionsTree);
268✔
499
        promise.then((items) => {
268✔
500
            this.isHierarchical = items.length > 0 && items.some(i => i.children && i.children.length > 0);
1,535✔
501
            this.uniqueValues = items;
268✔
502
            this.renderValues();
268✔
503
            this.loadingEnd.emit();
268✔
504
            this.sortingChanged.emit();
268✔
505
        });
506
    }
507

508
    private renderValues() {
509
        this.filterValues = this.generateFilterValues();
282✔
510
        this.generateListData();
282✔
511
        this.expressionsList.forEach(expr => {
282✔
512
            if (this.column.dataType === GridColumnDataType.String && this.column.filteringIgnoreCase
117✔
513
                && expr.expression.searchVal && expr.expression.searchVal instanceof Set) {
514
                this.modifyExpression(expr);
10✔
515
            }
516
        });
517
    }
518

519
    private generateFilterValues() {
520
        const formatValue = (value: any): any => {
282✔
521
            if (!value) return value;
192✔
522

523
            switch (this.column.dataType) {
176!
524
                case GridColumnDataType.Date:
525
                    return new Date(value).toDateString();
27✔
526
                case GridColumnDataType.DateTime:
527
                    return new Date(value).toISOString();
×
528
                case GridColumnDataType.Time:
529
                    return typeof value === 'string' ? value : new Date(value).toLocaleTimeString();
×
530
                default:
531
                    return value;
149✔
532
            }
533
        };
534

535
        const processExpression = (arr: any[], e: any): any[] => {
282✔
536
            if (e.expression.condition.name === 'in') {
117✔
537
                return [...arr, ...Array.from((e.expression.searchVal as Set<any>).values()).map(v => formatValue(v))];
102✔
538
            }
539
            return [...arr, formatValue(e.expression.searchVal)];
90✔
540
        };
541

542
        const filterValues = new Set<any>(this.expressionsList.reduce(processExpression, []));
282✔
543

544
        return filterValues;
282✔
545
    }
546

547
    private modifyExpression(expr: ExpressionUI) {
548
        const lowerCaseFilterValues = new Set(Array.from(expr.expression.searchVal).map((value: string) => value.toLowerCase()));
31✔
549

550
        this.grid.data.forEach(item => {
10✔
551
            if (lowerCaseFilterValues.has(item[this.column.field]?.toLowerCase())) {
76✔
552
                expr.expression.searchVal.add(item[this.column.field]);
30✔
553
            }
554
        });
555
    }
556

557
    private generateListData() {
558
        this.listData = new Array<FilterListItem>();
282✔
559
        const shouldUpdateSelection = this.areExpressionsSelectable();
282✔
560

561
        if (this.column.dataType === GridColumnDataType.Boolean) {
282✔
562
            this.addBooleanItems();
13✔
563
        } else {
564
            this.addItems(shouldUpdateSelection);
269✔
565
        }
566

567
        if (!this.isHierarchical && this.containsNullOrEmpty) {
282✔
568
            const blanksItem = this.generateBlanksItem(shouldUpdateSelection);
194✔
569
            this.listData.unshift(blanksItem);
194✔
570
        }
571

572
        if (this.listData.length > 0) {
282✔
573
            this.addSelectAllItem();
280✔
574
        }
575

576
        if (!(this.cdr as any).destroyed) {
282✔
577
            this.cdr.detectChanges();
238✔
578
        }
579

580
        this.listDataLoaded.emit();
282✔
581
    }
582

583
    private getColumnFilterExpressionsTree() {
584
        const gridExpressionsTree: IFilteringExpressionsTree = this.grid.filteringExpressionsTree;
282✔
585
        const expressionsTree = new FilteringExpressionsTree(gridExpressionsTree.operator, gridExpressionsTree.fieldName);
282✔
586

587
        for (const operand of gridExpressionsTree.filteringOperands) {
282✔
588
            if (operand instanceof FilteringExpressionsTree) {
99✔
589
                const columnExprTree = operand as FilteringExpressionsTree;
99✔
590
                if (columnExprTree.fieldName === this.column.field) {
99✔
591
                    continue;
80✔
592
                }
593
            }
594
            expressionsTree.filteringOperands.push(operand);
19✔
595
        }
596

597
        return expressionsTree;
282✔
598
    }
599

600
    private addBooleanItems() {
601
        this.selectAllSelected = true;
13✔
602
        this.selectAllIndeterminate = false;
13✔
603
        this.uniqueValues.forEach(element => {
13✔
604
            const value = element.value;
50✔
605
            const filterListItem = new FilterListItem();
50✔
606
            if (value !== undefined && value !== null && value !== '') {
50✔
607
                if (this.column.filteringExpressionsTree) {
25✔
608
                    if (value === true && this.expressionsList.find(exp => exp.expression.condition.name === 'true')) {
9✔
609
                        filterListItem.isSelected = true;
1✔
610
                        filterListItem.isFiltered = true;
1✔
611
                        this.selectAllIndeterminate = true;
1✔
612
                    } else if (value === false && this.expressionsList.find(exp => exp.expression.condition.name === 'false')) {
11✔
613
                        filterListItem.isSelected = true;
4✔
614
                        filterListItem.isFiltered = true;
4✔
615
                        this.selectAllIndeterminate = true;
4✔
616
                    } else {
617
                        filterListItem.isSelected = false;
4✔
618
                        filterListItem.isFiltered = false;
4✔
619
                    }
620
                } else {
621
                    filterListItem.isSelected = true;
16✔
622
                    filterListItem.isFiltered = true;
16✔
623
                }
624
                filterListItem.value = value;
25✔
625
                filterListItem.label = value ?
25✔
626
                    this.grid.resourceStrings.igx_grid_filter_true :
627
                    this.grid.resourceStrings.igx_grid_filter_false;
628
                filterListItem.indeterminate = false;
25✔
629
                this.listData.push(filterListItem);
25✔
630
            } else {
631
                this.containsNullOrEmpty = true;
25✔
632
            }
633
        });
634
    }
635

636
    private addItems(shouldUpdateSelection: boolean) {
637
        this.selectAllSelected = true;
269✔
638
        this.selectAllIndeterminate = false;
269✔
639
        this.containsNullOrEmpty = false;
269✔
640
        this.listData = this.generateFilterListItems(this.uniqueValues, shouldUpdateSelection);
269✔
641
        this.containsNullOrEmpty = this.uniqueValues.length > this.listData.length;
269✔
642
    }
643

644
    private generateFilterListItems(values: IgxFilterItem[], shouldUpdateSelection: boolean, parent?: FilterListItem) {
645
        const filterListItems = [];
2,139✔
646
        values?.forEach(element => {
2,139✔
647
            const value = element.value;
2,165✔
648
            const hasValue = value !== undefined && value !== null && value !== '';
2,165✔
649

650
            if (hasValue) {
2,165✔
651
                const filterListItem = new FilterListItem();
1,870✔
652
                filterListItem.parent = parent;
1,870✔
653
                filterListItem.value = value;
1,870✔
654
                filterListItem.label = element.label !== undefined ?
1,870✔
655
                    element.label :
656
                    this.getFilterItemLabel(value);
657
                filterListItem.indeterminate = false;
1,870✔
658
                filterListItem.isSelected = true;
1,870✔
659
                filterListItem.isFiltered = true;
1,870✔
660

661
                if (this.column.filteringExpressionsTree) {
1,870✔
662
                    filterListItem.isSelected = false;
571✔
663
                    filterListItem.isFiltered = false;
571✔
664

665
                    if (shouldUpdateSelection) {
571✔
666
                        const exprValue = this.getExpressionValue(value);
512✔
667
                        if (this.filterValues.has(exprValue)) {
512✔
668
                            filterListItem.isSelected = true;
157✔
669
                            filterListItem.isFiltered = true;
157✔
670
                        }
671
                        this.selectAllIndeterminate = true;
512✔
672
                    } else {
673
                        this.selectAllSelected = false;
59✔
674
                    }
675
                }
676

677
                filterListItem.children = this.generateFilterListItems(element.children ?? element.value?.children, shouldUpdateSelection, filterListItem);
1,870✔
678
                filterListItems.push(filterListItem);
1,870✔
679
            }
680
        });
681

682
        return filterListItems;
2,139✔
683
    }
684

685
    private addSelectAllItem() {
686
        const selectAll = new FilterListItem();
280✔
687
        selectAll.isSelected = this.selectAllSelected;
280✔
688
        selectAll.value = this.grid.resourceStrings.igx_grid_excel_select_all;
280✔
689
        selectAll.label = this.grid.resourceStrings.igx_grid_excel_select_all;
280✔
690
        selectAll.indeterminate = this.selectAllIndeterminate;
280✔
691
        selectAll.isSpecial = true;
280✔
692
        selectAll.isFiltered = this.selectAllSelected;
280✔
693
        this.listData.unshift(selectAll);
280✔
694
    }
695

696
    private generateBlanksItem(shouldUpdateSelection) {
697
        const blanks = new FilterListItem();
194✔
698
        if (this.column.filteringExpressionsTree) {
194✔
699
            if (shouldUpdateSelection) {
50✔
700
                if (this.filterValues.has(null)) {
38✔
701
                    blanks.isSelected = true;
7✔
702
                    blanks.isFiltered = true;
7✔
703
                } else {
704
                    blanks.isSelected = false;
31✔
705
                    blanks.isFiltered = false;
31✔
706
                }
707
            }
708
        } else {
709
            blanks.isSelected = true;
144✔
710
            blanks.isFiltered = true;
144✔
711
        }
712
        blanks.value = null;
194✔
713
        blanks.label = this.grid.resourceStrings.igx_grid_excel_blanks;
194✔
714
        blanks.indeterminate = false;
194✔
715
        blanks.isSpecial = true;
194✔
716
        blanks.isBlanks = true;
194✔
717

718
        return blanks;
194✔
719
    }
720

721
    private getFilterItemLabel(value: any, applyFormatter = true, data?: any) {
81✔
722
        if (this.column.formatter) {
81✔
723
            if (applyFormatter) {
24✔
724
                return this.column.formatter(value, data);
24✔
725
            }
726
            return value;
×
727
        }
728

729
        const { display, format, digitsInfo, currencyCode, timezone } = this.column.pipeArgs;
57✔
730
        const locale = this.grid.locale;
57✔
731

732
        switch (this.column.dataType) {
57!
733
            case GridColumnDataType.Date:
734
            case GridColumnDataType.DateTime:
735
            case GridColumnDataType.Time:
736
                return formatDate(value, format, locale, timezone);
24✔
737
            case GridColumnDataType.Currency:
738
                return formatCurrency(value, currencyCode || getLocaleCurrencyCode(locale), display, digitsInfo, locale);
×
739
            case GridColumnDataType.Number:
740
                return formatNumber(value, locale, digitsInfo);
21✔
741
            case GridColumnDataType.Percent:
742
                return formatPercent(value, locale, digitsInfo);
×
743
            default:
744
                return value;
12✔
745
        }
746
    }
747

748
    private getExpressionValue(value: any): string {
749
        if (this.column.dataType === GridColumnDataType.Date) {
512✔
750
            value = value ? new Date(value).toDateString() : value;
52!
751
        } else if (this.column.dataType === GridColumnDataType.DateTime) {
460!
752
            value = value ? new Date(value).toISOString() : value;
×
753
        } else if (this.column.dataType === GridColumnDataType.Time) {
460!
754
            value = value ? new Date(value).toLocaleTimeString() : value;
×
755
        }
756

757
        return value;
512✔
758
    }
759
}
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