Skip to content

Commit c90d675

Browse files
authored
Merge pull request #17146 from IgniteUI/esf-percent-search-21-1-x
fix(grid): ESF search matches numeric values without locale formatting (#17131)
2 parents c4af92a + 144354e commit c90d675

File tree

9 files changed

+215
-128
lines changed

9 files changed

+215
-128
lines changed

projects/igniteui-angular/grids/core/src/filtering/excel-style/excel-style-search.component.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -482,17 +482,26 @@ export class IgxExcelStyleSearchComponent implements AfterViewInit, OnDestroy {
482482
const matchedData = cloneHierarchicalArray(this.esf.listData, 'children');
483483
this.displayedListData = this.hierarchicalSelectMatches(matchedData, searchVal);
484484
this.cdr.detectChanges();
485+
/**
486+
* There are two calls of `matchesNumericValue` in this method: one when we generate the displayedListData in hierarchicalSelectMatches method
487+
* and another one when going through the tree nodes. We can avoid the second call by storing the items in a set.
488+
* However, if the datasource is small there is no significant difference in performance but we would be adding extra memory overhead.
489+
* We should test this when https://github.com/IgniteUI/igniteui-angular/issues/17144 issue is fixed with 100k or 1m records
490+
*/
485491
this.tree.nodes.forEach(n => {
486492
n.selected = true;
487-
if ((n.data as FilterListItem).label.toString().toLowerCase().indexOf(searchVal) > -1) {
493+
const item = n.data as FilterListItem;
494+
if (item.label.toString().toLowerCase().indexOf(searchVal) > -1 ||
495+
this.matchesNumericValue(item, searchVal)) {
488496
this.expandAllParentNodes(n);
489497
}
490498
});
491499
} else {
492500
this.displayedListData = this.esf.listData.filter((it, i) => (i === 0 && it.isSpecial) ||
493501
(it.label !== null && it.label !== undefined) &&
494502
!it.isBlanks &&
495-
it.label.toString().toLowerCase().indexOf(searchVal) > -1);
503+
(it.label.toString().toLowerCase().indexOf(searchVal) > -1 ||
504+
this.matchesNumericValue(it, searchVal)));
496505

497506
this.esf.listData.forEach(i => i.isSelected = false);
498507
this.displayedListData.forEach(i => i.isSelected = true);
@@ -724,7 +733,8 @@ export class IgxExcelStyleSearchComponent implements AfterViewInit, OnDestroy {
724733
node.expanded = false;
725734
}
726735

727-
if (element.label.toString().toLowerCase().indexOf(searchVal) > -1) {
736+
if (element.label.toString().toLowerCase().indexOf(searchVal) > -1 ||
737+
this.matchesNumericValue(element, searchVal)) {
728738
element.isSelected = true;
729739
this.hierarchicalSelectAllChildren(element);
730740
this._hierarchicalSelectedItems.push(element);
@@ -802,6 +812,23 @@ export class IgxExcelStyleSearchComponent implements AfterViewInit, OnDestroy {
802812
}
803813
}
804814

815+
private matchesNumericValue(item: FilterListItem, searchVal: string): boolean {
816+
const columnDataType = this.esf.column?.dataType;
817+
if (typeof item.value !== 'number' ||
818+
(columnDataType !== GridColumnDataType.Number &&
819+
columnDataType !== GridColumnDataType.Currency &&
820+
columnDataType !== GridColumnDataType.Percent)) {
821+
return false;
822+
}
823+
824+
let numericValue = item.value;
825+
if (columnDataType === GridColumnDataType.Percent) {
826+
numericValue = parseFloat((item.value * 100).toPrecision(15));
827+
}
828+
829+
return numericValue.toString().toLowerCase().indexOf(searchVal) > -1;
830+
}
831+
805832
private onArrowUpKeyDown() {
806833
if (this.focusedItem && this.focusedItem.index === 0 && this.virtDir.state.startIndex === 0) {
807834
// on ArrowUp the focus stays on the same element if it is the first focused

projects/igniteui-angular/grids/grid/src/grid-filtering-ui.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4113,6 +4113,25 @@ describe('IgxGrid - Filtering actions - Excel style filtering #grid', () => {
41134113
expect(listItems.length).toBe(8, 'incorrect rendered list items count');
41144114
});
41154115

4116+
it('Should match numeric column values when searching without locale-specific formatting characters.', async () => {
4117+
GridFunctions.clickExcelFilterIconFromCodeAsync(fix, grid, 'Downloads');
4118+
fix.detectChanges();
4119+
await wait(100);
4120+
const searchComponent = GridFunctions.getExcelStyleSearchComponent(fix);
4121+
const inputNativeElement = GridFunctions.getExcelStyleSearchComponentInput(fix, searchComponent);
4122+
4123+
// Type 1000 (without thousands separator) in search box.
4124+
// The value 1000 is displayed as "1,000" in the ESF list due to locale formatting.
4125+
// Searching "1000" should still match the "1,000" entry.
4126+
UIInteractions.clickAndSendInputElementValue(inputNativeElement, '1000', fix);
4127+
fix.detectChanges();
4128+
await wait(100);
4129+
4130+
const listItems = GridFunctions.getExcelStyleSearchComponentListItems(fix, searchComponent);
4131+
// Expect 3 items: Select All + Add to current filter + the matched "1,000" item
4132+
expect(listItems.length).toBe(3, 'searching plain number should match locale-formatted label');
4133+
});
4134+
41164135
it('Should enable/disable the apply button correctly.', async () => {
41174136
GridFunctions.clickExcelFilterIconFromCodeAsync(fix, grid, 'ProductName');
41184137
fix.detectChanges();

src/app/grid-cellMerging/grid-cellMerging.component.html

Lines changed: 78 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -43,79 +43,84 @@ <h4 class="sample-title">Grid with cell merge</h4>
4343
}
4444
</igx-input-group>
4545
</div>
46-
<igx-grid [data]="data" width="800px" height="550px" [moving]="true" #grid1
47-
[cellMergeMode]="'always'" [rowSelection]="'single'">
48-
<igx-column field="OrderID" header="Order ID">
49-
<ng-template igxCell let-cell="cell" let-val>
50-
Value: {{val}},Index: {{cell.row.index}}
51-
</ng-template>
52-
</igx-column>
53-
<igx-column field="ShipCountry" [groupable]="true" [hasSummary]="true" header="Ship Country" [merge]="true" width="200px" sortable="true">
54-
</igx-column>
55-
<igx-column field="OrderDate" header="Order Date" width="200px" [merge]="true" [groupable]="true" [dataType]="'date'" sortable="true">
56-
</igx-column>
57-
<igx-column field="PostalCode" header="Postal Code" width="200px" >
58-
</igx-column>
59-
<igx-column field="Discontinued" header="Discontinued" width="200px" sortable="true">
60-
</igx-column>
61-
<igx-column field="ShipName" header="Ship Name" width="250px">
62-
</igx-column>
63-
<igx-column field="ShipCity" header="Ship City" width="250px">
64-
</igx-column>
65-
<igx-column field="ShipperName" header="Shipper Name" width="250px">
66-
</igx-column>
67-
<igx-column field="Salesperson" header="Salesperson" width="250px">
68-
</igx-column>
69-
<igx-column field="UnitPrice" header="Unit Price" width="150px" dataType="number">
70-
</igx-column>
71-
<igx-column field="Quantity" header="Quantity" width="150px" dataType="number">
72-
</igx-column>
73-
74-
<igx-action-strip>
75-
<igx-grid-pinning-actions></igx-grid-pinning-actions>
76-
</igx-action-strip>
77-
<igx-grid-toolbar>
78-
<igx-grid-toolbar-actions>
79-
<igx-grid-toolbar-hiding></igx-grid-toolbar-hiding>
80-
<igx-grid-toolbar-pinning></igx-grid-toolbar-pinning>
81-
</igx-grid-toolbar-actions>
82-
</igx-grid-toolbar>
83-
</igx-grid>
46+
<div class="grids-grid">
47+
<igx-grid [data]="data" height="550px" [moving]="true" #grid1
48+
[cellMergeMode]="'always'" [rowSelection]="'single'" [allowFiltering]="true" [filterMode]="'excelStyleFilter'">
49+
<igx-column field="OrderID" header="Order ID">
50+
<ng-template igxCell let-cell="cell" let-val>
51+
Value: {{val}},Index: {{cell.row.index}}
52+
</ng-template>
53+
</igx-column>
54+
<igx-column field="ShipCountry" [groupable]="true" [hasSummary]="true" header="Ship Country" [merge]="true" width="200px" sortable="true">
55+
</igx-column>
56+
<igx-column field="OrderDate" header="Order Date" width="200px" [merge]="true" [groupable]="true" [dataType]="'date'" sortable="true">
57+
</igx-column>
58+
<igx-column field="PostalCode" header="Postal Code" width="200px" >
59+
</igx-column>
60+
<igx-column field="Discontinued" header="Discontinued" width="200px" sortable="true">
61+
</igx-column>
62+
<igx-column field="ShipName" header="Ship Name" width="250px">
63+
</igx-column>
64+
<igx-column field="ShipCity" header="Ship City" width="250px">
65+
</igx-column>
66+
<igx-column field="ShipperName" header="Shipper Name" width="250px">
67+
</igx-column>
68+
<igx-column field="Salesperson" header="Salesperson" width="250px">
69+
</igx-column>
70+
<igx-column field="UnitPrice" header="Unit Price" width="150px" dataType="currency">
71+
</igx-column>
72+
<igx-column field="ExtendedPrice" header="Extended Price" width="150px" dataType="currency">
73+
</igx-column>
74+
<igx-column field="Quantity" header="Quantity" width="150px" dataType="number">
75+
</igx-column>
8476

85-
<h4 class="sample-title">Hierarchical grid with cell merge</h4>
77+
<igx-action-strip>
78+
<igx-grid-pinning-actions></igx-grid-pinning-actions>
79+
</igx-action-strip>
80+
<igx-grid-toolbar>
81+
<igx-grid-toolbar-actions>
82+
<igx-grid-toolbar-hiding></igx-grid-toolbar-hiding>
83+
<igx-grid-toolbar-pinning></igx-grid-toolbar-pinning>
84+
</igx-grid-toolbar-actions>
85+
</igx-grid-toolbar>
86+
</igx-grid>
8687

87-
<igx-hierarchical-grid #hierarchicalGrid width="800px" [rowSelection]="'single'" [height]="'550px'" [data]="hierarchicalData" [autoGenerate]="false"
88-
[allowAdvancedFiltering]="true" [cellMergeMode]="'always'">
89-
<igx-grid-toolbar></igx-grid-toolbar>
90-
<igx-column field="EmployeeID" width="200px" [hidden]="true">
91-
</igx-column>
92-
<igx-column field="FirstName" width="200px">
93-
</igx-column>
94-
<igx-column field="LastName" width="200px">
95-
</igx-column>
96-
<igx-column field="Title" width="200px" [merge]="true" [hasSummary]="true">
97-
</igx-column>
98-
<igx-column [groupable]="true" [hasSummary]="true" field="City" width="200px" [merge]="true" editable="true" sortable="true">
99-
</igx-column>
100-
<igx-row-island [key]="'Orders'" [cellMergeMode]="'always'">
101-
<igx-column field="CustomerID" width="200px">
102-
</igx-column>
103-
<igx-column field="ShipName" width="200px">
104-
</igx-column>
105-
<igx-column field="ShipCountry" width="200px" [merge]="true" sortable="true">
106-
</igx-column>
107-
<igx-column field="ShipCity" width="200px" [merge]="true" sortable="true">
108-
</igx-column>
109-
</igx-row-island>
110-
</igx-hierarchical-grid>
88+
<igx-hierarchical-grid #hierarchicalGrid [rowSelection]="'single'" [height]="'550px'" [data]="hierarchicalData" [autoGenerate]="false"
89+
[allowAdvancedFiltering]="true" [cellMergeMode]="'always'">
90+
<igx-grid-toolbar [title]="'Hierarchical grid with cell merging'"></igx-grid-toolbar>
91+
<igx-column field="EmployeeID" width="200px" [hidden]="true">
92+
</igx-column>
93+
<igx-column field="FirstName" width="200px">
94+
</igx-column>
95+
<igx-column field="LastName" width="200px">
96+
</igx-column>
97+
<igx-column field="Title" width="200px" [merge]="true" [hasSummary]="true">
98+
</igx-column>
99+
<igx-column [groupable]="true" [hasSummary]="true" field="City" width="200px" [merge]="true" editable="true" sortable="true">
100+
</igx-column>
101+
<igx-row-island [key]="'Orders'" [cellMergeMode]="'always'">
102+
<igx-column field="CustomerID" width="200px">
103+
</igx-column>
104+
<igx-column field="ShipName" width="200px">
105+
</igx-column>
106+
<igx-column field="ShipCountry" width="200px" [merge]="true" sortable="true">
107+
</igx-column>
108+
<igx-column field="ShipCity" width="200px" [merge]="true" sortable="true">
109+
</igx-column>
110+
</igx-row-island>
111+
</igx-hierarchical-grid>
111112

112-
<h4 class="sample-title">Tree grid with cell merge</h4>
113-
<button (click)="toggleStrategy()">Toggle strategy</button>
114-
<igx-tree-grid [autoGenerate]="false" [rowSelection]="'single'" [data]="treeData" [cellMergeMode]="'always'" [mergeStrategy]="treeGridMergeStrategy"
115-
childDataKey="ChildCompanies" primaryKey="ID" [expansionDepth]="1" width="800px" [height]="'550px'">
116-
<igx-column field="ContactName" width="200px" [hasSummary]="true">
117-
</igx-column>
118-
<igx-column field="ContactTitle" width="200px"></igx-column>
119-
<igx-column field="Country" width="200px" [merge]="true" sortable="true"></igx-column>
120-
<igx-column field="City" width="200px" [merge]="true" sortable="true"></igx-column>
121-
</igx-tree-grid>
113+
<igx-tree-grid [autoGenerate]="false" [rowSelection]="'single'" [data]="treeData" [cellMergeMode]="'always'" [mergeStrategy]="treeGridMergeStrategy"
114+
childDataKey="ChildCompanies" primaryKey="ID" [expansionDepth]="1" [height]="'550px'">
115+
<igx-grid-toolbar [title]="'Tree grid with cell merging'">
116+
<igx-grid-toolbar-actions>
117+
<button igxButton (click)="toggleStrategy()">Toggle strategy</button>
118+
</igx-grid-toolbar-actions>
119+
</igx-grid-toolbar>
120+
<igx-column field="ContactName" width="200px" [hasSummary]="true">
121+
</igx-column>
122+
<igx-column field="ContactTitle" width="200px"></igx-column>
123+
<igx-column field="Country" width="200px" [merge]="true" sortable="true"></igx-column>
124+
<igx-column field="City" width="200px" [merge]="true" sortable="true"></igx-column>
125+
</igx-tree-grid>
126+
</div>

src/app/grid-cellMerging/grid-cellMerging.component.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,9 @@
2020
.searchInput{
2121
width: 800px;
2222
}
23+
24+
.grids-grid {
25+
display: grid;
26+
grid-template-columns: repeat(auto-fill, minmax(800px, 1fr));
27+
gap: 1rem;
28+
}

src/app/grid-cellMerging/grid-cellMerging.component.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { FormsModule } from '@angular/forms';
33
import {
44
DefaultTreeGridMergeStrategy,
55
IgxActionStripComponent,
6+
IgxButtonDirective,
67
IgxCellTemplateDirective,
78
IgxColumnComponent,
89
IgxGridComponent,
@@ -12,10 +13,10 @@ import {
1213
IgxGridToolbarHidingComponent,
1314
IgxGridToolbarPinningComponent,
1415
IgxHierarchicalGridComponent,
16+
IgxIconButtonDirective,
1517
IgxIconComponent,
1618
IgxInputDirective,
1719
IgxInputGroupComponent,
18-
IgxPaginatorComponent,
1920
IgxPrefixDirective,
2021
IgxRowIslandComponent,
2122
IgxSuffixDirective,
@@ -50,7 +51,9 @@ import { INVOICE_DATA } from '../shared/invoiceData';
5051
IgxSuffixDirective,
5152
IgxIconComponent,
5253
IgxInputDirective,
53-
IgxCellTemplateDirective
54+
IgxCellTemplateDirective,
55+
IgxButtonDirective,
56+
IgxIconButtonDirective
5457
]
5558
})
5659
export class GridCellMergingComponent {

src/app/grid-column-types/grid-column-types.sample.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
[filterMode]="filterMode"
1010
rowSelection="multiple"
1111
[rowEditable]="false"
12-
width="700px"
12+
width="800px"
1313
[primaryKey]="'ID'">
1414

1515
<igx-grid-toolbar >
@@ -45,7 +45,7 @@
4545
[filterMode]="filterMode"
4646
rowSelection="multiple"
4747
[rowEditable]="true"
48-
[width]="'700px'">
48+
[width]="'800px'">
4949

5050
<igx-grid-toolbar >
5151
<igx-grid-toolbar-actions>

src/app/hierarchical-grid-remote/hierarchical-grid-remote.sample.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ export class HierarchicalGridRemoteSampleComponent implements OnInit, AfterViewI
5555
fields: [
5656
{ field: 'orderId', dataType: 'number' }, // first field will be treated as foreign key
5757
{ field: 'productId', dataType: 'number' },
58-
{ field: 'unitPrice', dataType: 'number' },
58+
{ field: 'unitPrice', dataType: 'currency' },
5959
{ field: 'quantity', dataType: 'number' },
60-
{ field: 'discount', dataType: 'number' }
60+
{ field: 'discount', dataType: 'percent' }
6161
]
6262
}
6363
]
@@ -131,7 +131,7 @@ export class HierarchicalGridRemoteSampleComponent implements OnInit, AfterViewI
131131
console.log('data', data);
132132
event.grid.data = Object.values(data);
133133
event.grid.isLoading = false;
134-
this.cdr.detectChanges();
134+
this.cdr.detectChanges();
135135
});
136136
}
137137

src/app/hierarchical-grid-updating/hierarchical-grid-updating.sample.html

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,29 @@
44
<button igxButton="contained" (click)="logTransactionsIsland1()">RI1 Transactions</button>
55
<button igxButton="contained" (click)="commitTransactionsIsland1()">Commit R1 Transactions</button>
66
<div class="wrapper">
7-
<igx-hierarchical-grid #grid1 [batchEditing]="true" [data]="remoteData" [rowEditable]="true" [primaryKey]="'CustomerID'" [autoGenerate]="false"
8-
[height]="'800px'" [width]="'100%'" #hGrid>
9-
<igx-column field="CustomerID"></igx-column>
10-
<igx-column field="CompanyName"></igx-column>
11-
<igx-column field="ContactName"></igx-column>
12-
<igx-column field="ContactTitle"></igx-column>
13-
<igx-column field="Country"></igx-column>
14-
<igx-column field="Phone"></igx-column>
15-
<igx-row-island #rowIsland1 [key]="'Orders'" [primaryKey]="'OrderID'" [autoGenerate]="false"
16-
[rowSelection]='selectionMode' (gridCreated)="gridCreated($event, rowIsland1)"
17-
[rowEditable]="true">
18-
<igx-column field="OrderID"></igx-column>
19-
<igx-column field="OrderDate" [dataType]='"date"'></igx-column>
20-
<igx-column field="ShipCountry"></igx-column>
21-
<igx-column field="ShipCity"></igx-column>
22-
<igx-column field="ShipAddress"></igx-column>
23-
<igx-row-island #rowIsland2 [key]="'Order_Details'" [height]="'300px'" [primaryKey]="'ProductID'"
24-
[autoGenerate]="false" [rowSelection]='selectionMode' (gridCreated)="gridCreated($event, rowIsland2)">
25-
<igx-column field="ProductID"></igx-column>
26-
<igx-column field="UnitPrice"></igx-column>
27-
<igx-column field="Quantity"></igx-column>
28-
<igx-column field="Discount"></igx-column>
29-
</igx-row-island>
30-
</igx-row-island>
31-
</igx-hierarchical-grid>
32-
</div>
7+
<igx-hierarchical-grid #grid1 [batchEditing]="true" [data]="remoteData" [rowEditable]="true" [primaryKey]="'CustomerID'" [autoGenerate]="false"
8+
[height]="'800px'" [width]="'100%'" #hGrid>
9+
<igx-column field="CustomerID"></igx-column>
10+
<igx-column field="CompanyName"></igx-column>
11+
<igx-column field="ContactName"></igx-column>
12+
<igx-column field="ContactTitle"></igx-column>
13+
<igx-column field="Country"></igx-column>
14+
<igx-column field="Phone"></igx-column>
15+
<igx-row-island #rowIsland1 [key]="'Orders'" [primaryKey]="'OrderID'" [autoGenerate]="false"
16+
[rowSelection]="selectionMode" (gridCreated)="gridCreated($event, rowIsland1)"
17+
[rowEditable]="true">
18+
<igx-column field="OrderID"></igx-column>
19+
<igx-column field="OrderDate" [dataType]="'date'"></igx-column>
20+
<igx-column field="ShipCountry"></igx-column>
21+
<igx-column field="ShipCity"></igx-column>
22+
<igx-column field="ShipAddress"></igx-column>
23+
<igx-row-island #rowIsland2 [key]="'Order_Details'" [height]="'300px'" [primaryKey]="'ProductID'"
24+
[autoGenerate]="false" [rowSelection]="selectionMode" (gridCreated)="gridCreated($event, rowIsland2)">
25+
<igx-column field="ProductID"></igx-column>
26+
<igx-column field="UnitPrice" [dataType]="'currency'"></igx-column>
27+
<igx-column field="Quantity"></igx-column>
28+
<igx-column field="Discount" [dataType]="'percent'"></igx-column>
29+
</igx-row-island>
30+
</igx-row-island>
31+
</igx-hierarchical-grid>
32+
</div>

0 commit comments

Comments
 (0)