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

IgniteUI / igniteui-angular / 14462405496

15 Apr 2025 06:03AM UTC coverage: 91.612% (+0.01%) from 91.601%
14462405496

Pull #15562

github

web-flow
Merge 49a186823 into 044db8746
Pull Request #15562: feat(h-grid): add support for advanced filtering

13408 of 15682 branches covered (85.5%)

85 of 90 new or added lines in 6 files covered. (94.44%)

1 existing line in 1 file now uncovered.

26998 of 29470 relevant lines covered (91.61%)

34175.5 hits per line

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

90.16
/projects/igniteui-angular/src/lib/query-builder/query-builder.component.ts
1
import { booleanAttribute, ContentChild, EventEmitter, Output, TemplateRef } from '@angular/core';
2
import {
3
    Component, Input, ViewChild, ElementRef, OnDestroy, HostBinding
4
} from '@angular/core';
5
import { Subject } from 'rxjs';
6
import { IQueryBuilderResourceStrings, QueryBuilderResourceStringsEN } from '../core/i18n/query-builder-resources';
7
import { IExpressionTree } from '../data-operations/filtering-expressions-tree';
8
import { IgxOverlayOutletDirective } from '../directives/toggle/toggle.directive';
9
import { EntityType, FieldType } from '../grids/common/grid.interface';
10
import { getCurrentResourceStrings } from '../core/i18n/resources';
11
import { IgxQueryBuilderTreeComponent } from './query-builder-tree.component';
12
import { IgxIconService } from '../icon/icon.service';
13
import { editor } from '@igniteui/material-icons-extended';
14
import { IgxQueryBuilderSearchValueTemplateDirective } from './query-builder.directives';
15
import { recreateTree } from '../data-operations/expressions-tree-util';
16

17
/**
18
 * A component used for operating with complex filters by creating or editing conditions
19
 * and grouping them using AND/OR logic.
20
 * It is used internally in the Advanced Filtering of the Grid.
21
 *
22
 * @example
23
 * ```html
24
 * <igx-query-builder [entities]="this.entities">
25
 * </igx-query-builder>
26
 * ```
27
 */
28
@Component({
29
    selector: 'igx-query-builder',
30
    templateUrl: './query-builder.component.html',
31
    imports: [IgxQueryBuilderTreeComponent]
32
})
33
export class IgxQueryBuilderComponent implements OnDestroy {
3✔
34
    /**
35
     * @hidden @internal
36
     */
37
    @HostBinding('class.igx-query-builder')
38
    public cssClass = 'igx-query-builder';
154✔
39

40
    /**
41
     * @hidden @internal
42
     */
43
    @HostBinding('style.display')
44
    public display = 'block';
154✔
45

46
    /**
47
     * Gets/sets whether the confirmation dialog should be shown when changing entity.
48
     * Default value is `true`.
49
     */
50
    @Input({ transform: booleanAttribute })
51
    public showEntityChangeDialog = true;
154✔
52

53
    /**
54
     * Returns the entities.
55
     * @hidden
56
     */
57
    public get entities(): EntityType[] {
58
        return this._entities;
39,412✔
59
    }
60

61
    /**
62
     * Sets the entities.
63
     * @hidden
64
     */
65
    @Input()
66
    public set entities(entities: EntityType[]) {
67
        if (entities !== this._entities) {
154✔
68
            if (entities && this.expressionTree) {
154!
UNCOV
69
                this._expressionTree = recreateTree(this._expressionTree, entities);
×
70
            }
71
        }
72
        this._entities = entities;
154✔
73
    }
74

75
    /**
76
     * Returns the fields.
77
     * @hidden
78
     * @deprecated in version 19.1.0. Use the `entities` property instead.
79
     */
80
    public get fields(): FieldType[] {
81
        return this._fields;
×
82
    }
83

84
    /**
85
     * Sets the fields.
86
     * @hidden
87
     * @deprecated in version 19.1.0. Use the `entities` property instead.
88
     */
89
    @Input()
90
    public set fields(fields: FieldType[]) {
91
        if (fields) {
×
92
            this._fields = fields;
×
93
            this.entities = [
×
94
                {
95
                    name: null,
96
                    fields: fields
97
                }
98
            ];
99
        }
100
    }
101

102
    /**
103
    * Returns the expression tree.
104
    */
105
    public get expressionTree(): IExpressionTree {
106
        return this._expressionTree;
5,457✔
107
    }
108

109
    /**
110
     * Sets the expression tree.
111
     */
112
    @Input()
113
    public set expressionTree(expressionTree: IExpressionTree) {
114
        if (expressionTree !== this._expressionTree) {
136✔
115
            if (this.entities && expressionTree) {
90✔
116
                this._expressionTree = recreateTree(expressionTree, this.entities);
84✔
117
            } else {
118
                this._expressionTree = expressionTree;
6✔
119
            }
120
        }
121
    }
122

123
    /**
124
     * Gets the `locale` of the query builder.
125
     * If not set, defaults to application's locale.
126
     */
127
    @Input()
128
    public locale: string;
129

130
    /**
131
     * Sets the resource strings.
132
     * By default it uses EN resources.
133
     */
134
    @Input()
135
    public set resourceStrings(value: IQueryBuilderResourceStrings) {
136
        this._resourceStrings = Object.assign({}, this._resourceStrings, value);
1✔
137
    }
138

139
    /**
140
     * Returns the resource strings.
141
     */
142
    public get resourceStrings(): IQueryBuilderResourceStrings {
143
        return this._resourceStrings;
5,257✔
144
    }
145

146
    /**
147
     * Disables subsequent entity changes at the root level after the initial selection.
148
     */
149
    @Input()
150
    public disableEntityChange = false;
154✔
151

152
    /**
153
     * Disables return fields changes at the root level.
154
     */
155
     @Input()
156
     public disableReturnFieldsChange = false;
154✔
157

158
    /**
159
     * Event fired as the expression tree is changed.
160
     *
161
     * ```html
162
     *  <igx-query-builder (expressionTreeChange)='onExpressionTreeChange()'></igx-query-builder>
163
     * ```
164
     */
165
    @Output()
166
    public expressionTreeChange = new EventEmitter<IExpressionTree>();
154✔
167

168
    /**
169
     * @hidden @internal
170
     */
171
    @ContentChild(IgxQueryBuilderSearchValueTemplateDirective, { read: TemplateRef })
172
    public searchValueTemplate: TemplateRef<any>;
173

174
    /**
175
     * @hidden @internal
176
     */
177
    @ViewChild(IgxQueryBuilderTreeComponent)
178
    public queryTree: IgxQueryBuilderTreeComponent;
179

180
    private destroy$ = new Subject<any>();
154✔
181
    private _resourceStrings = getCurrentResourceStrings(QueryBuilderResourceStringsEN);
154✔
182
    private _expressionTree: IExpressionTree;
183
    private _fields: FieldType[];
184
    private _entities: EntityType[];
185
    private _shouldEmitTreeChange = true;
154✔
186

187
    constructor(protected iconService: IgxIconService) {
154✔
188
        this.registerSVGIcons();
154✔
189
    }
190

191
    /**
192
     * Returns whether the expression tree can be committed in the current state.
193
     */
194
    public canCommit(): boolean {
195
        return this.queryTree?.canCommitCurrentState() === true;
28✔
196
    }
197

198
    /**
199
     * Commits the expression tree in the current state if it is valid. If not throws an exception.
200
     */
201
    public commit(): void {
202
        if (this.canCommit()) {
3✔
203
            this._shouldEmitTreeChange = false;
2✔
204
            this.queryTree.commitCurrentState();
2✔
205
            this._shouldEmitTreeChange = true;
2✔
206
        } else {
207
            throw new Error('Expression tree can\'t be committed in the current state. Use `canCommit` method to check if the current state is valid.');
1✔
208
        }
209
    }
210

211
    /**
212
     * Discards all unsaved changes to the expression tree.
213
     */
214
    public discard(): void {
215
        this.queryTree.cancelOperandEdit();
5✔
216
    }
217

218
    /**
219
     * @hidden @internal
220
     */
221
    public ngOnDestroy(): void {
222
        this.destroy$.next(true);
154✔
223
        this.destroy$.complete();
154✔
224
    }
225

226
    /**
227
     * @hidden @internal
228
     *
229
     * used by the grid
230
     */
231
    public setPickerOutlet(outlet?: IgxOverlayOutletDirective | ElementRef) {
232
        this.queryTree.setPickerOutlet(outlet);
53✔
233
    }
234

235
    /**
236
     * @hidden @internal
237
     *
238
     * used by the grid
239
     */
240
    public get isContextMenuVisible(): boolean {
241
        return this.queryTree.isContextMenuVisible;
×
242
    }
243

244
    /**
245
     * @hidden @internal
246
     *
247
     * used by the grid
248
     */
249
    public exitOperandEdit() {
250
        this.queryTree.exitOperandEdit();
20✔
251
    }
252

253
    /**
254
     * @hidden @internal
255
     *
256
     * used by the grid
257
     */
258
    public setAddButtonFocus() {
259
        this.queryTree.setAddButtonFocus();
48✔
260
    }
261

262
    public onExpressionTreeChange(tree: IExpressionTree) {
263
        if (tree && this.entities && tree !== this._expressionTree) {
129✔
264
            this._expressionTree = recreateTree(tree, this.entities);
111✔
265
        } else {
266
            this._expressionTree = tree;
18✔
267
        }
268
        if (this._shouldEmitTreeChange) {
129✔
269
            this.expressionTreeChange.emit(tree);
127✔
270
        }
271
    }
272

273
    private registerSVGIcons(): void {
274
        const editorIcons = editor as any[];
154✔
275

276
        editorIcons.forEach((icon) => {
154✔
277
            this.iconService.addSvgIconFromText(icon.name, icon.value, 'imx-icons');
9,240✔
278
            this.iconService.addIconRef(icon.name, 'default', {
9,240✔
279
                name: icon.name,
280
                family: 'imx-icons'
281
            });
282
        });
283

284
        const inIcon = '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M560-280H120v-400h720v120h-80v-40H200v240h360v80Zm-360-80v-240 240Zm560 200v-120H640v-80h120v-120h80v120h120v80H840v120h-80Z"/></svg>';
154✔
285
        this.iconService.addSvgIconFromText('in', inIcon, 'imx-icons');
154✔
286
        this.iconService.addIconRef('in', 'default', {
154✔
287
            name: 'in',
288
            family: 'imx-icons'
289
        });
290

291
        const notInIcon = '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M560-280H120v-400h720v120h-80v-40H200v240h360v80Zm-360-80v-240 240Zm440 104 84-84-84-84 56-56 84 84 84-84 56 56-83 84 83 84-56 56-84-83-84 83-56-56Z"/></svg>';
154✔
292
        this.iconService.addSvgIconFromText('not-in', notInIcon, 'imx-icons');
154✔
293
        this.iconService.addIconRef('not-in', 'default', {
154✔
294
            name: 'not-in',
295
            family: 'imx-icons'
296
        });
297

298
        this.iconService.addIconRef('add', 'default', {
154✔
299
            name: 'add',
300
            family: 'material',
301
        });
302

303
        this.iconService.addIconRef('close', 'default', {
154✔
304
            name: 'close',
305
            family: 'material',
306
        });
307

308
        this.iconService.addIconRef('check', 'default', {
154✔
309
            name: 'check',
310
            family: 'material',
311
        });
312

313
        this.iconService.addIconRef('delete', 'default', {
154✔
314
            name: 'delete',
315
            family: 'material',
316
        });
317

318
        this.iconService.addIconRef('edit', 'default', {
154✔
319
            name: 'edit',
320
            family: 'material',
321
        });
322
    }
323
}
324

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