Skip to content

feat(IgxGridBaseDirective): Add Single and Multiple sorting options #10336

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

Merged
merged 49 commits into from
Apr 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
a30a38a
feat(IgxGridBaseDirective): add sorting options
katherinedragieva Oct 21, 2021
a4e22ac
Merge branch 'master' into kdragieva/grid-sorting-master
hanastasov Oct 21, 2021
627b752
feat(IgxGridBaseDirective): remove enum and refactor code
katherinedragieva Oct 21, 2021
e18028e
Merge branch 'kdragieva/grid-sorting-master' of https://github.com/Ig…
katherinedragieva Oct 21, 2021
c35b869
chore(IgxGridBaseDirective): fix trailing spaces and lint issues
katherinedragieva Oct 21, 2021
cdfc833
refactor(IgxGridBaseDirective): remove trailing spaces
katherinedragieva Oct 21, 2021
02f5a1b
Update projects/igniteui-angular/src/lib/grids/columns/interfaces.ts
katherinedragieva Oct 21, 2021
e618bd5
Update projects/igniteui-angular/src/lib/grids/grid-base.directive.ts
katherinedragieva Oct 22, 2021
3921571
Merge branch 'master' into kdragieva/grid-sorting-master
kdinev Nov 3, 2021
45ed518
fix(sorting & groupBy): decouple sorting and groupBy features
katherinedragieva Nov 11, 2021
789c22a
Merge branch 'kdragieva/grid-sorting-master' of https://github.com/Ig…
katherinedragieva Nov 11, 2021
3df6065
test(grid): fix trailing space, ng lnt
katherinedragieva Nov 12, 2021
8187dfa
Merge branch 'master' into kdragieva/grid-sorting-master
katherinedragieva Nov 22, 2021
31ebde5
Merge branch 'master' into kdragieva/grid-sorting-master
katherinedragieva Nov 24, 2021
0613c24
ci(IgxGridComponent): fixed errors occured in merging
katherinedragieva Nov 24, 2021
6d9a176
Merge branch 'master' into kdragieva/grid-sorting-master
katherinedragieva Jan 28, 2022
ef69052
Merge branch '13.1.x' of https://github.com/IgniteUI/igniteui-angular…
ddincheva Mar 15, 2022
e659281
fix(Grid): wrongfully resolved merge with master #9674
ddincheva Mar 16, 2022
31b6008
Merge branch '13.1.x' of https://github.com/IgniteUI/igniteui-angular…
ddincheva Mar 16, 2022
6797a43
Merge branch '13.1.x' into kdragieva/grid-sorting-master
ddincheva Mar 21, 2022
8b1ae23
Merge branch '13.1.x' of https://github.com/IgniteUI/igniteui-angular…
ddincheva Mar 22, 2022
3e74fa6
Merge branch '13.1.x' of https://github.com/IgniteUI/igniteui-angular…
ddincheva Mar 30, 2022
b5cfa6a
feat(GroupBy): handle groupBy sorting without updating sorting expres…
ddincheva Apr 4, 2022
dbe2440
feat(Sorting): remove sortIndex when single sorting mode is enabled #…
ddincheva Apr 4, 2022
51a6c56
feat(Sorting): grid sorting should not affect group by state #9674
ddincheva Apr 4, 2022
2c519a3
feat(*): update sort pipe to work based on group and sorting expressi…
ddincheva Apr 4, 2022
70cc291
fix(*): fix the iissues with hierarchical and tree grid #9674
ddincheva Apr 6, 2022
7ca5130
feat(TGrid): remove the binding logic between sorting expr and groupB…
ddincheva Apr 6, 2022
041d519
chore(*): update samples with sortingOption prop
ddincheva Apr 6, 2022
a4ebae6
chore(*): fix groupBy tests
ddincheva Apr 7, 2022
df3504d
chore(*): fix buildig errors
ddincheva Apr 7, 2022
087739a
chore(*): fix failing test due to the regression in excell export
ddincheva Apr 8, 2022
c5e4d64
chore(*): fix the thrown error when trying to group by nonexisting co…
ddincheva Apr 8, 2022
0892262
chore(*): fix wrong test expectation
ddincheva Apr 11, 2022
7ad0d9e
chore(*): add some additional test to verify separation of grouping a…
ddincheva Apr 11, 2022
c4d4446
Merge branch 'master' of https://github.com/IgniteUI/igniteui-angular…
ddincheva Apr 12, 2022
e209f08
Merge branch 'kdragieva/grid-sorting-master' of https://github.com/Ig…
ddincheva Apr 12, 2022
cf7495d
Merge pull request #11355 from IgniteUI/ddincheva/groupingSorting-13.1.x
hanastasov Apr 12, 2022
af111ec
chore(*): update the changelog
ddincheva Apr 12, 2022
bbe3a3c
Merge branch 'master' into kdragieva/grid-sorting-master
hanastasov Apr 18, 2022
943d09b
Merge branch 'master' into kdragieva/grid-sorting-master
hanastasov Apr 20, 2022
ce179ce
Update src/app/tree-grid-groupby/tree-grid-groupby.sample.ts
hanastasov Apr 20, 2022
79cebf5
Update projects/igniteui-angular/src/lib/grids/grid/grid.component.ts
hanastasov Apr 20, 2022
003bbbd
Merge branch 'master' into kdragieva/grid-sorting-master
hanastasov Apr 21, 2022
c483c69
chore(*): clear sorting when sortion oprtions are changed and update …
ddincheva Apr 21, 2022
24fe1c1
chore(*): preserve the check for undefined
ddincheva Apr 21, 2022
e225316
Merge branch 'master' of https://github.com/IgniteUI/igniteui-angular…
ddincheva Apr 21, 2022
99231b1
Merge branch 'master' into kdragieva/grid-sorting-master
hanastasov Apr 26, 2022
f2ca7bf
Merge branch 'master' into kdragieva/grid-sorting-master
hanastasov Apr 26, 2022
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
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

All notable changes for each version of this project will be documented in this file.

## 13.2.0
## 13.2.0

### New palette

A new fluent light and dark palettes that use the default fluent colors - `$light-fluent-palette` and `$dark-fluent-palette`.

### New Features
- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid`
- new *sortingOption* property has been introduced on grid level; This property allows you to set either `single` or `multiple` sorting mode; When single mode is enabled you can sort one column at a time; The default value of the property is `multiple`;

- **Behavioral Change** - sorting and grouping expressions are now working separately; If grouping/sorting expressions are in a conflict, grouping expressions take precedence. You can read more about that in our official documentation.
## 13.1.0

### New Features
Expand Down Expand Up @@ -138,7 +143,7 @@ A new fluent light and dark palettes that use the default fluent colors - `$ligh
- `IgxDialog`
- Added `focusTrap` input to set whether the Tab key focus is trapped within the dialog when opened. Defaults to `true`.
- `IgxProgressBar`
- Exposed new animationDuration input - sets the duration of the progress animation.
- Exposed new animationDuration input - sets the duration of the progress animation.

### General

Expand Down
58 changes: 58 additions & 0 deletions projects/igniteui-angular/src/lib/grids/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { IgxCell, IgxGridCRUDService, IgxEditRow } from './common/crud.service';
import { CellType, ColumnType, GridServiceType, GridType, RowType } from './common/grid.interface';
import { IGridEditEventArgs, IRowToggleEventArgs } from './common/events';
import { IgxColumnMovingService } from './moving/moving.service';
import { IGroupingExpression } from '../data-operations/grouping-expression.interface';
import { ISortingExpression, SortingDirection } from '../data-operations/sorting-strategy';
import { FilterUtil } from '../data-operations/filtering-strategy';

Expand Down Expand Up @@ -221,6 +222,15 @@ export class GridBaseAPIService<T extends GridType> implements GridServiceType {
this.grid.sortingExpressions = sortingState;
}

public sort_decoupled(expression: IGroupingExpression): void {
if (expression.dir === SortingDirection.None) {
this.remove_grouping_expression(expression.fieldName);
}
const groupingState = cloneArray((this.grid as any).groupingExpressions);
this.prepare_grouping_expression([groupingState], expression);
(this.grid as any).groupingExpressions = groupingState;
}

public sort_multiple(expressions: ISortingExpression[]): void {
const sortingState = cloneArray(this.grid.sortingExpressions);

Expand All @@ -234,6 +244,17 @@ export class GridBaseAPIService<T extends GridType> implements GridServiceType {
this.grid.sortingExpressions = sortingState;
}

public sort_groupBy_multiple(expressions: ISortingExpression[]): void {
const groupingState = cloneArray((this.grid as any).groupingExpressions);

for (const each of expressions) {
if (each.dir === SortingDirection.None) {
this.remove_grouping_expression(each.fieldName);
}
this.prepare_grouping_expression([groupingState], each);
}
}

public clear_sort(fieldName: string) {
const sortingState = this.grid.sortingExpressions;
const index = sortingState.findIndex((expr) => expr.fieldName === fieldName);
Expand Down Expand Up @@ -460,6 +481,43 @@ export class GridBaseAPIService<T extends GridType> implements GridServiceType {
});
}

public prepare_grouping_expression(stateCollections: Array<Array<any>>, expression: IGroupingExpression) {
if (expression.dir === SortingDirection.None) {
stateCollections.forEach(state => {
state.splice(state.findIndex((expr) => expr.fieldName === expression.fieldName), 1);
});
return;
}

/**
* We need to make sure the states in each collection with same fields point to the same object reference.
* If the different state collections provided have different sizes we need to get the largest one.
* That way we can get the state reference from the largest one that has the same fieldName as the expression to prepare.
*/
let maxCollection = stateCollections[0];
for (let i = 1; i < stateCollections.length; i++) {
if (maxCollection.length < stateCollections[i].length) {
maxCollection = stateCollections[i];
}
}
const maxExpr = maxCollection.find((expr) => expr.fieldName === expression.fieldName);

stateCollections.forEach(collection => {
const myExpr = collection.find((expr) => expr.fieldName === expression.fieldName);
if (!myExpr && !maxExpr) {
// Expression with this fieldName is missing from the current and the max collection.
collection.push(expression);
} else if (!myExpr && maxExpr) {
// Expression with this fieldName is missing from the current and but the max collection has.
collection.push(maxExpr);
Object.assign(maxExpr, expression);
} else {
// The current collection has the expression so just update it.
Object.assign(myExpr, expression);
}
});
}

public remove_grouping_expression(_fieldName) {
}

Expand Down
4 changes: 4 additions & 0 deletions projects/igniteui-angular/src/lib/grids/columns/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ export interface IColumnPipeArgs {
*/
display?: string;
}

export interface ISortingOptions {
mode: 'single' | 'multiple';
}
4 changes: 3 additions & 1 deletion projects/igniteui-angular/src/lib/grids/common/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { IBaseEventArgs, CancelableEventArgs } from '../../core/utils';
import { GridKeydownTargetType } from './enums';
import { CellType, ColumnType, GridType, RowType } from './grid.interface';
import { IFilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree';
import { IGroupingExpression } from '../../data-operations/grouping-expression.interface';
import { IgxBaseExporter } from '../../services/exporter-common/base-export-service';
import { IgxExporterOptionsBase } from '../../services/exporter-common/exporter-options-base';
import { ISortingExpression } from '../../data-operations/sorting-strategy';
Expand Down Expand Up @@ -201,7 +202,8 @@ export interface IActiveNodeChangeEventArgs extends IBaseEventArgs {
}

export interface ISortingEventArgs extends IBaseEventArgs, CancelableEventArgs {
sortingExpressions: ISortingExpression | Array<ISortingExpression>;
sortingExpressions?: ISortingExpression | Array<ISortingExpression>;
groupingExpressions?: IGroupingExpression | Array<IGroupingExpression>;
}

export interface IFilteringEventArgs extends IBaseEventArgs, CancelableEventArgs {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { ITreeGridRecord } from '../tree-grid/tree-grid.interfaces';
import { State, Transaction, TransactionService } from '../../services/transaction/transaction';
import { GridColumnDataType } from '../../data-operations/data-util';
import { IgxFilteringOperand } from '../../data-operations/filtering-condition';
import { IColumnPipeArgs, MRLResizeColumnInfo } from '../columns/interfaces';
import { IColumnPipeArgs, ISortingOptions, MRLResizeColumnInfo } from '../columns/interfaces';
import { IgxSummaryResult } from '../summaries/grid-summary';
import { ISortingExpression, ISortingStrategy, SortingDirection } from '../../data-operations/sorting-strategy';
import { IGridGroupingStrategy, IGridSortingStrategy } from './strategy';
Expand Down Expand Up @@ -444,6 +444,7 @@ export interface GridType extends IGridDataBindable {
records?: Map<any, ITreeGridRecord>;
processedExpandedFlatData?: any[] | null;
processedRecords?: Map<any, ITreeGridRecord>;
treeGroupArea?: any;

activeNodeChange: EventEmitter<IActiveNodeChangeEventArgs>;
gridKeydown: EventEmitter<IGridKeydownEventArgs>;
Expand Down Expand Up @@ -499,6 +500,7 @@ export interface GridType extends IGridDataBindable {
filteringExpressionsTreeChange: EventEmitter<IFilteringExpressionsTree>;
advancedFilteringExpressionsTree: IFilteringExpressionsTree;
advancedFilteringExpressionsTreeChange: EventEmitter<IFilteringExpressionsTree>;
sortingOptions: ISortingOptions;

batchEditing: boolean;
groupingExpansionState?: IGroupByExpandState[];
Expand Down
42 changes: 36 additions & 6 deletions projects/igniteui-angular/src/lib/grids/grid-base.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,15 @@ import { IgxPaginatorComponent } from '../paginator/paginator.component';
import { IgxGridHeaderRowComponent } from './headers/grid-header-row.component';
import { IgxGridGroupByAreaComponent } from './grouping/grid-group-by-area.component';
import { IgxFlatTransactionFactory, TRANSACTION_TYPE } from '../services/transaction/transaction-factory.service';
import { ISortingOptions } from './columns/interfaces';
import { GridSelectionRange, IgxGridTransaction } from './common/types';
import { VerticalAlignment, HorizontalAlignment, PositionSettings, OverlaySettings } from '../services/overlay/utilities';
import { IgxOverlayService } from '../services/overlay/overlay';
import { ConnectedPositioningStrategy } from '../services/overlay/position/connected-positioning-strategy';
import { ContainerPositionStrategy } from '../services/overlay/position/container-position-strategy';
import { AbsoluteScrollStrategy } from '../services/overlay/scroll/absolute-scroll-strategy';
import { Action, StateUpdateEvent, TransactionEventOrigin } from '../services/transaction/transaction';
import { ISortingExpression, SortingDirection } from '../data-operations/sorting-strategy';
import { ISortingExpression } from '../data-operations/sorting-strategy';
import { IGridSortingStrategy } from './common/strategy';
import { IgxGridExcelStyleFilteringComponent } from './filtering/excel-style/grid.excel-style-filtering.component';
import { IgxGridHeaderComponent } from './headers/grid-header.component';
Expand Down Expand Up @@ -2110,6 +2111,33 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements
this._sortingStrategy = value;
}

/**
* Gets/Sets the sorting options - single or multiple sorting.
* Accepts an `ISortingOptions` object with any of the `mode` properties.
*
* @example
* ```typescript
* const _sortingOptions: ISortingOptions = {
* mode: 'single'
* }
* ```html
* <igx-grid [sortingOptions]="sortingOptions"><igx-grid>
* ```
*/
@Input()
public set sortingOptions(value: ISortingOptions) {
this.clearSort();
this._sortingOptions = Object.assign(this._sortingOptions, value);
}

/**
* @hidden
* @internal
*/
public get sortingOptions() {
return this._sortingOptions;
}

/**
* Gets/Sets the current selection state.
*
Expand Down Expand Up @@ -2764,6 +2792,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements
protected _userOutletDirective: IgxOverlayOutletDirective;
protected _transactions: TransactionService<Transaction, State>;
protected _batchEditing = false;
protected _sortingOptions: ISortingOptions = { mode: 'multiple' };
protected _filterStrategy: IFilteringStrategy = new FilteringStrategy();
protected _autoGeneratedCols = [];
protected _dataView = [];
Expand Down Expand Up @@ -4527,14 +4556,15 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements

if (expression instanceof Array) {
for (const each of expression) {
if (each.dir === SortingDirection.None) {
this.gridAPI.remove_grouping_expression(each.fieldName);
}
this.gridAPI.prepare_sorting_expression([sortingState], each);
}
} else {
if (expression.dir === SortingDirection.None) {
this.gridAPI.remove_grouping_expression(expression.fieldName);
if (this._sortingOptions.mode === 'single') {
this.columns.forEach((col) => {
if (!(col.field === expression.fieldName)) {
this.clearSort(col.field);
}
});
}
this.gridAPI.prepare_sorting_expression([sortingState], expression);
}
Expand Down
35 changes: 9 additions & 26 deletions projects/igniteui-angular/src/lib/grids/grid/grid-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,16 @@ export class IgxGridAPIService extends GridBaseAPIService<GridType> implements G

public groupBy(expression: IGroupingExpression): void {
const groupingState = cloneArray(this.grid.groupingExpressions);
const sortingState = cloneArray(this.grid.sortingExpressions);
this.prepare_sorting_expression([sortingState, groupingState], expression);
this.prepare_grouping_expression([groupingState], expression);
this.grid.groupingExpressions = groupingState;
this.arrange_sorting_expressions();
}

public groupBy_multiple(expressions: IGroupingExpression[]): void {
const groupingState = cloneArray(this.grid.groupingExpressions);
const sortingState = cloneArray(this.grid.sortingExpressions);

for (const each of expressions) {
this.prepare_sorting_expression([sortingState, groupingState], each);
this.prepare_grouping_expression([groupingState], each);
}

this.grid.groupingExpressions = groupingState;
Expand All @@ -32,14 +30,11 @@ export class IgxGridAPIService extends GridBaseAPIService<GridType> implements G

public clear_groupby(name?: string | Array<string>) {
const groupingState = cloneArray(this.grid.groupingExpressions);
const sortingState = cloneArray(this.grid.sortingExpressions);

if (name) {
const names = typeof name === 'string' ? [name] : name;
const groupedCols = groupingState.filter((state) => names.indexOf(state.fieldName) < 0);
const newSortingExpr = sortingState.filter((state) => names.indexOf(state.fieldName) < 0);
this.grid.groupingExpressions = groupedCols;
this.grid.sortingExpressions = newSortingExpr;
names.forEach((colName) => {
const grExprIndex = groupingState.findIndex((exp) => exp.fieldName === colName);
const grpExpandState = this.grid.groupingExpansionState;
Expand All @@ -56,13 +51,6 @@ export class IgxGridAPIService extends GridBaseAPIService<GridType> implements G
// clear all
this.grid.groupingExpressions = [];
this.grid.groupingExpansionState = [];
for (const grExpr of groupingState) {
const sortExprIndex = sortingState.findIndex((exp) => exp.fieldName === grExpr.fieldName);
if (sortExprIndex > -1) {
sortingState.splice(sortExprIndex, 1);
}
}
this.grid.sortingExpressions = sortingState;
}
}

Expand Down Expand Up @@ -134,19 +122,14 @@ export class IgxGridAPIService extends GridBaseAPIService<GridType> implements G

public arrange_sorting_expressions() {
const groupingState = this.grid.groupingExpressions;
this.grid.sortingExpressions.sort((a, b) => {
const groupExprA = groupingState.find((expr) => expr.fieldName === a.fieldName);
const groupExprB = groupingState.find((expr) => expr.fieldName === b.fieldName);
if (groupExprA && groupExprB) {
return groupingState.indexOf(groupExprA) > groupingState.indexOf(groupExprB) ? 1 : -1;
} else if (groupExprA) {
return -1;
} else if (groupExprB) {
return 1;
} else {
return 0;
const sortingState = cloneArray(this.grid.sortingExpressions);
for (const grExpr of groupingState) {
const sortExprIndex = sortingState.findIndex((exp) => exp.fieldName === grExpr.fieldName);
if (sortExprIndex > -1) {
sortingState.splice(sortExprIndex, 1);
}
});
}
this.grid.sortingExpressions = sortingState;
}

public get_groupBy_record_id(gRow: IGroupByRecord): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
| gridAddRow:true:pipeTrigger
| gridRowPinning:id:true:pipeTrigger
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger:true
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger:true as pinnedData'>
| gridSort:sortingExpressions:groupingExpressions:sortStrategy:id:pipeTrigger:true as pinnedData'>
<div #pinContainer *ngIf='pinnedData.length > 0'
[ngClass]="{
'igx-grid__tr--pinned-bottom': !isRowPinningToTop,
Expand All @@ -70,7 +70,7 @@
| gridTransaction:id:pipeTrigger
| visibleColumns:hasVisibleColumns
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
| gridSort:sortingExpressions:groupingExpressions:sortStrategy:id:pipeTrigger
| gridGroupBy:groupingExpressions:groupingExpansionState:groupStrategy:groupsExpanded:id:groupsRecords:pipeTrigger
| gridPaging:paginator?.page:paginator?.perPage:id:pipeTrigger
| gridSummary:hasSummarizedColumns:summaryCalculationMode:summaryPosition:id:showSummaryOnCollapse:pipeTrigger:summaryPipeTrigger
Expand Down
Loading