• 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

1.27
/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')
UNCOV
38
    public cssClass = 'igx-query-builder';
×
39

40
    /**
41
     * @hidden @internal
42
     */
43
    @HostBinding('style.display')
UNCOV
44
    public display = 'block';
×
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 })
UNCOV
51
    public showEntityChangeDialog = true;
×
52

53
    /**
54
     * Gets the list of entities available for the IgxQueryBuilderComponent.
55
     *
56
     * Each entity describes a logical group of fields that can be used in queries.
57
     * An entity can optionally have child entities, allowing nested sub-queries.
58
     *
59
     * @returns An array of {@link EntityType} objects.
60
     */
61
    public get entities(): EntityType[] {
UNCOV
62
        return this._entities;
×
63
    }
64

65
    /**
66
     * Sets the list of entities for the IgxQueryBuilderComponent.
67
     * If the `expressionTree` is defined, it will be recreated with the new entities.
68
     *
69
     * Each entity should be an {@link EntityType} object describing the fields and optionally child entities.
70
     *
71
     * Example:
72
     * ```ts
73
     * [
74
     *   {
75
     *     name: 'Orders',
76
     *     fields: [{ field: 'OrderID', dataType: 'number' }],
77
     *     childEntities: [
78
     *       {
79
     *         name: 'OrderDetails',
80
     *         fields: [{ field: 'ProductID', dataType: 'number' }]
81
     *       }
82
     *     ]
83
     *   }
84
     * ]
85
     * ```
86
     *
87
     * @param entities - The array of entities to set.
88
     */
89
    @Input()
90
    public set entities(entities: EntityType[]) {
UNCOV
91
        if (entities !== this._entities) {
×
UNCOV
92
            if (entities && this.expressionTree) {
×
93
                this._expressionTree = recreateTree(this._expressionTree, entities);
×
94
            }
95
        }
UNCOV
96
        this._entities = entities;
×
97
    }
98

99
    /**
100
     * Gets the list of fields for the QueryBuilder.
101
     *
102
     * @deprecated since version 19.1.0. Use the `entities` property instead.
103
     * @hidden
104
     */
105
    public get fields(): FieldType[] {
106
        return this._fields;
×
107
    }
108

109
    /**
110
     * Sets the list of fields for the QueryBuilder.
111
     * Automatically wraps them into a single entity to maintain backward compatibility.
112
     *
113
     * @param fields - The array of fields to set.
114
     * @deprecated since version 19.1.0. Use the `entities` property instead.
115
     * @hidden
116
     */
117
    @Input()
118
    public set fields(fields: FieldType[]) {
119
        if (fields) {
×
120
            this._fields = fields;
×
121
            this.entities = [
×
122
                {
123
                    name: null,
124
                    fields: fields
125
                }
126
            ];
127
        }
128
    }
129

130
    /**
131
    * Returns the expression tree.
132
    */
133
    public get expressionTree(): IExpressionTree {
UNCOV
134
        return this._expressionTree;
×
135
    }
136

137
    /**
138
     * Sets the expression tree.
139
     */
140
    @Input()
141
    public set expressionTree(expressionTree: IExpressionTree) {
UNCOV
142
        if (expressionTree !== this._expressionTree) {
×
UNCOV
143
            if (this.entities && expressionTree) {
×
UNCOV
144
                this._expressionTree = recreateTree(expressionTree, this.entities);
×
145
            } else {
UNCOV
146
                this._expressionTree = expressionTree;
×
147
            }
148
        }
149
    }
150

151
    /**
152
     * Gets the `locale` of the query builder.
153
     * If not set, defaults to application's locale.
154
     */
155
    @Input()
156
    public locale: string;
157

158
    /**
159
     * Sets the resource strings.
160
     * By default it uses EN resources.
161
     */
162
    @Input()
163
    public set resourceStrings(value: IQueryBuilderResourceStrings) {
UNCOV
164
        this._resourceStrings = Object.assign({}, this._resourceStrings, value);
×
165
    }
166

167
    /**
168
     * Returns the resource strings.
169
     */
170
    public get resourceStrings(): IQueryBuilderResourceStrings {
UNCOV
171
        return this._resourceStrings;
×
172
    }
173

174
    /**
175
     * Disables subsequent entity changes at the root level after the initial selection.
176
     */
177
    @Input()
UNCOV
178
    public disableEntityChange = false;
×
179

180
    /**
181
     * Disables return fields changes at the root level.
182
     */
183
     @Input()
UNCOV
184
     public disableReturnFieldsChange = false;
×
185

186
    /**
187
     * Event fired as the expression tree is changed.
188
     *
189
     * ```html
190
     *  <igx-query-builder (expressionTreeChange)='onExpressionTreeChange()'></igx-query-builder>
191
     * ```
192
     */
193
    @Output()
UNCOV
194
    public expressionTreeChange = new EventEmitter<IExpressionTree>();
×
195

196
    /**
197
     * @hidden @internal
198
     */
199
    @ContentChild(IgxQueryBuilderSearchValueTemplateDirective, { read: TemplateRef })
200
    public searchValueTemplate: TemplateRef<any>;
201

202
    /**
203
     * @hidden @internal
204
     */
205
    @ViewChild(IgxQueryBuilderTreeComponent)
206
    public queryTree: IgxQueryBuilderTreeComponent;
207

UNCOV
208
    private destroy$ = new Subject<any>();
×
UNCOV
209
    private _resourceStrings = getCurrentResourceStrings(QueryBuilderResourceStringsEN);
×
210
    private _expressionTree: IExpressionTree;
211
    private _fields: FieldType[];
212
    private _entities: EntityType[];
UNCOV
213
    private _shouldEmitTreeChange = true;
×
214

UNCOV
215
    constructor(protected iconService: IgxIconService) {
×
UNCOV
216
        this.registerSVGIcons();
×
217
    }
218

219
    /**
220
     * Returns whether the expression tree can be committed in the current state.
221
     */
222
    public canCommit(): boolean {
UNCOV
223
        return this.queryTree?.canCommitCurrentState() === true;
×
224
    }
225

226
    /**
227
     * Commits the expression tree in the current state if it is valid. If not throws an exception.
228
     */
229
    public commit(): void {
UNCOV
230
        if (this.canCommit()) {
×
UNCOV
231
            this._shouldEmitTreeChange = false;
×
UNCOV
232
            this.queryTree.commitCurrentState();
×
UNCOV
233
            this._shouldEmitTreeChange = true;
×
234
        } else {
UNCOV
235
            throw new Error('Expression tree can\'t be committed in the current state. Use `canCommit` method to check if the current state is valid.');
×
236
        }
237
    }
238

239
    /**
240
     * Discards all unsaved changes to the expression tree.
241
     */
242
    public discard(): void {
UNCOV
243
        this.queryTree.cancelOperandEdit();
×
244
    }
245

246
    /**
247
     * @hidden @internal
248
     */
249
    public ngOnDestroy(): void {
UNCOV
250
        this.destroy$.next(true);
×
UNCOV
251
        this.destroy$.complete();
×
252
    }
253

254
    /**
255
     * @hidden @internal
256
     *
257
     * used by the grid
258
     */
259
    public setPickerOutlet(outlet?: IgxOverlayOutletDirective | ElementRef) {
UNCOV
260
        this.queryTree.setPickerOutlet(outlet);
×
261
    }
262

263
    /**
264
     * @hidden @internal
265
     *
266
     * used by the grid
267
     */
268
    public get isContextMenuVisible(): boolean {
269
        return this.queryTree.isContextMenuVisible;
×
270
    }
271

272
    /**
273
     * @hidden @internal
274
     *
275
     * used by the grid
276
     */
277
    public exitOperandEdit() {
UNCOV
278
        this.queryTree.exitOperandEdit();
×
279
    }
280

281
    /**
282
     * @hidden @internal
283
     *
284
     * used by the grid
285
     */
286
    public setAddButtonFocus() {
UNCOV
287
        this.queryTree.setAddButtonFocus();
×
288
    }
289

290
    public onExpressionTreeChange(tree: IExpressionTree) {
UNCOV
291
        if (tree && this.entities && tree !== this._expressionTree) {
×
UNCOV
292
            this._expressionTree = recreateTree(tree, this.entities);
×
293
        } else {
UNCOV
294
            this._expressionTree = tree;
×
295
        }
UNCOV
296
        if (this._shouldEmitTreeChange) {
×
UNCOV
297
            this.expressionTreeChange.emit(tree);
×
298
        }
299
    }
300

301
    private registerSVGIcons(): void {
UNCOV
302
        const editorIcons = editor as any[];
×
303

UNCOV
304
        editorIcons.forEach((icon) => {
×
UNCOV
305
            this.iconService.addSvgIconFromText(icon.name, icon.value, 'imx-icons');
×
UNCOV
306
            this.iconService.addIconRef(icon.name, 'default', {
×
307
                name: icon.name,
308
                family: 'imx-icons'
309
            });
310
        });
311

UNCOV
312
        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>';
×
UNCOV
313
        this.iconService.addSvgIconFromText('in', inIcon, 'imx-icons');
×
UNCOV
314
        this.iconService.addIconRef('in', 'default', {
×
315
            name: 'in',
316
            family: 'imx-icons'
317
        });
318

UNCOV
319
        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>';
×
UNCOV
320
        this.iconService.addSvgIconFromText('not-in', notInIcon, 'imx-icons');
×
UNCOV
321
        this.iconService.addIconRef('not-in', 'default', {
×
322
            name: 'not-in',
323
            family: 'imx-icons'
324
        });
325

UNCOV
326
        this.iconService.addIconRef('add', 'default', {
×
327
            name: 'add',
328
            family: 'material',
329
        });
330

UNCOV
331
        this.iconService.addIconRef('close', 'default', {
×
332
            name: 'close',
333
            family: 'material',
334
        });
335

UNCOV
336
        this.iconService.addIconRef('check', 'default', {
×
337
            name: 'check',
338
            family: 'material',
339
        });
340

UNCOV
341
        this.iconService.addIconRef('delete', 'default', {
×
342
            name: 'delete',
343
            family: 'material',
344
        });
345

UNCOV
346
        this.iconService.addIconRef('edit', 'default', {
×
347
            name: 'edit',
348
            family: 'material',
349
        });
350
    }
351
}
352

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