Skip to content

Commit e3b12b5

Browse files
committed
feat(filtering): fix selection and filtering logic buttons #5496
1 parent 735b0f8 commit e3b12b5

File tree

2 files changed

+128
-71
lines changed

2 files changed

+128
-71
lines changed

projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.html

+8-26
Original file line numberDiff line numberDiff line change
@@ -163,39 +163,21 @@ <h4 class="igx-typography__h6">
163163

164164
<div igxToggle
165165
style="display: flex; flex-flow: column; width: 200px; background-color: black; margin-left: 20px">
166-
<ng-container *ngIf="selectedGroups.length === 1">
167-
<igx-buttongroup #logicOperatorButtonGroup
168-
[displayDensity]="displayDensity"
169-
[multiSelection]="false">
170-
<button igxButton [displayDensity]="displayDensity"
171-
#andButton
172-
(keydown)="onLogicOperatorKeyDown(0)"
173-
tabindex="0"
174-
[selected]="selectedGroups[0].operator === 0"
175-
type="button"
176-
(click)="onLogicOperatorButtonClicked(0)">
177-
{{ grid.resourceStrings.igx_grid_filter_operator_and }}
178-
</button>
179-
180-
<button igxButton [displayDensity]="displayDensity"
181-
#orButton
182-
tabindex="0"
183-
(keydown)="onLogicOperatorKeyDown(1)"
184-
[selected]="selectedGroups[0].operator === 1"
185-
type="button"
186-
(click)="onLogicOperatorButtonClicked($event, 1)">
187-
{{ grid.resourceStrings.igx_grid_filter_operator_or }}
188-
</button>
166+
<ng-container *ngIf="contextualGroup">
167+
<igx-buttongroup [displayDensity]="displayDensity"
168+
[multiSelection]="false"
169+
[values]="filteringLogics"
170+
(onSelect)="selectFilteringLogic($event)">
189171
</igx-buttongroup>
190172

191-
<button igxButton="outlined" [displayDensity]="displayDensity" [disabled]="!selectedGroups[0].parent" (click)="ungroup()">
173+
<button igxButton="outlined" [displayDensity]="displayDensity" [disabled]="!contextualGroup.parent" (click)="ungroup()">
192174
Ungroup
193175
</button>
194-
<button igxButton="outlined" [displayDensity]="displayDensity" [disabled]="!selectedGroups[0].parent" (click)="deleteGroup()">
176+
<button igxButton="outlined" [displayDensity]="displayDensity" (click)="deleteGroup()">
195177
Delete
196178
</button>
197179
</ng-container>
198-
<ng-container *ngIf="selectedGroups.length !== 1 && selectedExpressions.length > 1">
180+
<ng-container *ngIf="!contextualGroup">
199181
<button igxButton="outlined" [displayDensity]="displayDensity" (click)="createAndGroup()">
200182
Create "And" Group
201183
</button>

projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.ts

+120-45
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
import { Component, Input, ViewChild, ChangeDetectorRef, ViewChildren, QueryList, ElementRef } from '@angular/core';
2-
import { PositionSettings, VerticalAlignment, HorizontalAlignment, OverlaySettings, Point } from '../../../services/overlay/utilities';
1+
import {
2+
Component, Input, ViewChild, ChangeDetectorRef, ViewChildren, QueryList, ElementRef, AfterViewInit, OnDestroy
3+
} from '@angular/core';
4+
import { VerticalAlignment, HorizontalAlignment, Point } from '../../../services/overlay/utilities';
35
import { ConnectedPositioningStrategy } from '../../../services/overlay/position/connected-positioning-strategy';
46
import { IgxFilteringService } from '../grid-filtering.service';
57
import { IgxOverlayService } from '../../../services/overlay/overlay';
6-
import { DisplayDensity } from '../../../core/displayDensity';
7-
import { IgxToggleDirective, CloseScrollStrategy } from 'igniteui-angular';
8+
import { IgxToggleDirective, CloseScrollStrategy, IButtonGroupEventArgs } from 'igniteui-angular';
89
import { IgxGridBaseComponent, IgxColumnComponent } from '../../grid';
910
import { FilteringExpressionsTree, IFilteringExpressionsTree } from '../../../data-operations/filtering-expressions-tree';
1011
import { FilteringLogic, IFilteringExpression } from '../../../data-operations/filtering-expression.interface';
1112
import { IgxStringFilteringOperand } from '../../../data-operations/filtering-condition';
1213
import { IgxChipComponent } from '../../../chips';
1314
import { IgxSelectComponent } from '../../../select';
15+
import { takeUntil } from 'rxjs/operators';
16+
import { Subject } from 'rxjs';
1417

1518
class ExpressionItem {
1619
constructor(parent?: ExpressionGroupItem) {
@@ -46,7 +49,7 @@ class ExpressionOperandItem extends ExpressionItem {
4649
selector: 'igx-advanced-filtering-dialog',
4750
templateUrl: './advanced-filtering-dialog.component.html'
4851
})
49-
export class IgxAdvancedFilteringDialogComponent {
52+
export class IgxAdvancedFilteringDialogComponent implements AfterViewInit, OnDestroy {
5053
@Input()
5154
public filteringService: IgxFilteringService;
5255

@@ -68,6 +71,10 @@ export class IgxAdvancedFilteringDialogComponent {
6871

6972
public addModeExpression: ExpressionOperandItem;
7073

74+
public contextualGroup: ExpressionGroupItem;
75+
76+
public filteringLogics;
77+
7178
public selectedCondition: string;
7279
public searchValue: string;
7380

@@ -97,13 +104,25 @@ export class IgxAdvancedFilteringDialogComponent {
97104
@ViewChildren(IgxChipComponent)
98105
public chips: QueryList<IgxChipComponent>;
99106

107+
private destroy$ = new Subject<any>();
100108
private _selectedColumn: IgxColumnComponent;
101109
private _clickTimer;
102110
private _dblClickDelay = 200;
103111
private _preventChipClick = false;
104112

105113
constructor(public cdr: ChangeDetectorRef) { }
106114

115+
public ngAfterViewInit(): void {
116+
this.contextMenuToggle.onClosed.pipe(takeUntil(this.destroy$)).subscribe((args) => {
117+
this.contextualGroup = null;
118+
});
119+
}
120+
121+
public ngOnDestroy(): void {
122+
this.destroy$.next(true);
123+
this.destroy$.complete();
124+
}
125+
107126
public get displayDensity() {
108127
return this.grid.displayDensity;
109128
}
@@ -271,7 +290,7 @@ export class IgxAdvancedFilteringDialogComponent {
271290
public onChipClick(expressionItem: ExpressionOperandItem) {
272291
this._clickTimer = setTimeout(() => {
273292
if (!this._preventChipClick) {
274-
this.toggleExpression(expressionItem);
293+
this.onToggleExpression(expressionItem);
275294
}
276295
this._preventChipClick = false;
277296
}, this._dblClickDelay);
@@ -311,6 +330,11 @@ export class IgxAdvancedFilteringDialogComponent {
311330
}
312331

313332
private clearSelection() {
333+
for (const group of this.selectedGroups) {
334+
group.selected = false;
335+
}
336+
this.selectedGroups = [];
337+
314338
for (const expr of this.selectedExpressions) {
315339
expr.selected = false;
316340
}
@@ -325,22 +349,44 @@ export class IgxAdvancedFilteringDialogComponent {
325349
this.toggleExpression(expressionItem);
326350
}
327351

328-
private toggleExpression(expressionItem: ExpressionOperandItem) {
352+
private onToggleExpression(expressionItem: ExpressionOperandItem) {
329353
this.exitOperandEdit();
354+
this.toggleExpression(expressionItem);
355+
356+
this.toggleContextMenu();
357+
}
358+
359+
private toggleExpression(expressionItem: ExpressionOperandItem) {
330360
expressionItem.selected = !expressionItem.selected;
331361

332362
if (expressionItem.selected) {
333363
this.selectedExpressions.push(expressionItem);
334364
} else {
335365
const index = this.selectedExpressions.indexOf(expressionItem);
336366
this.selectedExpressions.splice(index, 1);
367+
this.deselectParentRecursive(expressionItem);
337368
}
338-
339-
this.toggleContextMenu();
340369
}
341370

342371
private toggleContextMenu() {
343-
if (this.selectedExpressions.length > 1) {
372+
const contextualGroup = this.findSingleSelectedGroup();
373+
374+
if (contextualGroup || this.selectedExpressions.length > 1) {
375+
this.contextualGroup = contextualGroup;
376+
377+
if (contextualGroup) {
378+
this.filteringLogics = [
379+
{
380+
label: this.grid.resourceStrings.igx_grid_filter_operator_and,
381+
selected: contextualGroup.operator === FilteringLogic.And
382+
},
383+
{
384+
label: this.grid.resourceStrings.igx_grid_filter_operator_or,
385+
selected: contextualGroup.operator === FilteringLogic.Or
386+
}
387+
];
388+
}
389+
344390
setTimeout(() => {
345391
const chips = this.chips.filter(c => this.selectedExpressions.includes(c.data));
346392
const minTop = chips.reduce((t, c) =>
@@ -350,16 +396,40 @@ export class IgxAdvancedFilteringDialogComponent {
350396
this._overlaySettings.positionStrategy.settings.target = new Point(maxRight, minTop);
351397

352398
if (this.contextMenuToggle.collapsed) {
353-
this.contextMenuToggle.open(this._overlaySettings);
399+
this.contextMenuToggle.open(this._overlaySettings);
354400
} else {
355-
this.contextMenuToggle.reposition();
401+
this.contextMenuToggle.reposition();
356402
}
357403
}, 200);
358404
} else {
359405
this.contextMenuToggle.close();
360406
}
361407
}
362408

409+
private findSingleSelectedGroup(): ExpressionGroupItem {
410+
for (const group of this.selectedGroups) {
411+
const containsAllSelectedExpressions = this.selectedExpressions.every(op => this.isInsideGroup(op, group));
412+
413+
if (containsAllSelectedExpressions) {
414+
return group;
415+
}
416+
}
417+
418+
return null;
419+
}
420+
421+
private isInsideGroup(item: ExpressionItem, group: ExpressionGroupItem): boolean {
422+
if (!item) {
423+
return false;
424+
}
425+
426+
if (item.parent === group) {
427+
return true;
428+
}
429+
430+
return this.isInsideGroup(item.parent, group);
431+
}
432+
363433
private deleteItem(expressionItem: ExpressionItem) {
364434
if (!expressionItem.parent) {
365435
this.rootGroup = null;
@@ -420,45 +490,51 @@ export class IgxAdvancedFilteringDialogComponent {
420490

421491
private toggleGroup(groupItem: ExpressionGroupItem) {
422492
this.exitOperandEdit();
423-
groupItem.selected = !groupItem.selected;
424-
425-
if (groupItem.selected) {
426-
this.selectedGroups.push(groupItem);
427-
} else {
428-
const index = this.selectedGroups.indexOf(groupItem);
429-
this.selectedGroups.splice(index, 1);
493+
this.toggleGroupRecursive(groupItem, !groupItem.selected);
494+
if (!groupItem.selected) {
495+
this.deselectParentRecursive(groupItem);
430496
}
497+
this.toggleContextMenu();
498+
}
431499

432-
this.clearSelection();
500+
private toggleGroupRecursive(groupItem: ExpressionGroupItem, selected: boolean) {
501+
if (groupItem.selected !== selected) {
502+
groupItem.selected = selected;
433503

434-
for (const group of this.selectedGroups) {
435-
this.selectGroupRecursive(group);
504+
if (groupItem.selected) {
505+
this.selectedGroups.push(groupItem);
506+
} else {
507+
const index = this.selectedGroups.indexOf(groupItem);
508+
this.selectedGroups.splice(index, 1);
509+
}
436510
}
437511

438-
this.toggleContextMenu();
439-
}
440-
441-
private selectGroupRecursive(group: ExpressionGroupItem) {
442-
for (const expr of group.children) {
512+
for (const expr of groupItem.children) {
443513
if (expr instanceof ExpressionGroupItem) {
444-
if (!expr.selected) {
445-
expr.selected = true;
446-
}
447-
if (!this.selectedGroups.includes(expr)) {
448-
this.selectedGroups.push(expr);
449-
}
450-
this.selectGroupRecursive(expr);
514+
this.toggleGroupRecursive(expr, selected);
451515
} else {
452-
const operandItem = expr as ExpressionOperandItem;
453-
if (!operandItem.selected) {
454-
this.toggleExpression(operandItem);
516+
const operandExpression = expr as ExpressionOperandItem;
517+
if (operandExpression.selected !== selected) {
518+
this.toggleExpression(operandExpression);
455519
}
456520
}
457521
}
458522
}
459523

524+
private deselectParentRecursive(expressionItem: ExpressionItem) {
525+
const parent = expressionItem.parent;
526+
if (parent) {
527+
if (parent.selected) {
528+
parent.selected = false;
529+
const index = this.selectedGroups.indexOf(parent);
530+
this.selectedGroups.splice(index, 1);
531+
}
532+
this.deselectParentRecursive(parent);
533+
}
534+
}
535+
460536
public ungroup() {
461-
const selectedGroup = this.selectedGroups[0];
537+
const selectedGroup = this.contextualGroup;
462538
const parent = selectedGroup.parent;
463539
if (parent) {
464540
const index = parent.children.indexOf(selectedGroup);
@@ -469,25 +545,24 @@ export class IgxAdvancedFilteringDialogComponent {
469545
}
470546
}
471547

472-
this.selectedGroups = [];
473548
this.clearSelection();
474-
this.toggleContextMenu();
475549
}
476550

477551
public deleteGroup() {
478-
const selectedGroup = this.selectedGroups[0];
552+
const selectedGroup = this.contextualGroup;
479553
const parent = selectedGroup.parent;
480554
if (parent) {
481555
const index = parent.children.indexOf(selectedGroup);
482556
parent.children.splice(index, 1);
557+
} else {
558+
this.rootGroup = null;
483559
}
484-
this.selectedGroups = [];
560+
485561
this.clearSelection();
486-
this.toggleContextMenu();
487562
}
488563

489-
public onLogicOperatorButtonClicked(operator: FilteringLogic) {
490-
this.selectedGroups[0].operator = operator;
564+
public selectFilteringLogic(event: IButtonGroupEventArgs) {
565+
this.contextualGroup.operator = event.index as FilteringLogic;
491566
}
492567

493568
public initialize(filteringService: IgxFilteringService, overlayService: IgxOverlayService,

0 commit comments

Comments
 (0)