Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(grid): add FormattedValuesSortingStrategy for sorting by formatted values - master #14538

Merged
merged 20 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
38fce49
feat(grid): add FormattedValuesSortingStrategy for sorting by formatt…
georgianastasov Jul 17, 2024
149df98
Merge branch 'master' into ganastasov/feat-14442-master
hanastasov Jul 17, 2024
900a17b
Merge branch 'master' into ganastasov/feat-14442-master
georgianastasov Jul 19, 2024
36bf0e5
Merge branch 'master' into ganastasov/feat-14442-master
georgianastasov Jul 22, 2024
dbacac5
Merge branch 'master' into ganastasov/feat-14442-master
georgianastasov Jul 23, 2024
6bbe8a4
docs(changelog): add info for new FormattedValuesSortingStrategy
georgianastasov Jul 23, 2024
c43fc9c
Merge branch 'master' into ganastasov/feat-14442-master
hanastasov Jul 24, 2024
e069ff2
Merge branch 'master' into ganastasov/feat-14442-master
ddaribo Aug 19, 2024
dacb374
docs(changelog): move the description for the feature from version 18…
georgianastasov Aug 21, 2024
0b06ac9
Merge branch 'master' into ganastasov/feat-14442-master
ddaribo Aug 22, 2024
600369e
Merge branch 'master' into ganastasov/feat-14442-master
ddaribo Aug 26, 2024
0f3aa23
Merge branch 'master' of https://github.com/IgniteUI/igniteui-angular…
georgianastasov Aug 29, 2024
420596e
Merge branch 'master' into ganastasov/feat-14442-master
ddaribo Aug 30, 2024
8b1fccf
Merge branch 'master' of https://github.com/IgniteUI/igniteui-angular…
georgianastasov Sep 2, 2024
8f4fbcc
Merge branch 'master' into ganastasov/feat-14442-master
georgianastasov Sep 3, 2024
b971b7f
Merge branch 'master' into ganastasov/feat-14442-master
georgianastasov Sep 10, 2024
7bc847c
Merge branch 'master' into ganastasov/feat-14442-master
georgianastasov Sep 10, 2024
95cae58
Merge branch 'master' of https://github.com/IgniteUI/igniteui-angular…
georgianastasov Sep 10, 2024
c2d9157
Merge branch 'master' into ganastasov/feat-14442-master
georgianastasov Sep 11, 2024
71ddf30
Merge branch 'master' into ganastasov/feat-14442-master
hanastasov Sep 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ All notable changes for each version of this project will be documented in this
this.iconService.registerFamilyAlias('my-family', 'my-family-class');
this.iconService.setFamily('my-family', { className: 'my-family-class' });
```
- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid`
- To streamline the sorting of columns with custom formats, a new `FormattedValuesSortingStrategy` has been introduced. This strategy simplifies the sorting process by allowing direct sorting based on formatted values, eliminating the need to extend the `DefaultSortingStrategy` or implement a custom `ISortingStrategy`. This enhancement improves the ease of handling sorting with custom column formatters.

### General
- `ColumnType`, `IgxColumn`, `IgxColumnGroup`, `IgxColumnLayout`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,60 @@ export class GroupMemberCountSortingStrategy implements ISortingStrategy {
return reverse * (firstItemValuesLength - secondItemValuesLength);
}
}

export class FormattedValuesSortingStrategy extends DefaultSortingStrategy {
protected static override _instance: FormattedValuesSortingStrategy = null;

constructor() {
super();
}

public static override instance(): FormattedValuesSortingStrategy {
return this._instance || (this._instance = new this());
}

public override sort(
data: any[],
fieldName: string,
dir: SortingDirection,
ignoreCase: boolean,
valueResolver: (obj: any, key: string, isDate?: boolean) => any,
isDate?: boolean,
isTime?: boolean,
grid?: GridType
) {
const key = fieldName;
const reverse = (dir === SortingDirection.Desc ? -1 : 1);
const cmpFunc = (obj1: any, obj2: any) => this.compareObjects(obj1, obj2, key, reverse, ignoreCase, valueResolver, isDate, isTime, grid);
return this.arraySort(data, cmpFunc);
}

protected override compareObjects(
obj1: any,
obj2: any,
key: string,
reverse: number,
ignoreCase: boolean,
valueResolver: (obj: any, key: string, isDate?: boolean, isTime?: boolean) => any,
isDate: boolean,
isTime: boolean,
grid?: GridType
) {
let a = valueResolver.call(this, obj1, key, isDate, isTime);
let b = valueResolver.call(this, obj2, key, isDate, isTime);

if (grid) {
const col = grid.getColumnByName(key);
if (col && col.formatter) {
a = col.formatter(a);
b = col.formatter(b);
}
}

if (ignoreCase) {
a = a && a.toLowerCase ? a.toLowerCase() : a;
b = b && b.toLowerCase ? b.toLowerCase() : b;
}
return reverse * this.compareValues(a, b);
}
}
60 changes: 57 additions & 3 deletions projects/igniteui-angular/src/lib/grids/grid/grid.sorting.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { TestBed, fakeAsync, tick } from '@angular/core/testing';
import { IgxGridComponent } from './grid.component';
import { DefaultSortingStrategy, SortingDirection } from '../../data-operations/sorting-strategy';
import { DefaultSortingStrategy, FormattedValuesSortingStrategy, SortingDirection } from '../../data-operations/sorting-strategy';
import { configureTestSuite } from '../../test-utils/configure-suite';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { GridFunctions } from '../../test-utils/grid-functions.spec';
import { GridDeclaredColumnsComponent, SortByParityComponent, GridWithPrimaryKeyComponent, SortByAnotherColumnComponent, SortOnInitComponent } from '../../test-utils/grid-samples.spec';
import { GridDeclaredColumnsComponent, SortByParityComponent, GridWithPrimaryKeyComponent, SortByAnotherColumnComponent, SortOnInitComponent, IgxGridFormattedValuesSortingComponent } from '../../test-utils/grid-samples.spec';
import { UIInteractions } from '../../test-utils/ui-interactions.spec';
import { SampleTestData } from '../../test-utils/sample-test-data.spec';
import { CellType } from '../common/grid.interface';
import { NoopSortingStrategy } from '../common/strategy';
import { By } from '@angular/platform-browser';

describe('IgxGrid - Grid Sorting #grid', () => {

Expand All @@ -21,7 +22,8 @@ describe('IgxGrid - Grid Sorting #grid', () => {
GridDeclaredColumnsComponent,
SortByParityComponent,
GridWithPrimaryKeyComponent,
NoopAnimationsModule
NoopAnimationsModule,
IgxGridFormattedValuesSortingComponent
]
});
}));
Expand Down Expand Up @@ -405,6 +407,58 @@ describe('IgxGrid - Grid Sorting #grid', () => {
expect(grid.getCellByKey(6, 'LastName').row.index).toBeGreaterThan(grid.getCellByKey(7, 'LastName').row.index);
expect(grid.getCellByKey(4, 'LastName').row.index).toBeGreaterThan(grid.getCellByKey(5, 'LastName').row.index);
});

it('Should sort grid by formatted values using FormattedValuesSortingStrategy', fakeAsync(() => {
fixture = TestBed.createComponent(IgxGridFormattedValuesSortingComponent);
tick();
fixture.detectChanges();

grid = fixture.componentInstance.grid;
tick();
fixture.detectChanges();

const productNameColumn = grid.getColumnByName("ProductName");
const quantityColumn = grid.getColumnByName("QuantityPerUnit");

expect(productNameColumn.sortStrategy instanceof FormattedValuesSortingStrategy).toBeTruthy();
expect(quantityColumn.sortStrategy instanceof FormattedValuesSortingStrategy).toBeTruthy();

const productNameHeaderCell = GridFunctions.getColumnHeader('ProductName', fixture);

GridFunctions.clickHeaderSortIcon(productNameHeaderCell);
tick(30);
fixture.detectChanges();

const firstProductNameCell = fixture.debugElement.queryAll(By.css('.igx-grid__td'))[1];
expect(firstProductNameCell.nativeElement.textContent.trim()).toBe("a-Alice Mutton");

GridFunctions.clickHeaderSortIcon(productNameHeaderCell);
tick(30);
fixture.detectChanges();

const lastProductNameCell = fixture.debugElement.queryAll(By.css('.igx-grid__td'))[1];
expect(lastProductNameCell.nativeElement.textContent.trim()).toBe("b-Tofu");

grid.clearSort();
tick();
fixture.detectChanges();

const quantityPerUnitHeaderCell = GridFunctions.getColumnHeader('QuantityPerUnit', fixture);

GridFunctions.clickHeaderSortIcon(quantityPerUnitHeaderCell);
tick(30);
fixture.detectChanges();

const firstQuantityCell = fixture.debugElement.queryAll(By.css('.igx-grid__td'))[2];
expect(firstQuantityCell.nativeElement.textContent.trim()).toBe("c");

GridFunctions.clickHeaderSortIcon(quantityPerUnitHeaderCell);
tick(30);
fixture.detectChanges();

const lastQuantityCell = fixture.debugElement.queryAll(By.css('.igx-grid__td'))[2];
expect(lastQuantityCell.nativeElement.textContent.trim()).toBe("d-36 boxes");
}));
});

describe('UI tests', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { ISortingOptions, IgxExcelStyleHeaderIconDirective, IgxGridToolbarAdvanc
import { IgxRowAddTextDirective, IgxRowEditActionsDirective, IgxRowEditTabStopDirective, IgxRowEditTemplateDirective, IgxRowEditTextDirective } from '../grids/grid.rowEdit.directive';
import { IgxExcelStyleColumnOperationsTemplateDirective, IgxExcelStyleFilterOperationsTemplateDirective, IgxGridExcelStyleFilteringComponent } from '../grids/filtering/excel-style/excel-style-filtering.component';
import { FilteringLogic } from '../data-operations/filtering-expression.interface';
import { ISortingStrategy, SortingDirection } from '../data-operations/sorting-strategy';
import { FormattedValuesSortingStrategy, ISortingStrategy, SortingDirection } from '../data-operations/sorting-strategy';
import { IgxActionStripComponent } from '../action-strip/action-strip.component';
import { IDataCloneStrategy } from '../data-operations/data-clone-strategy';
import { IgxColumnLayoutComponent } from '../grids/columns/column-layout.component';
Expand Down Expand Up @@ -2266,6 +2266,42 @@ export class SortOnInitComponent extends GridDeclaredColumnsComponent implements
}
}

@Component({
template: `
<igx-grid #grid [data]="data" [primaryKey]="'ProductID'" width="900px" height="600px">
<igx-column field="ProductID" header="Product ID" [sortable]="true"></igx-column>
<igx-column field="ProductName" header="Product Name" [dataType]="'string'" [sortable]="true"
[formatter]="formatProductName" [sortStrategy]="sortStrategy"></igx-column>
<igx-column field="QuantityPerUnit" header="Quantity Per Unit" [dataType]="'string'" [sortable]="true"
[formatter]="formatQuantity" [sortStrategy]="sortStrategy"></igx-column>
<igx-column field="UnitPrice" header="Unit Price" [dataType]="'number'" [sortable]="true"></igx-column>
<igx-column field="OrderDate" header="Order Date" [dataType]="'date'" [sortable]="true"></igx-column>
</igx-grid>
`,
standalone: true,
imports: [IgxGridComponent, IgxColumnComponent]
})
export class IgxGridFormattedValuesSortingComponent extends BasicGridComponent {
public override data = SampleTestData.gridProductData();
public sortStrategy = new FormattedValuesSortingStrategy();

public formatProductName = (value: string) => {
if (!value) {
return 'a';
}
const prefix = value.length > 10 ? 'a' : 'b';
return `${prefix}-${value}`;
}

public formatQuantity = (value: string) => {
if (!value) {
return 'c';
}
const prefix = value.length > 10 ? 'c' : 'd';
return `${prefix}-${value}`;
}
}

@Component({
template: `
<igx-grid #grid [data]="data" [height]="'500px'" [width]="'500px'">
Expand Down
Loading