From 04f736c073c566f095c4bf33c2cbad3443d049df Mon Sep 17 00:00:00 2001 From: Ghislain Beaulac Date: Wed, 20 Feb 2019 18:10:32 -0500 Subject: [PATCH 1/5] poc(editor): start concept for rendering angular component as filter --- src/app/app.module.ts | 3 + .../examples/custom-angularComponentEditor.ts | 6 +- .../examples/custom-angularComponentFilter.ts | 173 ++++++++++++++++++ .../examples/filter-ng-select.component.ts | 30 +++ 4 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 src/app/examples/custom-angularComponentFilter.ts create mode 100644 src/app/examples/filter-ng-select.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1335896b9..ea34f1ec2 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -10,6 +10,7 @@ import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { AppComponent } from './app.component'; import { EditorNgSelectComponent } from './examples/editor-ng-select.component'; +import { FilterNgSelectComponent } from './examples/filter-ng-select.component'; import { GridAddItemComponent } from './examples/grid-additem.component'; import { GridBasicComponent } from './examples/grid-basic.component'; import { GridClientSideComponent } from './examples/grid-clientside.component'; @@ -72,6 +73,7 @@ export function appInitializerFactory(translate: TranslateService, injector: Inj declarations: [ AppComponent, EditorNgSelectComponent, + FilterNgSelectComponent, GridAddItemComponent, GridBasicComponent, GridClientSideComponent, @@ -126,6 +128,7 @@ export function appInitializerFactory(translate: TranslateService, injector: Inj entryComponents: [ // dynamically created components EditorNgSelectComponent, + FilterNgSelectComponent, RowDetailPreloadComponent, RowDetailViewComponent, ], diff --git a/src/app/examples/custom-angularComponentEditor.ts b/src/app/examples/custom-angularComponentEditor.ts index 5bb683b47..acf069827 100644 --- a/src/app/examples/custom-angularComponentEditor.ts +++ b/src/app/examples/custom-angularComponentEditor.ts @@ -27,12 +27,12 @@ export class CustomAngularComponentEditor implements Editor { /** Angular Util Service */ get angularUtilService(): AngularUtilService { - return this.columnDef && this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor.params.angularUtilService; + return this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor.params.angularUtilService; } /** Get the Collection */ get collection(): any[] { - return this.columnDef && this.columnDef && this.columnDef.internalColumnEditor.collection || []; + return this.columnDef && this.columnDef.internalColumnEditor.collection || []; } /** Get Column Definition object */ @@ -56,7 +56,7 @@ export class CustomAngularComponentEditor implements Editor { init() { if (!this.columnEditor || !this.columnEditor.params.component) { - throw new Error(`[Angular-Slickgrid] For the Editors.angularComponent to work properly, you need to provide your component to the "component" property and make sure to add it to your "entryComponents" array. + throw new Error(`[Angular-Slickgrid] For Editor with Angular Component to work properly, you need to provide your component to the "component" property and make sure to add it to your "entryComponents" array. Example: this.columnDefs = [{ id: 'title', field: 'title', editor: { component: MyComponent, model: Editors.angularComponent, collection: [...] },`); } if (this.columnEditor && this.columnEditor.params.component) { diff --git a/src/app/examples/custom-angularComponentFilter.ts b/src/app/examples/custom-angularComponentFilter.ts new file mode 100644 index 000000000..f3aa16734 --- /dev/null +++ b/src/app/examples/custom-angularComponentFilter.ts @@ -0,0 +1,173 @@ +import { + AngularUtilService, + Column, + ColumnFilter, + Filter, + FilterArguments, + FilterCallback, + GridOption, + OperatorType, + OperatorString, + SearchTerm, +} from './../modules/angular-slickgrid'; +import { ComponentRef } from '@angular/core'; + +// using external non-typed js libraries +declare var $: any; + +export class CustomAngularComponentFilter implements Filter { + private _clearFilterTriggered = false; + private $filterElm: any; + + /** Angular Component Reference */ + componentRef: ComponentRef; + + grid: any; + searchTerms: SearchTerm[]; + columnDef: Column; + callback: FilterCallback; + operator: OperatorType | OperatorString = OperatorType.equal; + + constructor() {} + + /** Angular Util Service (could be inside the Grid Options Params or the Filter Params ) */ + get angularUtilService(): AngularUtilService { + let angularUtilService = this.gridOptions && this.gridOptions.params && this.gridOptions.params.angularUtilService; + if (!angularUtilService || !(angularUtilService instanceof AngularUtilService)) { + angularUtilService = this.columnFilter && this.columnFilter.params && this.columnFilter.params.angularUtilService; + } + return angularUtilService; + } + + /** Get the Collection */ + get collection(): any[] { + return this.columnFilter && this.columnFilter.collection || []; + } + + /** Getter for the Filter Operator */ + get columnFilter(): ColumnFilter { + return this.columnDef && this.columnDef.filter || {}; + } + + /** Getter for the Grid Options pulled through the Grid Object */ + get gridOptions(): GridOption { + return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {}; + } + + /** + * Initialize the Filter + */ + init(args: FilterArguments) { + this.grid = args.grid; + this.callback = args.callback; + this.columnDef = args.columnDef; + this.searchTerms = args.searchTerms || []; + + if (!this.columnFilter || !this.columnFilter.params.component || !(this.angularUtilService instanceof AngularUtilService)) { + throw new Error(`[Angular-Slickgrid] For Filter with Angular Component to work properly, you need to provide your component to the "component" property and make sure to add it to your "entryComponents" array. + You also need to provide the "AngularUtilService" via the Filter Params OR the Grid Options Params + Example: this.columnDefs = [{ id: 'title', field: 'title', filter: { model: CustomAngularComponentFilter, collection: [...], params: { component: MyComponent, angularUtilService: this.angularUtilService }}]; + OR this.columnDefs = [{ id: 'title', field: 'title', filter: { model: CustomAngularComponentFilter, collection: [...] }]; this.gridOptions = { params: { angularUtilService: this.angularUtilService }}`); + } + + if (this.columnFilter && this.columnFilter.params.component) { + const $headerElm = this.grid.getHeaderRowColumn(this.columnDef.id); + $($headerElm).empty(); + this.componentRef = this.columnFilter.params.angularUtilService.createAngularComponentAppendToDom(this.columnFilter.params.component, $headerElm); + Object.assign(this.componentRef.instance, { collection: this.collection }); + + this.componentRef.instance.onModelChanged.subscribe((item) => { + console.warn('item changed', item); + }); + } + + // // filter input can only have 1 search term, so we will use the 1st array index if it exist + // const searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms[0]) || ''; + + // // step 1, create HTML string template + // const filterTemplate = this.buildTemplateHtmlString(); + + // // step 2, create the DOM Element of the filter & initialize it if searchTerm is filled + // this.$filterElm = this.createDomElement(filterTemplate, searchTerm); + + // // step 3, subscribe to the keyup event and run the callback when that happens + // this.$filterElm.keyup((e: any) => { + // const value = e && e.target && e.target.value || ''; + // if (this._clearFilterTriggered) { + // this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered }); + // this._clearFilterTriggered = false; // reset flag for next use + // this.$filterElm.removeClass('filled'); + // } else { + // value === '' ? this.$filterElm.removeClass('filled') : this.$filterElm.addClass('filled'); + // this.callback(e, { columnDef: this.columnDef, searchTerms: [value] }); + // } + // }); + } + + /** + * Clear the filter value + */ + clear() { + if (this.$filterElm) { + this._clearFilterTriggered = true; + this.$filterElm.val(''); + this.$filterElm.trigger('keyup'); + } + } + + /** + * destroy the filter + */ + destroy() { + if (this.$filterElm) { + this.$filterElm.off('keyup').remove(); + } + } + + /** + * Set value(s) on the DOM element + */ + setValues(values) { + if (values) { + this.$filterElm.val(values); + } + } + + // + // private functions + // ------------------ + + /** + * Create the HTML template as a string + */ + private buildTemplateHtmlString() { + let placeholder = (this.gridOptions) ? (this.gridOptions.defaultFilterPlaceholder || '') : ''; + if (this.columnFilter && this.columnFilter.placeholder) { + placeholder = this.columnFilter.placeholder; + } + return ``; + } + + /** + * From the html template string, create a DOM element + * @param filterTemplate + */ + private createDomElement(filterTemplate: string, searchTerm?: SearchTerm) { + const $headerElm = this.grid.getHeaderRowColumn(this.columnDef.id); + $($headerElm).empty(); + + // create the DOM element & add an ID and filter class + const $filterElm = $(filterTemplate); + + $filterElm.val(searchTerm); + $filterElm.attr('id', `filter-${this.columnDef.id}`); + $filterElm.data('columnId', this.columnDef.id); + + // append the new DOM element to the header row + if ($filterElm && typeof $filterElm.appendTo === 'function') { + $filterElm.appendTo($headerElm); + } + + return $filterElm; + } +} diff --git a/src/app/examples/filter-ng-select.component.ts b/src/app/examples/filter-ng-select.component.ts new file mode 100644 index 000000000..00fdce4cc --- /dev/null +++ b/src/app/examples/filter-ng-select.component.ts @@ -0,0 +1,30 @@ +import { Component } from '@angular/core'; +import { Subject } from 'rxjs'; + +@Component({ + template: ` + + + {{ item?.name }} + + ` +}) +export class FilterNgSelectComponent { + selectedId: string; + selectedItem: any; + collection; // this will be filled by the collection of your column definition + onModelChanged = new Subject(); // object + + onChange(item: any) { + this.selectedItem = item; + this.onModelChanged.next(item); + } +} From 6f135f4a02eb924ebffc974f18b332d7927d7f1e Mon Sep 17 00:00:00 2001 From: Ghislain Beaulac Date: Wed, 20 Feb 2019 20:35:50 -0500 Subject: [PATCH 2/5] fix(filter): regression bug filtering data doesn't always refresh grid - partially revert commit bb62c0 by putting back onRowsChanged event however we will use updateRow instead of invalidateRows which has the side effect dealt with in that previous commit bb62c0 --- .../components/angular-slickgrid.component.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts index 8baa10e29..eb93ed1ca 100644 --- a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts +++ b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts @@ -474,6 +474,18 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn this._eventHandler.subscribe(dataView.onRowCountChanged, (e: any, args: any) => { grid.invalidate(); }); + + // without this, filtering data with local dataset will not always show correctly + // also don't use "invalidateRows" since it destroys the entire row and as bad user experience when updating a row + // see commit: https://github.com/ghiscoding/Angular-Slickgrid/commit/bb62c0aa2314a5d61188ff005ccb564577f08805 + if (gridOptions && gridOptions.enableFiltering) { + this._eventHandler.subscribe(dataView.onRowsChanged, (e: any, args: any) => { + if (args && args.rows && Array.isArray(args.rows)) { + args.rows.forEach((row) => grid.updateRow(row)); + grid.render(); + } + }); + } } // does the user have a colspan callback? From 2763c55b5a57d330a3161fc6aab022558fbeaef4 Mon Sep 17 00:00:00 2001 From: Ghislain Beaulac Date: Wed, 20 Feb 2019 21:07:11 -0500 Subject: [PATCH 3/5] feat(editor): finalize Custom Filter with Angular Component --- src/app/app.component.html | 2 +- .../examples/custom-angularComponentEditor.ts | 12 +- .../examples/custom-angularComponentFilter.ts | 105 ++++-------------- src/app/examples/custom-inputFilter.ts | 2 +- .../examples/filter-ng-select.component.ts | 6 +- src/app/examples/grid-angular.component.html | 6 +- src/app/examples/grid-angular.component.scss | 16 +++ src/app/examples/grid-angular.component.ts | 47 ++++++-- src/app/examples/grid-editor.component.html | 2 +- .../filters/autoCompleteFilter.ts | 2 +- .../filters/compoundDateFilter.ts | 5 +- .../filters/compoundInputFilter.ts | 2 +- .../angular-slickgrid/filters/inputFilter.ts | 2 +- .../formatters/complexObjectFormatter.ts | 13 ++- src/index.html | 2 +- 15 files changed, 115 insertions(+), 109 deletions(-) create mode 100644 src/app/examples/grid-angular.component.scss diff --git a/src/app/app.component.html b/src/app/app.component.html index c6daf9ab5..897e2759c 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -92,7 +92,7 @@ 21- Row Detail View
  • - 22- Editors Angular Components + 22- Use of Angular Components
  • diff --git a/src/app/examples/custom-angularComponentEditor.ts b/src/app/examples/custom-angularComponentEditor.ts index 22a416229..9b9341407 100644 --- a/src/app/examples/custom-angularComponentEditor.ts +++ b/src/app/examples/custom-angularComponentEditor.ts @@ -78,8 +78,12 @@ export class CustomAngularComponentEditor implements Editor { if (this.columnEditor && this.columnEditor.params.component) { const componentOutput = this.angularUtilService.createAngularComponentAppendToDom(this.columnEditor.params.component, this.args.container); this.componentRef = componentOutput && componentOutput.componentRef; + + // here we override the collection object of the Angular Component + // but technically you can pass any values you wish to your Component Object.assign(this.componentRef.instance, { collection: this.collection }); + // when our model (item object) changes, we'll call a save of the slickgrid editor this.componentRef.instance.onModelChanged.subscribe((item) => { this.save(); }); @@ -105,29 +109,29 @@ export class CustomAngularComponentEditor implements Editor { } } + /** optional, implement a hide method on your Angular Component */ hide() { - // optional, implement a hide method on your Angular Component if (this.componentRef && this.componentRef.instance && typeof this.componentRef.instance.hide === 'function') { this.componentRef.instance.hide(); } } + /** optional, implement a show method on your Angular Component */ show() { - // optional, implement a show method on your Angular Component if (this.componentRef && this.componentRef.instance && typeof this.componentRef.instance.show === 'function') { this.componentRef.instance.show(); } } + /** destroy the Angular Component */ destroy() { - // destroy the Angular Component if (this.componentRef && this.componentRef.destroy) { this.componentRef.destroy(); } } + /** optional, implement a focus method on your Angular Component */ focus() { - // optional, implement a focus method on your Angular Component if (this.componentRef && this.componentRef.instance && typeof this.componentRef.instance.focus === 'function') { this.componentRef.instance.focus(); } diff --git a/src/app/examples/custom-angularComponentFilter.ts b/src/app/examples/custom-angularComponentFilter.ts index f3aa16734..d33913c7c 100644 --- a/src/app/examples/custom-angularComponentFilter.ts +++ b/src/app/examples/custom-angularComponentFilter.ts @@ -16,9 +16,6 @@ import { ComponentRef } from '@angular/core'; declare var $: any; export class CustomAngularComponentFilter implements Filter { - private _clearFilterTriggered = false; - private $filterElm: any; - /** Angular Component Reference */ componentRef: ComponentRef; @@ -44,7 +41,7 @@ export class CustomAngularComponentFilter implements Filter { return this.columnFilter && this.columnFilter.collection || []; } - /** Getter for the Filter Operator */ + /** Getter for the Column Filter */ get columnFilter(): ColumnFilter { return this.columnDef && this.columnDef.filter || {}; } @@ -71,56 +68,38 @@ export class CustomAngularComponentFilter implements Filter { } if (this.columnFilter && this.columnFilter.params.component) { - const $headerElm = this.grid.getHeaderRowColumn(this.columnDef.id); - $($headerElm).empty(); - this.componentRef = this.columnFilter.params.angularUtilService.createAngularComponentAppendToDom(this.columnFilter.params.component, $headerElm); - Object.assign(this.componentRef.instance, { collection: this.collection }); - - this.componentRef.instance.onModelChanged.subscribe((item) => { - console.warn('item changed', item); + // use a delay to make sure Angular ran at least a full cycle and it finished rendering the Component before hooking onto it + // else we get the infamous error "ExpressionChangedAfterItHasBeenCheckedError" + setTimeout(() => { + const $headerElm = this.grid.getHeaderRowColumn(this.columnDef.id); + $($headerElm).empty(); + const componentOuput = this.angularUtilService.createAngularComponentAppendToDom(this.columnFilter.params.component, $headerElm); + this.componentRef = componentOuput.componentRef; + + // here we override the collection object of the Angular Component + // but technically you can pass any values you wish to your Component + Object.assign(componentOuput.componentRef.instance, { collection: this.collection }); + + componentOuput.componentRef.instance.onModelChanged.subscribe((item) => { + this.callback(undefined, { columnDef: this.columnDef, operator: this.operator, searchTerms: [item.id] }); + }); }); } - - // // filter input can only have 1 search term, so we will use the 1st array index if it exist - // const searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms[0]) || ''; - - // // step 1, create HTML string template - // const filterTemplate = this.buildTemplateHtmlString(); - - // // step 2, create the DOM Element of the filter & initialize it if searchTerm is filled - // this.$filterElm = this.createDomElement(filterTemplate, searchTerm); - - // // step 3, subscribe to the keyup event and run the callback when that happens - // this.$filterElm.keyup((e: any) => { - // const value = e && e.target && e.target.value || ''; - // if (this._clearFilterTriggered) { - // this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered }); - // this._clearFilterTriggered = false; // reset flag for next use - // this.$filterElm.removeClass('filled'); - // } else { - // value === '' ? this.$filterElm.removeClass('filled') : this.$filterElm.addClass('filled'); - // this.callback(e, { columnDef: this.columnDef, searchTerms: [value] }); - // } - // }); } /** * Clear the filter value */ clear() { - if (this.$filterElm) { - this._clearFilterTriggered = true; - this.$filterElm.val(''); - this.$filterElm.trigger('keyup'); + if (this.componentRef && this.componentRef.instance && this.componentRef.instance.hasOwnProperty('selectedId')) { + this.componentRef.instance.selectedId = 0; } } - /** - * destroy the filter - */ + /** destroy the Angular Component */ destroy() { - if (this.$filterElm) { - this.$filterElm.off('keyup').remove(); + if (this.componentRef && this.componentRef.destroy) { + this.componentRef.destroy(); } } @@ -128,46 +107,8 @@ export class CustomAngularComponentFilter implements Filter { * Set value(s) on the DOM element */ setValues(values) { - if (values) { - this.$filterElm.val(values); - } - } - - // - // private functions - // ------------------ - - /** - * Create the HTML template as a string - */ - private buildTemplateHtmlString() { - let placeholder = (this.gridOptions) ? (this.gridOptions.defaultFilterPlaceholder || '') : ''; - if (this.columnFilter && this.columnFilter.placeholder) { - placeholder = this.columnFilter.placeholder; - } - return ``; - } - - /** - * From the html template string, create a DOM element - * @param filterTemplate - */ - private createDomElement(filterTemplate: string, searchTerm?: SearchTerm) { - const $headerElm = this.grid.getHeaderRowColumn(this.columnDef.id); - $($headerElm).empty(); - - // create the DOM element & add an ID and filter class - const $filterElm = $(filterTemplate); - - $filterElm.val(searchTerm); - $filterElm.attr('id', `filter-${this.columnDef.id}`); - $filterElm.data('columnId', this.columnDef.id); - - // append the new DOM element to the header row - if ($filterElm && typeof $filterElm.appendTo === 'function') { - $filterElm.appendTo($headerElm); + if (this.componentRef && this.componentRef.instance && this.componentRef.instance.hasOwnProperty('selectedId')) { + this.componentRef.instance.selectedId = values; } - - return $filterElm; } } diff --git a/src/app/examples/custom-inputFilter.ts b/src/app/examples/custom-inputFilter.ts index fcbce4eaf..5ddf47799 100644 --- a/src/app/examples/custom-inputFilter.ts +++ b/src/app/examples/custom-inputFilter.ts @@ -24,7 +24,7 @@ export class CustomInputFilter implements Filter { constructor() {} - /** Getter for the Filter Operator */ + /** Getter for the Column Filter */ get columnFilter(): ColumnFilter { return this.columnDef && this.columnDef.filter || {}; } diff --git a/src/app/examples/filter-ng-select.component.ts b/src/app/examples/filter-ng-select.component.ts index 00fdce4cc..876c14916 100644 --- a/src/app/examples/filter-ng-select.component.ts +++ b/src/app/examples/filter-ng-select.component.ts @@ -1,14 +1,16 @@ import { Component } from '@angular/core'; import { Subject } from 'rxjs'; +// the appendTo="body" (necessary for SlickGrid filter) requires the body to be position relative like so +// @Component({ template: ` - diff --git a/src/app/examples/grid-angular.component.html b/src/app/examples/grid-angular.component.html index c1a858906..b191aafab 100644 --- a/src/app/examples/grid-angular.component.html +++ b/src/app/examples/grid-angular.component.html @@ -4,7 +4,7 @@

    {{title}}


    - +
    diff --git a/src/app/examples/grid-angular.component.scss b/src/app/examples/grid-angular.component.scss new file mode 100644 index 000000000..9e5990c28 --- /dev/null +++ b/src/app/examples/grid-angular.component.scss @@ -0,0 +1,16 @@ +h3 { + font-style: normal; + color: #3d3d3d; +} +.subtitle { + font-size: 18px; +} +.ng-select.custom { + border:0px; + max-height: 27px; + border-radius: 0; +} +.ng-input { + padding-top: -4px !important; + padding-left: 4px !important; +} diff --git a/src/app/examples/grid-angular.component.ts b/src/app/examples/grid-angular.component.ts index 883ffe8ee..a27a45181 100644 --- a/src/app/examples/grid-angular.component.ts +++ b/src/app/examples/grid-angular.component.ts @@ -1,4 +1,5 @@ -import { Component, Injectable, OnInit, EmbeddedViewRef } from '@angular/core'; +import { CustomAngularComponentFilter } from './custom-angularComponentFilter'; +import { Component, Injectable, OnInit, ViewEncapsulation } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { AngularGridInstance, @@ -15,6 +16,7 @@ import { import { EditorNgSelectComponent } from './editor-ng-select.component'; import { CustomAngularComponentEditor } from './custom-angularComponentEditor'; import { CustomTitleFormatterComponent } from './custom-titleFormatter.component'; +import { FilterNgSelectComponent } from './filter-ng-select.component'; // using external non-typed js libraries declare var Slick: any; @@ -23,20 +25,31 @@ declare var $: any; const NB_ITEMS = 100; @Component({ - templateUrl: './grid-angular.component.html' + templateUrl: './grid-angular.component.html', + styleUrls: ['./grid-angular.component.scss'], + encapsulation: ViewEncapsulation.None }) @Injectable() export class GridAngularComponent implements OnInit { - title = 'Example 22: Multiple Angular Components'; + title = 'Example 22: Use of Angular Components'; subTitle = ` +

    Filters, Editors, AsyncPostRender with Angular Components

    Grid with usage of Angular Components as Editor & AsyncPostRender (similar to Formatter).
    • Support of Angular Component as Custom Editor (click on any "Assignee" name cell)
      • That column uses ng-select as a custom editor as an Angular Component -
      • Increased Grid Options "rowHeight" to 45 so that the "ng-select" fits in the cell. Ideally it would be better to override the ng-select css styling to change it's max height
      • +
      • Increased Grid Options "rowHeight" & "headerRowHeight" to 45 so that the "ng-select" fits in the cell. Ideally it would be better to override the ng-select css styling to change it's max height
      +
    • Support of Angular Component as Custom Filter ("Assignee" columns), which also uses "ng-select"
    • The 2nd "Assignee" column (showing in bold text) uses "asyncPostRender" with an Angular Component
    • +
        +
      • Why can't we use Angular Component as Customer Formatter and why do I see a slight delay in loading the data?
      • +
      • It's totally normal since SlickGrid Formatters only accept strings (synchronously), + so we cannot use that (Angular requires at least 1 full cycle to render the element), so we are left with SlickGrid "asyncPostRender" and + it works but as the name suggest it's async users might see noticeable delay in loading the data +
      • +
    `; @@ -51,6 +64,7 @@ export class GridAngularComponent implements OnInit { updatedObject: any; selectedLanguage = 'en'; assignees = [ + { id: '', name: '' }, { id: '1', name: 'John' }, { id: '2', name: 'Pierre' }, { id: '3', name: 'Paul' }, @@ -91,10 +105,18 @@ export class GridAngularComponent implements OnInit { minWidth: 100, filterable: true, sortable: true, - type: FieldType.string, + filter: { + model: new CustomAngularComponentFilter(), // create a new instance to make each Filter independent from each other + collection: this.assignees, + params: { + component: FilterNgSelectComponent, + } + }, + queryFieldFilter: 'assignee.id', // for a complex object it's important to tell the Filter which field to query and our CustomAngularComponentFilter returns the "id" property + queryFieldSorter: 'assignee.name', formatter: Formatters.complexObject, params: { - complexField: 'assignee.name', + complexFieldLabel: 'assignee.name', }, exportWithFormatter: true, editor: { @@ -115,7 +137,15 @@ export class GridAngularComponent implements OnInit { minWidth: 100, filterable: true, sortable: true, - type: FieldType.string, + filter: { + model: new CustomAngularComponentFilter(), // create a new instance to make each Filter independent from each other + collection: this.assignees, + params: { + component: FilterNgSelectComponent, + } + }, + queryFieldFilter: 'assignee.id', // for a complex object it's important to tell the Filter which field to query and our CustomAngularComponentFilter returns the "id" property + queryFieldSorter: 'assignee.name', // loading formatter, text to display while Post Render gets processed formatter: () => '...', @@ -205,6 +235,7 @@ export class GridAngularComponent implements OnInit { containerId: 'demo-container', sidePadding: 15 }, + headerRowHeight: 45, rowHeight: 45, // increase row height so that the ng-select fits in the cell editable: true, enableCellNavigation: true, @@ -238,7 +269,7 @@ export class GridAngularComponent implements OnInit { tempDataset.push({ id: i, title: 'Task ' + i, - assignee: i % 3 ? this.assignees[2] : i % 2 ? this.assignees[1] : this.assignees[0], + assignee: i % 3 ? this.assignees[3] : i % 2 ? this.assignees[2] : this.assignees[1], duration: Math.round(Math.random() * 100) + '', percentComplete: randomPercent, percentCompleteNumber: randomPercent, diff --git a/src/app/examples/grid-editor.component.html b/src/app/examples/grid-editor.component.html index dd8466ebd..4af2b6734 100644 --- a/src/app/examples/grid-editor.component.html +++ b/src/app/examples/grid-editor.component.html @@ -3,7 +3,7 @@

    {{title}}

    - +