diff --git a/CHANGELOG.md b/CHANGELOG.md index c562562268d..52c47c9b0a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes for each version of this project will be documented in this file. +## 8.2.0 + +### New Features +- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid` + - `uniqueColumnValuesStrategy` input is added. This property provides a callback for loading unique column values on demand. If this property is provided, the unique values it generates will be used by the Excel Style Filtering (instead of using the unique values from the data that is bound to the grid). + - `igxExcelStyleLoading` directive is added, which can be used to provide a custom loading template for the Excel Style Filtering. If this property is not provided, a default loading template will be used instead. +### General +- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid` + - **Breaking Change** `igxExcelStyleSortingTemplate` directive is renamed to `igxExcelStyleSorting`. + - **Breaking Change** `igxExcelStyleMovingTemplate` directive is renamed to `igxExcelStyleMoving`. + - **Breaking Change** `igxExcelStyleHidingTemplate` directive is renamed to `igxExcelStyleHiding`. + - **Breaking Change** `igxExcelStylePinningTemplate` directive is renamed to `igxExcelStylePinning`. + ## 8.1.3 - `IgxCombo` - Combo `onSelectionChange` events now emits the item(s) that were added to or removed from the collection: diff --git a/projects/igniteui-angular/migrations/migration-collection.json b/projects/igniteui-angular/migrations/migration-collection.json index 3f8599e3284..999c2997364 100644 --- a/projects/igniteui-angular/migrations/migration-collection.json +++ b/projects/igniteui-angular/migrations/migration-collection.json @@ -45,6 +45,11 @@ "version": "7.3.4", "description": "Updates Ignite UI for Angular from v7.2.0 to v7.3.4", "factory": "./update-7_3_4" + }, + "migration-10": { + "version": "8.2.0", + "description": "Updates Ignite UI for Angular from v8.1.x to v8.2.0", + "factory": "./update-8_2_0" } } } diff --git a/projects/igniteui-angular/migrations/update-8_2_0/changes/selectors.json b/projects/igniteui-angular/migrations/update-8_2_0/changes/selectors.json new file mode 100644 index 00000000000..78c0c033e8f --- /dev/null +++ b/projects/igniteui-angular/migrations/update-8_2_0/changes/selectors.json @@ -0,0 +1,25 @@ +{ + "$schema": "../../common/schema/selector.schema.json", + "changes": [ + { + "type": "directive", + "selector": "igxExcelStyleSortingTemplate", + "replaceWith": "igxExcelStyleSorting" + }, + { + "type": "directive", + "selector": "igxExcelStyleMovingTemplate", + "replaceWith": "igxExcelStyleMoving" + }, + { + "type": "directive", + "selector": "igxExcelStyleHidingTemplate", + "replaceWith": "igxExcelStyleHiding" + }, + { + "type": "directive", + "selector": "igxExcelStylePinningTemplate", + "replaceWith": "igxExcelStylePinning" + } + ] +} diff --git a/projects/igniteui-angular/migrations/update-8_2_0/index.spec.ts b/projects/igniteui-angular/migrations/update-8_2_0/index.spec.ts new file mode 100644 index 00000000000..8d9cd5a2eae --- /dev/null +++ b/projects/igniteui-angular/migrations/update-8_2_0/index.spec.ts @@ -0,0 +1,53 @@ +import * as path from 'path'; + +// tslint:disable:no-implicit-dependencies +import { virtualFs } from '@angular-devkit/core'; +import { EmptyTree } from '@angular-devkit/schematics'; +// tslint:disable-next-line:no-submodule-imports +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; + +describe('Update 8.2.0', () => { + let appTree: UnitTestTree; + const schematicRunner = new SchematicTestRunner('ig-migrate', path.join(__dirname, '../migration-collection.json')); + const configJson = { + defaultProject: 'testProj', + projects: { + testProj: { + sourceRoot: '/testSrc' + } + }, + schematics: { + '@schematics/angular:component': { + prefix: 'appPrefix' + } + } + }; + + beforeEach(() => { + appTree = new UnitTestTree(new EmptyTree()); + appTree.create('/angular.json', JSON.stringify(configJson)); + }); + + it('should update Excel Style Filtering template selectors', done => { + appTree.create( + '/testSrc/appPrefix/component/custom.component.html', + ` +
Sorting Template
+
Hiding Template
+
Moving Template
+
Pinning Template
+
`); + + const tree = schematicRunner.runSchematic('migration-10', {}, appTree); + expect(tree.readContent('/testSrc/appPrefix/component/custom.component.html')) + .toEqual( + ` +
Sorting Template
+
Hiding Template
+
Moving Template
+
Pinning Template
+
`); + + done(); + }); +}); diff --git a/projects/igniteui-angular/migrations/update-8_2_0/index.ts b/projects/igniteui-angular/migrations/update-8_2_0/index.ts new file mode 100644 index 00000000000..59cb3c16529 --- /dev/null +++ b/projects/igniteui-angular/migrations/update-8_2_0/index.ts @@ -0,0 +1,17 @@ +import { + Rule, + SchematicContext, + Tree +} from '@angular-devkit/schematics'; +import { UpdateChanges } from '../common/UpdateChanges'; + +const version = '8.2.0'; + +export default function(): Rule { + return (host: Tree, context: SchematicContext) => { + context.logger.info(`Applying migration for Ignite UI for Angular to version ${version}`); + + const update = new UpdateChanges(__dirname, host, context); + update.applyChanges(); + }; +} diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid/_excel-filtering-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid/_excel-filtering-component.scss index 2cd59e6db7f..0db606f3899 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/grid/_excel-filtering-component.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid/_excel-filtering-component.scss @@ -11,6 +11,10 @@ @include b(igx-excel-filter) { @extend %grid-excel-filter !optional; + @include e(loading) { + @extend %igx-excel-filter__loading !optional; + } + @include e(menu) { @extend %grid-excel-menu !optional; } diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid/_excel-filtering-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid/_excel-filtering-theme.scss index a416f346299..8ea653bb143 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/grid/_excel-filtering-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid/_excel-filtering-theme.scss @@ -16,6 +16,12 @@ display: block; } + %igx-excel-filter__loading { + display: flex; + justify-content: center; + align-items: center; + } + %grid-excel-icon { cursor: pointer; diff --git a/projects/igniteui-angular/src/lib/grids/README.md b/projects/igniteui-angular/src/lib/grids/README.md index 148e82cbe18..08550e0fd4b 100644 --- a/projects/igniteui-angular/src/lib/grids/README.md +++ b/projects/igniteui-angular/src/lib/grids/README.md @@ -174,6 +174,7 @@ Below is the list of all inputs that the developers may set to configure the gri |`filteringLogic`| FilteringLogic | The filtering logic of the grid. Defaults to _AND_. | |`filteringExpressionsTree`| IFilteringExpressionsTree | The filtering state of the grid. | |`emptyFilteredGridMessage`| string | The message displayed when there are no records and the grid is filtered.| +|`uniqueColumnValuesStrategy`| void | Property that provides a callback for loading unique column values on demand. If this property is provided, the unique values it generates will be used by the Excel Style Filtering. | |`sortingExpressions`|Array|The sorting state of the grid.| |`rowSelectable`|boolean|Enables multiple row selection, default is _false_.| |`height`|string|The height of the grid element. You can pass values such as `1000px`, `75%`, etc.| diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-search.component.html b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-search.component.html index 6bcf15400ba..39b8c430dd0 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-search.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-search.component.html @@ -19,21 +19,33 @@ - -
- - - {{ column.formatter && !item.isSpecial ? column.formatter(item.label) : column.dataType === 'number' ? (item.label | igxdecimal: - column.grid.locale) : column.dataType === 'date' ? (item.label | igxdate: column.grid.locale) : item.label }} - - -
-
+ +
+ + + {{ column.formatter && !item.isSpecial ? column.formatter(item.label) : column.dataType === 'number' ? (item.label | igxdecimal: + column.grid.locale) : column.dataType === 'date' ? (item.label | igxdate: column.grid.locale) : item.label }} + + +
+ + +
+ + +
+
+
+ + + + + diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-search.component.ts b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-search.component.ts index 31e9ed7c9ad..87e1fe80bfa 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-search.component.ts +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-search.component.ts @@ -3,16 +3,25 @@ import { Component, ChangeDetectionStrategy, Input, - ViewChild + ViewChild, + ChangeDetectorRef, + TemplateRef, + Directive } from '@angular/core'; import { IgxColumnComponent } from '../../column.component'; -import { IgxFilterOptions } from '../../../directives/filter/filter.directive'; import { IChangeCheckboxEventArgs } from '../../../checkbox/checkbox.component'; import { IgxInputDirective } from '../../../directives/input/input.directive'; import { DisplayDensity } from '../../../core/density'; import { IgxForOfDirective } from '../../../directives/for-of/for_of.directive'; import { FilterListItem } from './grid.excel-style-filtering.component'; +@Directive({ + selector: '[igxExcelStyleLoading]' +}) +export class IgxExcelStyleLoadingValuesTemplateDirective { + constructor(public template: TemplateRef) {} +} + /** * @hidden */ @@ -24,8 +33,24 @@ import { FilterListItem } from './grid.excel-style-filtering.component'; }) export class IgxExcelStyleSearchComponent implements AfterViewInit { + private _isLoading; + + public get isLoading() { + return this._isLoading; + } + + public set isLoading(value: boolean) { + this._isLoading = value; + if (!(this._cdr as any).destroyed) { + this._cdr.detectChanges(); + } + } + public searchValue: any; + @Input() + public grid: any; + @Input() public data: FilterListItem[]; @@ -43,9 +68,24 @@ export class IgxExcelStyleSearchComponent implements AfterViewInit { @ViewChild(IgxForOfDirective, { static: true }) protected virtDir: IgxForOfDirective; - constructor() { } + @ViewChild('defaultExcelStyleLoadingValuesTemplate', { read: TemplateRef, static: true }) + protected defaultExcelStyleLoadingValuesTemplate: TemplateRef; + + public get valuesLoadingTemplate() { + if (this.grid.excelStyleLoadingValuesTemplateDirective) { + return this.grid.excelStyleLoadingValuesTemplateDirective.template; + } else { + return this.defaultExcelStyleLoadingValuesTemplate; + } + } + + constructor(private _cdr: ChangeDetectorRef) { } public ngAfterViewInit() { + this.refreshSize(); + } + + public refreshSize() { requestAnimationFrame(() => { this.virtDir.recalcUpdateSizes(); }); diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.component.html b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.component.html index 0c1a3c8ff38..d1d6c1912b7 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.component.html @@ -124,6 +124,7 @@

{{ column.header || column.field }}

#excelStyleSearch [column]="column" [data]="listData" + [grid]="grid" [displayDensity]="grid.displayDensity"> diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.component.ts b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.component.ts index 5fd32802ade..1bcc4e17176 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.component.ts +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.component.ts @@ -52,28 +52,28 @@ export class FilterListItem { } @Directive({ - selector: '[igxExcelStyleSortingTemplate]' + selector: '[igxExcelStyleSorting]' }) export class IgxExcelStyleSortingTemplateDirective { constructor(public template: TemplateRef) {} } @Directive({ - selector: '[igxExcelStyleMovingTemplate]' + selector: '[igxExcelStyleMoving]' }) export class IgxExcelStyleMovingTemplateDirective { constructor(public template: TemplateRef) {} } @Directive({ - selector: '[igxExcelStyleHidingTemplate]' + selector: '[igxExcelStyleHiding]' }) export class IgxExcelStyleHidingTemplateDirective { constructor(public template: TemplateRef) {} } @Directive({ - selector: '[igxExcelStylePinningTemplate]' + selector: '[igxExcelStylePinning]' }) export class IgxExcelStylePinningTemplateDirective { constructor(public template: TemplateRef) {} @@ -343,28 +343,56 @@ export class IgxGridExcelStyleFilteringComponent implements OnDestroy, OnInit, A } public populateColumnData() { - let data = this.column.gridAPI.get_all_data(this.grid.id); - const gridExpressionsTree: IFilteringExpressionsTree = this.grid.filteringExpressionsTree; - const expressionsTree = new FilteringExpressionsTree(gridExpressionsTree.operator, gridExpressionsTree.fieldName); - - for (const operand of gridExpressionsTree.filteringOperands) { - if (operand instanceof FilteringExpressionsTree) { - const columnExprTree = operand as FilteringExpressionsTree; - if (columnExprTree.fieldName === this.column.field) { - break; - } - } - expressionsTree.filteringOperands.push(operand); + if (this.grid.uniqueColumnValuesStrategy) { + this.renderColumnValuesRemotely(); + } else { + this.renderColumnValuesFromData(); } + } + + private renderColumnValuesRemotely() { + this.excelStyleSearch.isLoading = true; + const expressionsTree: FilteringExpressionsTree = this.getColumnFilterExpressionsTree(); + + this.grid.uniqueColumnValuesStrategy(this.column, expressionsTree, (colVals: any[]) => { + const columnValues = (this.column.dataType === DataType.Date) ? + colVals.map(val => val ? val.toDateString() : val) : colVals; + + this.renderValues(columnValues); + this.excelStyleSearch.isLoading = false; + this.excelStyleSearch.refreshSize(); + }); + } + + public renderColumnValuesFromData() { + let data = this.column.gridAPI.get_all_data(this.grid.id); + const expressionsTree = this.getColumnFilterExpressionsTree(); if (expressionsTree.filteringOperands.length) { const state = { expressionsTree: expressionsTree }; data = DataUtil.filter(cloneArray(data), state); } - if (this.column.dataType === DataType.Date) { - this.uniqueValues = Array.from(new Set(data.map(record => - record[this.column.field] ? record[this.column.field].toDateString() : record[this.column.field]))); + const columnField = this.column.field; + const columnValues = (this.column.dataType === DataType.Date) ? + data.map(record => record[columnField] ? record[columnField].toDateString() : record[columnField]) : + data.map(record => record[columnField]); + + this.renderValues(columnValues); + } + + private renderValues(columnValues: any[]) { + this.generateUniqueValues(columnValues); + this.generateFilterValues(this.column.dataType === DataType.Date); + this.generateListData(); + } + + private generateUniqueValues(columnValues: any[]) { + this.uniqueValues = Array.from(new Set(columnValues)); + } + + private generateFilterValues(isDateColumn: boolean = false) { + if (isDateColumn) { this.filterValues = new Set(this.expressionsList.reduce((arr, e) => { if (e.expression.condition.name === 'in') { return [ ...arr, ...Array.from((e.expression.searchVal as Set).values()).map(v => @@ -373,7 +401,6 @@ export class IgxGridExcelStyleFilteringComponent implements OnDestroy, OnInit, A return [ ...arr, ...[e.expression.searchVal ? e.expression.searchVal.toDateString() : e.expression.searchVal] ]; }, [])); } else { - this.uniqueValues = Array.from(new Set(data.map(record => record[this.column.field]))); this.filterValues = new Set(this.expressionsList.reduce((arr, e) => { if (e.expression.condition.name === 'in') { return [ ...arr, ...Array.from((e.expression.searchVal as Set).values()) ]; @@ -381,6 +408,9 @@ export class IgxGridExcelStyleFilteringComponent implements OnDestroy, OnInit, A return [ ...arr, ...[e.expression.searchVal] ]; }, [])); } + } + + private generateListData() { this.listData = new Array(); const shouldUpdateSelection = this.areExpressionsSelectable() && this.areExpressionsValuesInTheList(); @@ -403,7 +433,26 @@ export class IgxGridExcelStyleFilteringComponent implements OnDestroy, OnInit, A this.addSelectAllItem(); - this.cdr.detectChanges(); + if (!(this.cdr as any).destroyed) { + this.cdr.detectChanges(); + } + } + + private getColumnFilterExpressionsTree() { + const gridExpressionsTree: IFilteringExpressionsTree = this.grid.filteringExpressionsTree; + const expressionsTree = new FilteringExpressionsTree(gridExpressionsTree.operator, gridExpressionsTree.fieldName); + + for (const operand of gridExpressionsTree.filteringOperands) { + if (operand instanceof FilteringExpressionsTree) { + const columnExprTree = operand as FilteringExpressionsTree; + if (columnExprTree.fieldName === this.column.field) { + break; + } + } + expressionsTree.filteringOperands.push(operand); + } + + return expressionsTree; } private addBooleanItems() { diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.module.ts b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.module.ts index 0555432ce8b..8a86532b58a 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.module.ts +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/grid.excel-style-filtering.module.ts @@ -1,5 +1,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { IgxExcelStyleLoadingValuesTemplateDirective } from './excel-style-search.component'; import { IgxGridExcelStyleFilteringComponent, IgxExcelStyleSortingTemplateDirective, @@ -29,6 +30,7 @@ import { IgxFilterModule } from '../../../directives/filter/filter.directive'; import { IgxToggleModule } from '../../../directives/toggle/toggle.directive'; import { IgxListModule } from '../../../list/list.component'; import { IgxExcelStyleSearchFilterPipe } from './excel-style-search.pipe'; +import { IgxProgressBarModule } from '../../../progressbar/progressbar.component'; /** * @hidden @@ -46,6 +48,7 @@ import { IgxExcelStyleSearchFilterPipe } from './excel-style-search.pipe'; IgxExcelStyleHidingTemplateDirective, IgxExcelStyleMovingTemplateDirective, IgxExcelStylePinningTemplateDirective, + IgxExcelStyleLoadingValuesTemplateDirective, IgxExcelStyleSearchFilterPipe ], exports: [ @@ -54,6 +57,7 @@ import { IgxExcelStyleSearchFilterPipe } from './excel-style-search.pipe'; IgxExcelStyleHidingTemplateDirective, IgxExcelStyleMovingTemplateDirective, IgxExcelStylePinningTemplateDirective, + IgxExcelStyleLoadingValuesTemplateDirective, IgxExcelStyleDateExpressionComponent ], imports: [ @@ -71,7 +75,8 @@ import { IgxExcelStyleSearchFilterPipe } from './excel-style-search.pipe'; IgxCheckboxModule, IgxFilterModule, IgxToggleModule, - IgxListModule + IgxListModule, + IgxProgressBarModule ], entryComponents: [ IgxGridExcelStyleFilteringComponent diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index ec5f392ec48..bd3023028d2 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -80,6 +80,7 @@ import { IgxSummaryRowComponent } from './summaries/summary-row.component'; import { IgxGridSelectionService, GridSelectionRange, IgxGridCRUDService, IgxRow, IgxCell } from '../core/grid-selection'; import { DragScrollDirection } from './drag-select.directive'; import { ICachedViewLoadedEventArgs, IgxTemplateOutletDirective } from '../directives/template-outlet/template_outlet.directive'; +import { IgxExcelStyleLoadingValuesTemplateDirective } from './filtering/excel-style/excel-style-search.component'; import { IgxExcelStyleSortingTemplateDirective, IgxExcelStylePinningTemplateDirective, @@ -1007,6 +1008,27 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements } } + /** + * An @Input property that provides a callback for loading unique column values on demand. + * If this property is provided, the unique values it generates will be used by the Excel Style Filtering. + * ```html + * + * ``` + * + * ```typescript + * public columnValuesStrategy = (column: IgxColumnComponent, + * filteringExpressionsTree: IFilteringExpressionsTree, + * done: (uniqueValues: any[]) => void) => { + * this.dataService.getColumnData(column, filteringExpressionsTree, uniqueValues => done(uniqueValues)); + * } + * ``` + * @memberof IgxGridBaseComponent + */ + @Input() + public uniqueColumnValuesStrategy: (column: IgxColumnComponent, + filteringExpressionsTree: IFilteringExpressionsTree, + done: (values: any[]) => void) => void; + /** * Emitted when `IgxGridCellComponent` is clicked. Returns the `IgxGridCellComponent`. * ```html @@ -1575,6 +1597,11 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements @ContentChild(IgxExcelStylePinningTemplateDirective, { read: IgxExcelStylePinningTemplateDirective, static: true }) public excelStylePinningTemplateDirective: IgxExcelStylePinningTemplateDirective; + /** + *@hidden + */ + @ContentChild(IgxExcelStyleLoadingValuesTemplateDirective, { read: IgxExcelStyleLoadingValuesTemplateDirective, static: true }) + public excelStyleLoadingValuesTemplateDirective: IgxExcelStyleLoadingValuesTemplateDirective; /** * @hidden diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts index 63849a55b98..bf405fb7b06 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts @@ -41,7 +41,8 @@ import { IgxGridFilteringMCHComponent, IgxTestExcelFilteringDatePickerComponent, IgxGridFilteringTemplateComponent, - IgxGridFilteringESFTemplatesComponent + IgxGridFilteringESFTemplatesComponent, + IgxGridFilteringESFLoadOnDemandComponent } from '../../test-utils/grid-samples.spec'; const FILTER_UI_ROW = 'igx-grid-filtering-row'; @@ -3505,6 +3506,7 @@ describe('IgxGrid - Filtering actions - Excel style filtering', () => { IgxGridFilteringComponent, IgxTestExcelFilteringDatePickerComponent, IgxGridFilteringESFTemplatesComponent, + IgxGridFilteringESFLoadOnDemandComponent, IgxGridFilteringMCHComponent ], imports: [ @@ -5616,6 +5618,38 @@ describe('IgxGrid - Filtering actions - Excel style filtering', () => { })); }); + describe('Load values on demand', () => { + let fix, grid; + beforeEach(fakeAsync(() => { + fix = TestBed.createComponent(IgxGridFilteringESFLoadOnDemandComponent); + grid = fix.componentInstance.grid; + fix.detectChanges(); + })); + + it('Verify unique values are loaded correctly in ESF search component.', fakeAsync(() => { + // Open excel style custom filtering dialog and wait a bit. + GridFunctions.clickExcelFilterIcon(fix, 'ProductName'); + fix.detectChanges(); + tick(400); + + // Verify items in search have not loaded yet and that the loading indicator is visible. + const searchComponent = GridFunctions.getExcelStyleSearchComponent(fix); + let listItems = searchComponent.querySelectorAll('igx-list-item'); + expect(listItems.length).toBe(0, 'incorrect rendered list items count'); + let loadingIndicator = GridFunctions.getExcelFilteringLoadingIndicator(fix); + expect(loadingIndicator).not.toBeNull('esf loading indicator is not visible'); + + // Wait for items to load. + tick(650); + + // Verify items in search have loaded and that the loading indicator is not visible. + listItems = searchComponent.querySelectorAll('igx-list-item'); + expect(listItems.length).toBe(6, 'incorrect rendered list items count'); + loadingIndicator = GridFunctions.getExcelFilteringLoadingIndicator(fix); + expect(loadingIndicator).toBeNull('esf loading indicator is visible'); + })); + }); + describe(null, () => { let fix, grid; beforeEach(fakeAsync(() => { diff --git a/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts b/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts index 41c15b462b2..f9cdd1de7fa 100644 --- a/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts @@ -744,6 +744,12 @@ export class GridFunctions { return excelMenu.querySelector('igx-excel-style-column-moving'); } + public static getExcelFilteringLoadingIndicator(fix: ComponentFixture) { + const searchComponent = GridFunctions.getExcelStyleSearchComponent(fix); + const loadingIndicator = searchComponent.querySelector('.igx-excel-filter__loading'); + return loadingIndicator; + } + public static getColumnCells(fix, columnKey) { const allCells = fix.debugElement.queryAll(By.css('igx-grid-cell')); return allCells.filter((cell) => cell.componentInstance.column.field === columnKey); diff --git a/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts b/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts index 44aea88428b..b5f23ea1d03 100644 --- a/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts @@ -11,6 +11,8 @@ import { IgxColumnComponent } from '../grids/column.component'; import { IgxTransactionService } from '../services'; import { IgxFilteringOperand } from '../data-operations/filtering-condition'; import { ExpressionUI } from '../grids/filtering/grid-filtering.service'; +import { IFilteringExpressionsTree } from '../data-operations/filtering-expressions-tree'; +import { FilteringStrategy } from '../data-operations/filtering-strategy'; @Component({ template: `
@@ -933,6 +935,32 @@ export class IgxGridFilteringComponent extends BasicGridComponent { } } +@Component({ + template: ` + + + + + + + ` +}) +export class IgxGridFilteringESFLoadOnDemandComponent extends BasicGridComponent { + private _filteringStrategy = new FilteringStrategy(); + public data = SampleTestData.excelFilteringData(); + + public columnValuesStrategy = (column: IgxColumnComponent, + columnExprTree: IFilteringExpressionsTree, + done: (uniqueValues: any[]) => void) => { + setTimeout(() => { + const filteredData = this._filteringStrategy.filter(this.data, columnExprTree); + const columnValues = filteredData.map(record => record[column.field]); + done(columnValues); + }, 1000); + } +} + @Component({ template: ` -
Sorting Template
-
Hiding Template
-
Moving Template
-
Pinning Template
+
Sorting Template
+
Hiding Template
+
Moving Template
+
Pinning Template
` }) export class IgxGridFilteringESFTemplatesComponent extends BasicGridComponent { diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 267a88a52dd..a0aff036f8a 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -173,6 +173,11 @@ export class AppComponent implements OnInit { icon: 'view_column', name: 'Grid Filter Template' }, + { + link: '/gridEsfLoadOnDemand', + icon: 'view_column', + name: 'Grid ESF Load On Demand' + }, { link: '/gridColumnMoving', icon: 'view_column', diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 9f92623bcac..00bf4f08bfb 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -106,6 +106,7 @@ import { GridFilterTemplateSampleComponent } from './grid-filter-template/grid-f import { GridMRLConfigSampleComponent } from './grid-multi-row-layout-config/grid-mrl-config.sample'; import { GridMRLCustomNavigationSampleComponent } from './grid-mrl-custom-navigation/grid-mrl-custom-navigation'; import { GridClipboardSampleComponent } from './grid-clipboard/grid-clipboard.sample'; +import { GridEsfLoadOnDemandComponent } from './grid-esf-load-on-demand/grid-esf-load-on-demand.component'; @@ -204,7 +205,8 @@ const components = [ GridSearchBoxComponent, GridSearchComponent, GridFilterTemplateSampleComponent, - GridClipboardSampleComponent + GridClipboardSampleComponent, + GridEsfLoadOnDemandComponent ]; @NgModule({ diff --git a/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.component.html b/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.component.html new file mode 100644 index 00000000000..920b6c71b74 --- /dev/null +++ b/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.component.html @@ -0,0 +1,28 @@ +
+ + Allows loading unique column values into the Excel Style Filtering on demand. + + +
+
+
+ +
+ + + + + + + + + + +
+
+
diff --git a/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.component.scss b/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.component.scss new file mode 100644 index 00000000000..7bb6f8bd0ba --- /dev/null +++ b/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.component.scss @@ -0,0 +1,4 @@ +.density-chooser { + margin-bottom: 16px; + max-width: 900px; +} diff --git a/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.component.ts b/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.component.ts new file mode 100644 index 00000000000..9dd61e08229 --- /dev/null +++ b/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.component.ts @@ -0,0 +1,41 @@ +import { Component, ViewChild, OnInit } from '@angular/core'; +import { IgxGridComponent, IgxColumnComponent, IFilteringExpressionsTree } from 'igniteui-angular'; +import { SAMPLE_DATA } from '../shared/sample-data'; +import { GridESFLoadOnDemandService } from './grid-esf-load-on-demand.service'; + +@Component({ + selector: 'app-grid-esf-load-on-demand', + templateUrl: './grid-esf-load-on-demand.component.html', + styleUrls: ['./grid-esf-load-on-demand.component.scss'] +}) +export class GridEsfLoadOnDemandComponent implements OnInit { + + private esfService = new GridESFLoadOnDemandService(); + + public data: Array; + public density = 'comfortable'; + public displayDensities; + + @ViewChild('grid1', { static: true }) + public grid1: IgxGridComponent; + + public columnValuesStrategy = (column: IgxColumnComponent, + columnExprTree: IFilteringExpressionsTree, + done: (uniqueValues: any[]) => void) => { + this.esfService.getColumnData(column, columnExprTree, uniqueValues => done(uniqueValues)); + } + + public ngOnInit(): void { + this.displayDensities = [ + { label: 'comfortable', selected: this.density === 'comfortable', togglable: true }, + { label: 'cosy', selected: this.density === 'cosy', togglable: true }, + { label: 'compact', selected: this.density === 'compact', togglable: true } + ]; + + this.data = this.esfService.getRecordsData(); + } + + public selectDensity(event) { + this.density = this.displayDensities[event.index].label; + } +} diff --git a/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.service.ts b/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.service.ts new file mode 100644 index 00000000000..7cb8441093d --- /dev/null +++ b/src/app/grid-esf-load-on-demand/grid-esf-load-on-demand.service.ts @@ -0,0 +1,18 @@ +import { IgxColumnComponent, IFilteringExpressionsTree, FilteringStrategy } from 'igniteui-angular'; +import { SAMPLE_DATA } from '../shared/sample-data'; + +export class GridESFLoadOnDemandService { + private _filteringStrategy = new FilteringStrategy(); + + public getRecordsData() { + return SAMPLE_DATA.slice(0); + } + + public getColumnData(column: IgxColumnComponent, columnExprTree: IFilteringExpressionsTree, done: (colVals: any[]) => void) { + setTimeout(() => { + const filteredData = this._filteringStrategy.filter(this.getRecordsData(), columnExprTree); + const columnValues = filteredData.map(record => record[column.field]); + done(columnValues); + }, 1000); + } +} diff --git a/src/app/routing.ts b/src/app/routing.ts index 6a2ac2e9a7a..daf39318f5a 100644 --- a/src/app/routing.ts +++ b/src/app/routing.ts @@ -84,6 +84,7 @@ import { GridFilterTemplateSampleComponent } from './grid-filter-template/grid-f import { GridMRLConfigSampleComponent } from './grid-multi-row-layout-config/grid-mrl-config.sample'; import { GridMRLCustomNavigationSampleComponent } from './grid-mrl-custom-navigation/grid-mrl-custom-navigation'; import { GridClipboardSampleComponent } from './grid-clipboard/grid-clipboard.sample'; +import { GridEsfLoadOnDemandComponent } from './grid-esf-load-on-demand/grid-esf-load-on-demand.component'; const appRoutes = [ { @@ -308,6 +309,10 @@ const appRoutes = [ path: 'gridFilterTemplate', component: GridFilterTemplateSampleComponent }, + { + path: 'gridEsfLoadOnDemand', + component: GridEsfLoadOnDemandComponent + }, { path: 'gridClipboard', component: GridClipboardSampleComponent