From 217bf9d7e72ae40f1a02974e681f26494ae51807 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Mon, 5 Dec 2022 19:25:32 -0500 Subject: [PATCH] fix: fixing few small issues in Examples after adding Cypress E2E tests --- src/examples/slickgrid/example10.tsx | 13 +- src/examples/slickgrid/example16.tsx | 53 +- src/examples/slickgrid/example18.tsx | 7 +- .../slickgrid/example19-detail-view.tsx | 108 ----- src/examples/slickgrid/example19.tsx | 240 ---------- src/examples/slickgrid/example21.tsx | 3 +- src/examples/slickgrid/example23.tsx | 4 +- src/examples/slickgrid/example26.tsx | 453 ------------------ src/examples/slickgrid/example27.tsx | 2 +- src/examples/slickgrid/example28.tsx | 23 +- src/examples/slickgrid/example29.tsx | 2 +- src/examples/slickgrid/example30.tsx | 9 +- src/examples/slickgrid/example31.tsx | 7 +- src/examples/slickgrid/example33.tsx | 7 +- src/examples/slickgrid/example34.tsx | 4 +- src/examples/slickgrid/example5.tsx | 17 +- src/examples/slickgrid/example7.scss | 10 + src/examples/slickgrid/example7.tsx | 204 +++++--- src/examples/slickgrid/example9.tsx | 14 +- src/index.tsx | 5 + .../components/slickgrid-react.tsx | 35 +- .../services/translater.service.ts | 1 - src/slickgrid.scss | 4 +- 23 files changed, 278 insertions(+), 947 deletions(-) delete mode 100644 src/examples/slickgrid/example19-detail-view.tsx delete mode 100644 src/examples/slickgrid/example19.tsx delete mode 100644 src/examples/slickgrid/example26.tsx create mode 100644 src/examples/slickgrid/example7.scss diff --git a/src/examples/slickgrid/example10.tsx b/src/examples/slickgrid/example10.tsx index 2f4f49ef..aaac8d3c 100644 --- a/src/examples/slickgrid/example10.tsx +++ b/src/examples/slickgrid/example10.tsx @@ -11,7 +11,7 @@ interface State { columnDefinitions1?: Column[]; columnDefinitions2?: Column[]; selectedTitle: string; - selectedTitles: any[]; + selectedTitles: string; } export default class Example10 extends React.Component { title = 'Example 10: Multiple Grids with Row Selection'; @@ -41,7 +41,7 @@ export default class Example10 extends React.Component { dataset1: [], dataset2: [], selectedTitle: '', - selectedTitles: [], + selectedTitles: '', }; } @@ -266,7 +266,6 @@ export default class Example10 extends React.Component { // IMPORTANT, the Pagination MUST BE CREATED on initial page load before you can start toggling it // Basically you cannot toggle a Pagination that doesn't exist (must created at the time as the grid) showGrid2Pagination(showPagination: boolean) { - console.log('toggle grid2 pagination', showPagination) this.reactGrid2.paginationService!.togglePaginationVisibility(showPagination); } @@ -306,11 +305,11 @@ export default class Example10 extends React.Component {
Pagination - -
@@ -345,11 +344,11 @@ export default class Example10 extends React.Component { data-test="toggle-pagination-grid2" /> {this.isGrid2WithPagination && - - diff --git a/src/examples/slickgrid/example16.tsx b/src/examples/slickgrid/example16.tsx index 66f1de79..37f5c3ae 100644 --- a/src/examples/slickgrid/example16.tsx +++ b/src/examples/slickgrid/example16.tsx @@ -1,4 +1,4 @@ -import { ReactGridInstance, Column, ExtensionName, Filters, Formatters, GridOption, ReactSlickgridComponent } from '../../slickgrid-react'; +import { ReactGridInstance, Column, ExtensionName, Filters, Formatters, GridOption, ReactSlickgridComponent, OnEventArgs } from '../../slickgrid-react'; import React from 'react'; import BaseSlickGridState from './state-slick-grid-base'; @@ -49,11 +49,7 @@ export default class Example16 extends React.Component { document.title = this.title; // populate the dataset once the grid is ready - this.setState((state: State, props: Props) => { - return { - dataset: this.getData(), - }; - }); + this.setState((state: State) => ({ dataset: this.getData() })); } /* Define grid Options and Columns */ @@ -251,6 +247,47 @@ export default class Example16 extends React.Component { this.reactGrid.sortService.disableSortFunctionality(true); } + addEditDeleteColumns() { + if (this.state.columnDefinitions[0].id !== 'change-symbol') { + const newCols = [ + { + id: 'change-symbol', + field: 'id', + excludeFromColumnPicker: true, + excludeFromGridMenu: true, + excludeFromHeaderMenu: true, + formatter: Formatters.editIcon, + minWidth: 30, + maxWidth: 30, + onCellClick: (clickEvent: Event, args: OnEventArgs) => { + alert(`Technically we should Edit "Task ${args.dataContext.id}"`); + } + }, { + id: 'delete-symbol', + field: 'id', + excludeFromColumnPicker: true, + excludeFromGridMenu: true, + excludeFromHeaderMenu: true, + formatter: Formatters.deleteIcon, + minWidth: 30, + maxWidth: 30, + onCellClick: (e: Event, args: OnEventArgs) => { + if (confirm('Are you sure?')) { + this.reactGrid.gridService.deleteItemById(args.dataContext.id); + } + } + } + ]; + + // NOTE if you use an Extensions (Checkbox Selector, Row Detail, ...) that modifies the column definitions in any way + // you MUST use "getAllColumnDefinitions()" from the GridService, using this will be ALL columns including the 1st column that is created internally + // for example if you use the Checkbox Selector (row selection), you MUST use the code below + const allColumns = this.reactGrid.gridService.getAllColumnDefinitions(); + allColumns.unshift(newCols[0], newCols[1]); + this.setState((state: State) => ({ ...state, columnDefinitions: [...allColumns] })); // (or use slice) reassign to column definitions for Aurelia to do dirty checking + } + } + // or Toggle Filtering/Sorting functionalities // --------------------------------------------- @@ -302,6 +339,10 @@ export default class Example16 extends React.Component { Toggle Sorting +
diff --git a/src/examples/slickgrid/example18.tsx b/src/examples/slickgrid/example18.tsx index bc1f8b58..13b49007 100644 --- a/src/examples/slickgrid/example18.tsx +++ b/src/examples/slickgrid/example18.tsx @@ -194,7 +194,7 @@ export default class Example18 extends React.Component { } }, { - id: 'effortDriven', name: 'Effort Driven', field: 'effortDriven', + id: 'effortDriven', name: 'Effort-Driven', field: 'effortDriven', width: 80, minWidth: 20, maxWidth: 100, cssClass: 'cell-effort-driven', sortable: true, @@ -224,6 +224,7 @@ export default class Example18 extends React.Component { createPreHeaderPanel: true, showPreHeaderPanel: true, preHeaderPanelHeight: 40, + showCustomFooter: true, enableFiltering: true, // you could debounce/throttle the input text filter if you have lots of data // filterTypingDebounce: 250, @@ -535,12 +536,12 @@ export default class Example18 extends React.Component { { this.state.selectedGroupingFields.map((groupField, index) => -
+
diff --git a/src/examples/slickgrid/example19-detail-view.tsx b/src/examples/slickgrid/example19-detail-view.tsx deleted file mode 100644 index 5b540ec3..00000000 --- a/src/examples/slickgrid/example19-detail-view.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import Example19 from './example19'; -import { SlickDataView, SlickGrid, ViewModelBindableData } from '../../slickgrid-react'; - -export class DetailViewCustomElement { - model!: { - duration: Date; - percentComplete: number; - reporter: string; - start: Date; - finish: Date; - effortDriven: boolean; - assignee: string; - title: string; - }; - - // you also have access to the following objects (it must match the exact property names shown below) - addon: any; // row detail addon instance - grid!: SlickGrid; - dataView!: SlickDataView; - - // you can also optionally use the Parent Component reference - // NOTE that you MUST provide it through the "parent" property in your "rowDetail" grid options - parent?: Example19; - - bind(_bindingContext: any, overrideContext: any) { - if (overrideContext && overrideContext.parentOverrideContext && overrideContext.parentOverrideContext.bindingContext && overrideContext.parentOverrideContext.bindingContext.model) { - this.bindReferences(overrideContext.parentOverrideContext.bindingContext); - } - } - - bindReferences(data: ViewModelBindableData) { - if (data) { - this.model = data.model; - this.addon = data.addon; - this.grid = data.grid; - this.dataView = data.dataView; - this.parent = data.parent; - } - } - - alertAssignee(name: string) { - if (typeof name === 'string') { - alert(`Assignee on this task is: ${name.toUpperCase()}`); - } else { - alert('No one is assigned to this task.'); - } - } - - deleteRow(model: any) { - if (confirm(`Are you sure that you want to delete ${model.title}?`)) { - // you first need to collapse all rows (via the 3rd party addon instance) - this.addon.collapseAll(); - - // then you can delete the item from the dataView - this.dataView.deleteItem(model.rowId); - - this.parent!.showFlashMessage(`Deleted row with ${model.title}`, 'danger'); - } - } - - callParentMethod(model: any) { - this.parent!.showFlashMessage(`We just called Parent Method from the Row Detail Child Component on ${model.title}`); - } - - render() { - return ( -
-

{this.model.title}

-
-
-
{this.model.reporter}
-
{this.model.duration}
-
{this.model.percentComplete}
-
- -
-
{this.model.start}
-
{this.model.finish}
-
-
-
- -
- -
-

- Find out who is the Assignee - - - -

-
- -
- - -
-
- ); - } -} diff --git a/src/examples/slickgrid/example19.tsx b/src/examples/slickgrid/example19.tsx deleted file mode 100644 index 9a19538c..00000000 --- a/src/examples/slickgrid/example19.tsx +++ /dev/null @@ -1,240 +0,0 @@ -import { - ReactGridInstance, - Column, - ExtensionList, - FieldType, - Filters, - Formatters, - GridOption, - ReactSlickgridComponent, -} from '../../slickgrid-react'; -import React from 'react'; - -interface Props { } - -export default class Example19 extends React.Component { - detailViewRowCount = 9; - title = 'Example 19: Row Detail View'; - subTitle = ` - Add functionality to show extra information with a Row Detail View, (Wiki docs) -
    -
  • Click on the row "+" icon or anywhere on the row to open it (the latter can be changed via property "useRowClick: false")
  • -
  • Pass a View/Model as a Template to the Row Detail
  • -
  • You can use "expandableOverride()" callback to override logic to display expand icon on every row (for example only show it every 2nd row)
  • -
- `; - - reactGrid!: ReactGridInstance; - gridOptions!: GridOption; - columnDefinitions: Column[] = []; - dataset: any[] = []; - extensions!: ExtensionList; - flashAlertType = 'info'; - message = ''; - - constructor(public readonly props: Props) { - super(props); - // define the grid options & columns and then create the grid itself - this.defineGrid(); - this.componentDidMount(); - } - - get rowDetailInstance(): any { - // you can get the SlickGrid RowDetail plugin (addon) instance via 2 ways - - // option 1 - return this.extensions.rowDetailView.instance || {}; - - // OR options 2 - // return this.reactGrid && this.reactGrid.extensionService.getExtensionInstanceByName(ExtensionName.rowDetailView) || {}; - } - - componentDidMount() { - document.title = this.title; - // populate the dataset once the grid is ready - this.getData(); - } - - reactGridReady(reactGrid: ReactGridInstance) { - this.reactGrid = reactGrid; - } - - /* Define grid Options and Columns */ - defineGrid() { - this.columnDefinitions = [ - { id: 'title', name: 'Title', field: 'title', sortable: true, type: FieldType.string, width: 70, filterable: true }, - { id: 'duration', name: 'Duration (days)', field: 'duration', formatter: Formatters.decimal, params: { minDecimal: 1, maxDecimal: 2 }, sortable: true, type: FieldType.number, minWidth: 90, filterable: true }, - { id: 'percent2', name: '% Complete', field: 'percentComplete2', formatter: Formatters.progressBar, type: FieldType.number, sortable: true, minWidth: 100, filterable: true, filter: { model: Filters.slider, operator: '>' } }, - { id: 'start', name: 'Start', field: 'start', formatter: Formatters.dateIso, sortable: true, type: FieldType.date, minWidth: 90, exportWithFormatter: true, filterable: true, filter: { model: Filters.compoundDate } }, - { id: 'finish', name: 'Finish', field: 'finish', formatter: Formatters.dateIso, sortable: true, type: FieldType.date, minWidth: 90, exportWithFormatter: true, filterable: true, filter: { model: Filters.compoundDate } }, - { - id: 'effort-driven', name: 'Effort Driven', field: 'effortDriven', - minWidth: 100, - formatter: Formatters.checkmark, type: FieldType.boolean, - filterable: true, sortable: true, - filter: { - collection: [{ value: '', label: '' }, { value: true, label: 'True' }, { value: false, label: 'False' }], - model: Filters.singleSelect - } - } - ]; - - this.gridOptions = { - autoResize: { - container: '#demo-container', - rightPadding: 10 - }, - enableFiltering: true, - enableRowDetailView: true, - rowSelectionOptions: { - selectActiveRow: true - }, - datasetIdPropertyName: 'rowId', // optionally use a different "id" - rowDetailView: { - // optionally change the column index position of the icon (defaults to 0) - // columnIndexPosition: 1, - - // We can load the "process" asynchronously in 3 different ways (react-http-client, react-fetch-client OR even Promise) - process: (item) => this.simulateServerAsyncCall(item), - // process: (item) => this.http.get(`api/item/${item.id}`), - - // load only once and reuse the same item detail without calling process method - loadOnce: true, - - // limit expanded row to only 1 at a time - singleRowExpand: false, - - // false by default, clicking anywhere on the row will open the detail view - // when set to false, only the "+" icon would open the row detail - // if you use editor or cell navigation you would want this flag set to false (default) - useRowClick: true, - - // how many grid rows do we want to use for the row detail panel (this is only set once and will be used for all row detail) - // also note that the detail view adds an extra 1 row for padding purposes - // so if you choose 4 panelRows, the display will in fact use 5 rows - panelRows: this.detailViewRowCount, - - // you can override the logic for showing (or not) the expand icon - // for example, display the expand icon only on every 2nd row - // expandableOverride: (row: number, dataContext: any, grid: SlickGrid) => (dataContext.id % 2 === 1), - - // // Preload View Template - // preloadView: PLATFORM.moduleName('examples/example19-preload.html'), - - // // ViewModel Template to load when row detail data is ready - // viewModel: PLATFORM.moduleName('examples/example19-detail-view'), - - // Optionally pass your Parent Component reference to your Child Component (row detail component) - parent: this - } - }; - } - - getData() { - // mock a dataset - this.dataset = []; - for (let i = 0; i < 1000; i++) { - const randomYear = 2000 + Math.floor(Math.random() * 10); - const randomMonth = Math.floor(Math.random() * 11); - const randomDay = Math.floor((Math.random() * 29)); - const randomPercent = Math.round(Math.random() * 100); - - this.dataset[i] = { - rowId: i, - title: 'Task ' + i, - duration: (i % 33 === 0) ? null : Math.random() * 100 + '', - percentComplete: randomPercent, - percentComplete2: randomPercent, - percentCompleteNumber: randomPercent, - start: new Date(randomYear, randomMonth, randomDay), - finish: new Date(randomYear, (randomMonth + 1), randomDay), - effortDriven: (i % 5 === 0) - }; - } - } - - changeDetailViewRowCount() { - const options = this.rowDetailInstance.getOptions(); - if (options && options.panelRows) { - options.panelRows = this.detailViewRowCount; // change number of rows dynamically - this.rowDetailInstance.setOptions(options); - } - } - - closeAllRowDetail() { - this.rowDetailInstance.collapseAll(); - } - - showFlashMessage(message: string, alertType = 'info') { - this.message = message; - this.flashAlertType = alertType; - } - - /** Just for demo purposes, we will simulate an async server call and return more details on the selected row item */ - simulateServerAsyncCall(item: any) { - // random set of names to use for more item detail - const randomNames = ['John Doe', 'Jane Doe', 'Chuck Norris', 'Bumblebee', 'Jackie Chan', 'Elvis Presley', 'Bob Marley', 'Mohammed Ali', 'Bruce Lee', 'Rocky Balboa']; - - // fill the template on async delay - return new Promise((resolve) => { - setTimeout(() => { - const itemDetail = item; - - // let's add some extra properties to our item for a better async simulation - itemDetail.assignee = randomNames[this.randomNumber(0, 10)]; - itemDetail.reporter = randomNames[this.randomNumber(0, 10)]; - - // resolve the data after delay specified - resolve(itemDetail); - }, 1000); - }); - } - - private randomNumber(min: number, max: number) { - return Math.floor(Math.random() * (max - min + 1) + min); - } - - render() { - return ( -
-

- {this.title} - - - code - - -

-
- -
- -    - - - - -
- {this.message &&
{this.message}
} - -
- - this.reactGridReady($event.detail)} - /> -
- ); - } -} diff --git a/src/examples/slickgrid/example21.tsx b/src/examples/slickgrid/example21.tsx index b9556dd4..4cd1d6e2 100644 --- a/src/examples/slickgrid/example21.tsx +++ b/src/examples/slickgrid/example21.tsx @@ -233,7 +233,7 @@ export default class Example21 extends React.Component { { this.state.columnDefinitions.map((column) => - + ) } @@ -255,6 +255,7 @@ export default class Example21 extends React.Component { className="form-control" placeholder="search value" data-test="search-value-input" + value={this.state.searchValue} onInput={($event) => this.searchValueChanged($event)} />
diff --git a/src/examples/slickgrid/example26.tsx b/src/examples/slickgrid/example26.tsx deleted file mode 100644 index 371a53ff..00000000 --- a/src/examples/slickgrid/example26.tsx +++ /dev/null @@ -1,453 +0,0 @@ -import { i18n } from 'i18next'; -import { - ReactGridInstance, - ReactUtilService, - Column, - EditCommand, - Editors, - FieldType, - Filters, - Formatters, - GridOption, - OnEventArgs, - OperatorType, - ReactSlickgridComponent -} from '../../slickgrid-react'; -import { CustomInputEditor } from './custom-inputEditor'; -import { CustomInputFilter } from './custom-inputFilter'; -import React from 'react'; -import { withTranslation } from 'react-i18next'; - -// using external non-typed js libraries -declare const Slick: any; - -const NB_ITEMS = 100; - -interface Props { } - -class Example26 extends React.Component { - title = 'Example 26: Use of React Custom Elements'; - subTitle = ` -

Filters, Editors, AsyncPostRender with React Custom Elements

- Grid with usage of React Custom Elements as Editor & AsyncPostRender (similar to Formatter). -
    -
  • Support of React Custom Element as Custom Editor (click on any "Assignee" name cell)
  • -
      -
    • That column uses a simple select drodown wrapped in an React Custom Element -
    • Increased Grid Options "rowHeight" & "headerRowHeight" to 45 so that the Custom Element fits in the cell.
    • -
    -
  • Support of React Custom Element as Custom Filter ("Assignee" columns), which also uses Custom Element -
  • The 2nd "Assignee" column (showing in bold text) uses "asyncPostRender" with an React Custom Element
  • -
      -
    • Why can't we use React Custom Element 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 (React 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 -
    • -
    -
- `; - private _commandQueue: EditCommand[] = []; - reactGrid!: ReactGridInstance; - gridOptions!: GridOption; - columnDefinitions: Column[] = []; - dataset: any[] = []; - updatedObject: any; - isAutoEdit = true; - alertWarning: any; - selectedLanguage: string; - assignees = [ - { id: '', name: '' }, - { id: '1', name: 'John' }, - { id: '2', name: 'Pierre' }, - { id: '3', name: 'Paul' }, - ]; - selectedItem: any; - selectedId = ''; - private i18n: i18n; - - constructor(public readonly props: Props, private reactUtilService: ReactUtilService) { - super(props); - // define the grid options & columns and then create the grid itself - this.defineGrid(); - this.selectedLanguage = this.i18n.language; - } - - componentDidMount() { - document.title = this.title; - // populate the dataset once the grid is ready - this.dataset = this.mockData(NB_ITEMS); - } - - reactGridReady(reactGrid: ReactGridInstance) { - this.reactGrid = reactGrid; - } - - /* Define grid Options and Columns */ - defineGrid() { - this.columnDefinitions = [ - { - id: 'title', - name: 'Title', - field: 'title', - filterable: true, - sortable: true, - type: FieldType.string, - editor: { - model: Editors.longText, - minLength: 5, - maxLength: 255, - }, - minWidth: 100, - onCellChange: (_e: Event, args: OnEventArgs) => { - console.log(args); - this.alertWarning = `Updated Title: ${args.dataContext.title}`; - } - }, { - id: 'assignee', - name: 'Assignee', - field: 'assignee', - minWidth: 100, - filterable: true, - sortable: true, - filter: { - model: new CustomAureliaViewModelFilter(), - collection: this.assignees, - params: { - aureliaUtilService: this.aureliaUtilService, // pass the aureliaUtilService here OR in the grid option params - templateUrl: PLATFORM.moduleName('examples/slickgrid/filter-select') // FilterSelect, - } - }, - queryFieldFilter: 'assignee.id', // for a complex object it's important to tell the Filter which field to query and our CustomAureliaComponentFilter returns the "id" property - queryFieldSorter: 'assignee.name', - formatter: Formatters.complexObject, - params: { - complexFieldLabel: 'assignee.name', - }, - exportWithFormatter: true, - editor: { - model: CustomAureliaViewModelEditor, - collection: this.assignees, - params: { - aureliaUtilService: this.aureliaUtilService, // pass the aureliaUtilService here OR in the grid option params - templateUrl: PLATFORM.moduleName('examples/slickgrid/editor-select') // EditorSelect, - } - }, - onCellChange: (_e: Event, args: OnEventArgs) => { - console.log(args); - this.alertWarning = `Updated Title: ${args.dataContext.title}`; - } - }, { - id: 'assignee2', - name: 'Assignee with Aurelia Component', - field: 'assignee', - minWidth: 125, - filterable: true, - sortable: true, - filter: { - model: new CustomAureliaViewModelFilter(), - collection: this.assignees, - params: { - aureliaUtilService: this.aureliaUtilService, // pass the aureliaUtilService here OR in the grid option params - templateUrl: PLATFORM.moduleName('examples/slickgrid/filter-select') // FilterSelect, - } - }, - queryFieldFilter: 'assignee.id', // for a complex object it's important to tell the Filter which field to query and our CustomAureliaComponentFilter returns the "id" property - queryFieldSorter: 'assignee.name', - - // loading formatter, text to display while Post Render gets processed - formatter: () => '...', - - // to load an Aurelia Custom Element, you cannot use a Formatter since Aurelia needs at least 1 cycle to render everything - // you can use a PostRenderer but you will visually see the data appearing, - // which is why it's still better to use regular Formatter (with jQuery if need be) instead of Aurelia Custom Element - asyncPostRender: this.renderAureliaComponent.bind(this), - params: { - templateUrl: PLATFORM.moduleName('examples/slickgrid/custom-title-formatter'), // CustomTitleFormatterCustomElement, - complexFieldLabel: 'assignee.name' // for the exportCustomFormatter - }, - exportCustomFormatter: Formatters.complexObject, - }, { - id: 'duration', - name: 'Duration (days)', - field: 'duration', - filterable: true, - minWidth: 100, - sortable: true, - type: FieldType.number, - filter: { model: Filters.slider, params: { hideSliderNumber: false } }, - editor: { - model: Editors.slider, - minValue: 0, - maxValue: 100, - // params: { hideSliderNumber: true }, - }, - /* - editor: { - // default is 0 decimals, if no decimals is passed it will accept 0 or more decimals - // however if you pass the "decimalPlaces", it will validate with that maximum - model: Editors.float, - minValue: 0, - maxValue: 365, - // the default validation error message is in English but you can override it by using "errorMessage" - // errorMessage: this.i18n.tr('INVALID_FLOAT', { maxDecimal: 2 }), - params: { decimalPlaces: 2 }, - }, - */ - }, { - id: 'complete', - name: '% Complete', - field: 'percentComplete', - filterable: true, - formatter: Formatters.multiple, - type: FieldType.number, - editor: { - // We can also add HTML text to be rendered (any bad script will be sanitized) but we have to opt-in, else it will be sanitized - enableRenderHtml: true, - collection: Array.from(Array(101).keys()).map(k => ({ value: k, label: k, symbol: '' })), - customStructure: { - value: 'value', - label: 'label', - labelSuffix: 'symbol' - }, - collectionSortBy: { - property: 'label', - sortDesc: true - }, - collectionFilterBy: { - property: 'value', - value: 0, - operator: OperatorType.notEqual - }, - model: Editors.singleSelect, - }, - minWidth: 100, - params: { - formatters: [Formatters.collectionEditor, Formatters.percentCompleteBar], - } - }, { - id: 'start', - name: 'Start', - field: 'start', - filterable: true, - filter: { model: Filters.compoundDate }, - formatter: Formatters.dateIso, - sortable: true, - minWidth: 100, - type: FieldType.date, - editor: { - model: Editors.date - }, - }, { - id: 'finish', - name: 'Finish', - field: 'finish', - filterable: true, - filter: { model: Filters.compoundDate }, - formatter: Formatters.dateIso, - sortable: true, - minWidth: 100, - type: FieldType.date, - editor: { - model: Editors.date - }, - } - ]; - - this.gridOptions = { - asyncEditorLoading: false, - autoEdit: this.isAutoEdit, - autoCommitEdit: false, - autoResize: { - container: '#demo-container', - rightPadding: 10 - }, - rowHeight: 45, // increase row height so that the custom elements fits in the cell - editable: true, - enableCellNavigation: true, - enableColumnPicker: true, - enableExcelCopyBuffer: true, - enableFiltering: true, - enableAsyncPostRender: true, // for the React PostRenderer, don't forget to enable it - asyncPostRenderDelay: 0, // also make sure to remove any delay to render it - editCommandHandler: (_item, _column, editCommand) => { - this._commandQueue.push(editCommand); - editCommand.execute(); - }, - i18n: this.i18n, - params: { - reactUtilService: this.reactUtilService // provide the service to all at once (Editor, Filter, AsyncPostRender) - } - }; - } - - mockData(itemCount: number, startingIndex = 0) { - // mock a dataset - const tempDataset: any[] = []; - for (let i = startingIndex; i < (startingIndex + itemCount); i++) { - const randomYear = 2000 + Math.floor(Math.random() * 10); - const randomMonth = Math.floor(Math.random() * 11); - const randomDay = Math.floor((Math.random() * 29)); - const randomPercent = Math.round(Math.random() * 100); - - tempDataset.push({ - id: i, - title: 'Task ' + i, - assignee: i % 3 ? this.assignees[2] : i % 2 ? this.assignees[1] : this.assignees[0], - duration: Math.round(Math.random() * 100) + '', - percentComplete: randomPercent, - percentCompleteNumber: randomPercent, - start: new Date(randomYear, randomMonth, randomDay), - finish: new Date(randomYear, (randomMonth + 1), randomDay), - effortDriven: (i % 5 === 0), - }); - } - return tempDataset; - } - - onCellChanged(_e: Event, args: any) { - console.log('onCellChange', args); - this.updatedObject = { ...args.item }; - } - - onCellClicked(_e: Event, args: any) { - const metadata = this.reactGrid.gridService.getColumnFromEventArguments(args); - console.log(metadata); - - if (metadata.columnDef.id === 'edit') { - this.alertWarning = `open a modal window to edit: ${metadata.dataContext.title}`; - - // highlight the row, to customize the color, you can change the SASS variable $row-highlight-background-color - this.reactGrid.gridService.highlightRow(args.row, 1500); - - // you could also select the row, when using "enableCellNavigation: true", it automatically selects the row - // this.reactGrid.gridService.setSelectedRow(args.row); - } else if (metadata.columnDef.id === 'delete') { - if (confirm('Are you sure?')) { - this.reactGrid.gridService.deleteItemById(metadata.dataContext.id); - this.alertWarning = `Deleted: ${metadata.dataContext.title}`; - } - } - } - - onCellValidation(_e: Event, args: any) { - alert(args.validationResults.msg); - } - - changeAutoCommit() { - this.gridOptions.autoCommitEdit = !this.gridOptions.autoCommitEdit; - this.reactGrid.slickGrid.setOptions({ - autoCommitEdit: this.gridOptions.autoCommitEdit - }); - return true; - } - - renderReactComponent(cellNode: JQuery, _row: number, dataContext: any, colDef: Column) { - // if (colDef.params.templateUrl && cellNode.length) { - // this.reactUtilService.createReactViewModelAddToSlot(colDef.params.templateUrl, { model: dataContext }, cellNode[0], true); - // } - } - - setAutoEdit(isAutoEdit: boolean) { - this.isAutoEdit = isAutoEdit; - this.reactGrid.slickGrid.setOptions({ - autoEdit: isAutoEdit - }); - return true; - } - - switchLanguage() { - this.selectedLanguage = (this.selectedLanguage === 'en') ? 'fr' : 'en'; - this.i18n.changeLanguage(this.selectedLanguage); - } - - undo() { - const command = this._commandQueue.pop(); - if (command && Slick.GlobalEditorLock.cancelCurrentEdit()) { - command.undo(); - this.reactGrid.slickGrid.gotoCell(command.row, command.cell, false); - } - } - - render() { - return ( -
-

- {this.title} - - - code - - -

-
- -
- -
- -
-
- - -
-
-
-
- - -
-
-
-
-
- - -
-
-
- -
- {this.updatedObject &&
- Updated Item: {this.updatedObject.toString} -
} - {this.alertWarning &&
- {this.alertWarning} -
} -
- -
- this.reactGridReady($event.detail)} - onCellChange={$event => this.onCellChanged($event.detail.eventData, $event.detail.args)} - onClick={$event => this.onCellClicked($event.detail.eventData, $event.detail.args)} - /> -
-
- ); - } -} - -export default withTranslation()(Example26); \ No newline at end of file diff --git a/src/examples/slickgrid/example27.tsx b/src/examples/slickgrid/example27.tsx index 9b140d24..ab7986d9 100644 --- a/src/examples/slickgrid/example27.tsx +++ b/src/examples/slickgrid/example27.tsx @@ -388,7 +388,7 @@ export default class Example27 extends React.Component { 25k rows diff --git a/src/examples/slickgrid/example28.tsx b/src/examples/slickgrid/example28.tsx index a8d477de..612b9f4e 100644 --- a/src/examples/slickgrid/example28.tsx +++ b/src/examples/slickgrid/example28.tsx @@ -126,8 +126,6 @@ export default class Example28 extends React.Component { // } }, // change header/cell row height for salesforce theme - headerRowHeight: 35, - rowHeight: 33, showCustomFooter: true, // we can also preset collapsed items via Grid Presets (parentId: 4 => is the "pdf" folder) @@ -165,6 +163,7 @@ export default class Example28 extends React.Component { clearSearch() { this.setState((state: State) => ({ ...state, searchString: '' })); + this.searchStringChanged(''); } searchStringChanged(val: string) { @@ -269,7 +268,7 @@ export default class Example28 extends React.Component { { id: 18, file: 'something.txt', dateModified: '2015-03-03T03:50:00.123Z', size: 90 }, { id: 21, file: 'documents', files: [ - { id: 2, file: 'txt', files: [{ id: 3, file: 'todo.txt', dateModified: '2015-05-12T14:50:00.123Z', size: 0.7, }] }, + { id: 2, file: 'txt', files: [{ id: 3, file: 'todo.txt', description: 'things to do someday maybe', dateModified: '2015-05-12T14:50:00.123Z', size: 0.7, }] }, { id: 4, file: 'pdf', files: [ { id: 22, file: 'map2.pdf', dateModified: '2015-07-21T08:22:00.123Z', size: 2.9, }, @@ -279,7 +278,7 @@ export default class Example28 extends React.Component { ] }, { id: 9, file: 'misc', files: [{ id: 10, file: 'todo.txt', dateModified: '2015-02-26T16:50:00.123Z', size: 0.4, }] }, - { id: 7, file: 'xls', files: [{ id: 8, file: 'compilation.xls', dateModified: '2014-10-02T14:50:00.123Z', size: 2.3, }] }, + { id: 7, file: 'xls', files: [{ id: 8, file: 'compilation.xls', description: 'movie compilation', dateModified: '2014-10-02T14:50:00.123Z', size: 2.3, }] }, ] }, { @@ -288,13 +287,20 @@ export default class Example28 extends React.Component { { id: 16, file: 'rock', files: [{ id: 17, file: 'soft.mp3', dateModified: '2015-05-13T13:50:00Z', size: 98, }] }, { id: 14, file: 'pop', files: [ - { id: 15, file: 'theme.mp3', dateModified: '2015-03-01T17:05:00Z', size: 47, }, - { id: 25, file: 'song.mp3', dateModified: '2016-10-04T06:33:44Z', size: 6.3, } + { id: 15, file: 'theme.mp3', description: 'Movie Theme Song', dateModified: '2015-03-01T17:05:00Z', size: 47, }, + { id: 25, file: 'song.mp3', description: 'it is a song...', dateModified: '2016-10-04T06:33:44Z', size: 6.3, } ] }, ] }] }, + { + id: 26, file: 'recipes', description: 'Cake Recipes', dateModified: '2012-03-05T12:44:00.123Z', files: [ + { id: 29, file: 'cheesecake', description: 'strawberry cheesecake', dateModified: '2012-04-04T13:52:00.123Z', size: 0.2 }, + { id: 30, file: 'chocolate-cake', description: 'tasty sweet chocolate cake', dateModified: '2012-05-05T09:22:00.123Z', size: 0.2 }, + { id: 31, file: 'coffee-cake', description: 'chocolate coffee cake', dateModified: '2012-01-01T08:08:48.123Z', size: 0.2 }, + ] + }, ]; } @@ -337,9 +343,8 @@ export default class Example28 extends React.Component {
- this.searchStringChanged(($event.target as HTMLInputElement).value)} /> -
diff --git a/src/examples/slickgrid/example29.tsx b/src/examples/slickgrid/example29.tsx index df2e9fde..4c721375 100644 --- a/src/examples/slickgrid/example29.tsx +++ b/src/examples/slickgrid/example29.tsx @@ -12,7 +12,7 @@ const Footer = () => { return (
Footer Slot
- + {state.clickedTimes > 0 &&
You've clicked me {state.clickedTimes} time(s)
}
) diff --git a/src/examples/slickgrid/example30.tsx b/src/examples/slickgrid/example30.tsx index d2fb1a51..cca70822 100644 --- a/src/examples/slickgrid/example30.tsx +++ b/src/examples/slickgrid/example30.tsx @@ -673,15 +673,16 @@ export default class Example30 extends React.Component { this.undoAllEdits(); // then change a single grid options to make the grid non-editable (readonly) + const isGridEditable = !this.state.isGridEditable; this.setState((state: State) => ({ ...state, - isGridEditable: !state.isGridEditable, - isCompositeDisabled: !state.isGridEditable, - isMassSelectionDisabled: !state.isGridEditable, + isGridEditable, + isCompositeDisabled: !isGridEditable, + isMassSelectionDisabled: !isGridEditable, })); // dynamically change SlickGrid editable grid option - this.reactGrid.slickGrid.setOptions({ editable: this.state.isGridEditable }); + this.reactGrid.slickGrid.setOptions({ editable: isGridEditable }); } removeUnsavedStylingFromCell(_item: any, column: Column, row: number) { diff --git a/src/examples/slickgrid/example31.tsx b/src/examples/slickgrid/example31.tsx index 22686c81..d1e5e341 100644 --- a/src/examples/slickgrid/example31.tsx +++ b/src/examples/slickgrid/example31.tsx @@ -31,6 +31,7 @@ interface State extends BaseSlickGridState { isCountEnabled: boolean; isSelectEnabled: boolean; isExpandEnabled: boolean; + isOtherGenderAdded: boolean; odataVersion: number; odataQuery: string; processing: boolean; @@ -47,7 +48,6 @@ export default class Example31 extends React.Component { `; reactGrid!: ReactGridInstance; - isOtherGenderAdded = false; constructor(public readonly props: Props) { super(props); @@ -57,6 +57,7 @@ export default class Example31 extends React.Component { dataset: [], paginationOptions: undefined, errorStatus: '', + isOtherGenderAdded: false, isCountEnabled: true, isSelectEnabled: false, isExpandEnabled: false, @@ -201,7 +202,7 @@ export default class Example31 extends React.Component { } // don't add it more than once - this.isOtherGenderAdded = true; + this.setState((state: State) => ({ ...state, isOtherGenderAdded: true })); } displaySpinner(isProcessing: boolean) { @@ -515,7 +516,7 @@ export default class Example31 extends React.Component { Set Sorting Dynamically
diff --git a/src/examples/slickgrid/example33.tsx b/src/examples/slickgrid/example33.tsx index f88cee7a..f746b5b6 100644 --- a/src/examples/slickgrid/example33.tsx +++ b/src/examples/slickgrid/example33.tsx @@ -4,7 +4,6 @@ import { Editors, FieldType, Filters, - formatNumber, Formatter, Formatters, GridOption, @@ -19,7 +18,7 @@ import React from 'react'; import { ReactGridInstance, ReactSlickgridComponent } from '../../slickgrid-react'; import BaseSlickGridState from './state-slick-grid-base'; -const NB_ITEMS = 5000; +const NB_ITEMS = 500; interface Props { } interface State extends BaseSlickGridState { @@ -387,7 +386,7 @@ export default class Example32 extends React.Component { handleServerDelayInputChange(e: React.FormEvent) { this.setState((state: State) => ({ ...state, - serverApiDelay: +((e.target as HTMLInputElement)?.value ?? 0), + serverApiDelay: parseInt((e.target as HTMLInputElement)?.value) ?? '', })); } @@ -520,7 +519,7 @@ export default class Example32 extends React.Component {
this.handleServerDelayInputChange($event)} />
diff --git a/src/examples/slickgrid/example34.tsx b/src/examples/slickgrid/example34.tsx index 5a10cadb..45082e51 100644 --- a/src/examples/slickgrid/example34.tsx +++ b/src/examples/slickgrid/example34.tsx @@ -390,8 +390,8 @@ export default class Example34 extends React.Component {
- - Changes Rate(ms) + this.handleRefreshRateChange($event.target as HTMLInputElement)} /> this.handleRefreshRateChange($event.target as HTMLInputElement)} /> diff --git a/src/examples/slickgrid/example5.tsx b/src/examples/slickgrid/example5.tsx index 9493a6b4..95fef06b 100644 --- a/src/examples/slickgrid/example5.tsx +++ b/src/examples/slickgrid/example5.tsx @@ -76,11 +76,11 @@ export default class Example5 extends React.Component { isSelectEnabled: false, isExpandEnabled: false, metrics: {} as Metrics, - status: {class:'', text:''}, + status: { class: '', text: '' }, odataVersion: 2, odataQuery:'', - processing:false, - isPageErrorTest:false + processing: false, + isPageErrorTest: false }; } @@ -211,9 +211,9 @@ export default class Example5 extends React.Component { // once pagination totalItems is filled, we can update the dataset this.setState((state: State) => ({ - ...state, - paginationOptions: { ...state.gridOptions!.pagination, totalItems: totalItemCount } as Pagination, - dataset: state.odataVersion === 4 ? data.value : data.d.results, + ...state, + paginationOptions: { ...state.gridOptions!.pagination, totalItems: totalItemCount } as Pagination, + dataset: state.odataVersion === 4 ? data.value : data.d.results, odataQuery: data['query'], metrics: { ...state.metrics, totalItemCount } })); @@ -263,12 +263,12 @@ export default class Example5 extends React.Component { if (param.includes('$filter=')) { const filterBy = param.substring('$filter='.length).replace('%20', ' '); if (filterBy.includes('contains')) { - const filterMatch = filterBy.match(/substringof\('(.*?)',\s([a-zA-Z\/]+)/); + const filterMatch = filterBy.match(/contains\(([a-zA-Z\/]+),\s?'(.*?)'/); const fieldName = filterMatch![1].trim(); (columnFilters as any)[fieldName] = { type: 'substring', term: filterMatch![2].trim() }; } if (filterBy.includes('substringof')) { - const filterMatch = filterBy.match(/substringof\('(.*?)',([a-zA-Z ]*)/); + const filterMatch = filterBy.match(/substringof\('(.*?)',\s([a-zA-Z\/]+)/); const fieldName = filterMatch![2].trim(); (columnFilters as any)[fieldName] = { type: 'substring', term: filterMatch![1].trim() }; } @@ -396,6 +396,7 @@ export default class Example5 extends React.Component { } } + // console.log('Backend Result', backendResult); resolve(backendResult); }, 150); }); diff --git a/src/examples/slickgrid/example7.scss b/src/examples/slickgrid/example7.scss new file mode 100644 index 00000000..f28874ce --- /dev/null +++ b/src/examples/slickgrid/example7.scss @@ -0,0 +1,10 @@ +/* 1st grid */ +#grid7-1 { + --slick-header-button-float: right; +} + +/* 2nd grid */ +#grid7-2 { + --slick-header-button-margin: 4px 0 50px 0; + --slick-header-button-float: left; +} diff --git a/src/examples/slickgrid/example7.tsx b/src/examples/slickgrid/example7.tsx index 20538143..5845c51d 100644 --- a/src/examples/slickgrid/example7.tsx +++ b/src/examples/slickgrid/example7.tsx @@ -1,25 +1,24 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import React from 'react'; -import { ReactGridInstance, Formatter, SlickGrid, ReactSlickgridComponent } from '../../slickgrid-react'; -import BaseSlickGridState from './state-slick-grid-base'; +import { Column, GridOption, ReactGridInstance, ReactSlickgridComponent } from '../../slickgrid-react'; +import './example7.scss'; -const columnsWithHighlightingById: any = {}; - -// create a custom Formatter to highlight negative values in red -const highlightingFormatter: Formatter = (_row, _cell, value, columnDef) => { - if (columnsWithHighlightingById[columnDef.id] && value < 0) { - return `
${value}
`; - } else { - return value; - } -}; +let columns1WithHighlightingById: any = {}; +let columns2WithHighlightingById: any = {}; // eslint-disable-next-line @typescript-eslint/no-empty-interface interface Props { } // eslint-disable-next-line @typescript-eslint/no-empty-interface -interface State extends BaseSlickGridState{} +interface State { + gridOptions1?: GridOption; + gridOptions2?: GridOption; + columnDefinitions1: Column[]; + columnDefinitions2: Column[]; + dataset1: any[]; + dataset2: any[]; +} export default class Example7 extends React.Component { title = 'Example 7: Header Button Plugin'; @@ -41,17 +40,22 @@ export default class Example7 extends React.Component { `; - gridObj: SlickGrid; columnsWithHighlightingById: Record; - reactGrid!:ReactGridInstance; + reactGrid1!: ReactGridInstance; + reactGrid2!: ReactGridInstance; constructor(public readonly props: Props) { super(props); - this.columnsWithHighlightingById = {}; + columns1WithHighlightingById = {}; + columns2WithHighlightingById = {}; + this.state = { - columnDefinitions: [], - dataset: [], - gridOptions: undefined + gridOptions1: undefined, + gridOptions2: undefined, + columnDefinitions1: [], + columnDefinitions2: [], + dataset1: [], + dataset2: [] }; } @@ -60,13 +64,16 @@ export default class Example7 extends React.Component { this.defineGrid(); } - reactGridReady(reactGrid: ReactGridInstance) { - this.reactGrid = reactGrid; - this.gridObj = reactGrid && reactGrid.slickGrid; + reactGrid1Ready(reactGrid: ReactGridInstance) { + this.reactGrid1 = reactGrid; + } + + reactGrid2Ready(reactGrid: ReactGridInstance) { + this.reactGrid2 = reactGrid; } - getGridOptions(){ - return { + defineGrid() { + const gridOptions1 = { enableAutoResize: true, enableHeaderButton: true, enableHeaderMenu: false, @@ -75,55 +82,99 @@ export default class Example7 extends React.Component { rightPadding: 10 }, enableFiltering: false, + enableExcelCopyBuffer: true, + excelCopyBufferOptions: { + onCopyCells: (e, args) => console.log('onCopyCells', e, args), + onPasteCells: (e, args) => console.log('onPasteCells', e, args), + onCopyCancelled: (e, args) => console.log('onCopyCancelled', e, args), + }, enableCellNavigation: true, + gridHeight: 275, headerButton: { // you can use the "onCommand" (in Grid Options) and/or the "action" callback (in Column Definition) - onCommand: (_e, args) => { - const column = args.column; - const button = args.button; - const command = args.command; - - if (command === 'toggle-highlight') { - if (button.cssClass === 'fa fa-circle red') { - delete columnsWithHighlightingById[column.id]; - button.cssClass = 'fa fa-circle-o red faded'; - button.tooltip = 'Highlight negative numbers.'; - } else { - columnsWithHighlightingById[column.id] = true; - button.cssClass = 'fa fa-circle red'; - button.tooltip = 'Remove highlight.'; - } - this.gridObj.invalidate(); - } - } + onCommand: (_e, args) => this.handleOnCommand(_e, args, 1) } }; - } - defineGrid() { - const columnDefinitions = this.getData(); - const gridOptions = this.getGridOptions(); + // grid 2 options, same as grid 1 + extras + const gridOptions2 = { + ...gridOptions1, + enableHeaderMenu: true, + enableFiltering: true, + // frozenColumn: 2, + // frozenRow: 2, + headerButton: { + onCommand: (_e, args) => this.handleOnCommand(_e, args, 2) + } + }; + + const columnDefinitions1 = this.createColumnDefinitions(1); + const columnDefinitions2 = this.createColumnDefinitions(2); - this.setState((state:any, props:any)=>{ + this.setState((state: any) => { return { ...state, - gridOptions, - columnDefinitions + gridOptions1, + gridOptions2, + columnDefinitions1, + columnDefinitions2, + dataset1: this.loadData(200, columnDefinitions1), + dataset2: this.loadData(200, columnDefinitions2), }; }); } - getData() { + handleOnCommand(_e: Event, args: any, gridNo: 1 | 2) { + const column = args.column; + const button = args.button; + const command = args.command; + + if (command === 'toggle-highlight') { + if (button.cssClass === 'fa fa-circle red') { + if (gridNo === 1) { + delete columns1WithHighlightingById[column.id]; + } else { + delete columns2WithHighlightingById[column.id]; + } + button.cssClass = 'fa fa-circle-o red faded'; + button.tooltip = 'Highlight negative numbers.'; + } else { + if (gridNo === 1) { + columns1WithHighlightingById[column.id] = true; + } else { + columns2WithHighlightingById[column.id] = true; + } + button.cssClass = 'fa fa-circle red'; + button.tooltip = 'Remove highlight.'; + } + if (gridNo === 1) { + this.reactGrid1.slickGrid.invalidate(); + } else { + this.reactGrid2.slickGrid.invalidate(); + } + } + } + + createColumnDefinitions(gridNo: number) { // Set up some test columns. const columnDefinitions: any[] = []; + for (let i = 0; i < 10; i++) { columnDefinitions.push({ id: i, name: 'Column ' + String.fromCharCode('A'.charCodeAt(0) + i), field: i + '', width: i === 0 ? 70 : 100, // have the 2 first columns wider + filterable: true, sortable: true, - formatter: highlightingFormatter, + formatter: (_row, _cell, value, columnDef) => { + if (gridNo === 1 && columns1WithHighlightingById[columnDef.id] && value < 0) { + return `
${value}
`; + } else if (gridNo === 2 && columns2WithHighlightingById[columnDef.id] && value < 0) { + return `
${value}
`; + } + return value; + }, header: { buttons: [ { @@ -180,6 +231,11 @@ export default class Example7 extends React.Component { ] }; + // when floating to left, you might want to inverse the icon orders + if (gridNo === 2) { + columnDefinitions[0].header?.buttons?.reverse(); + } + // Set a button on the second column to demonstrate hover. columnDefinitions[1].name = 'Hover me!'; columnDefinitions[1].header = { @@ -195,28 +251,25 @@ export default class Example7 extends React.Component { ] }; + return columnDefinitions; + } + + loadData(count: number, columnDefinitions: Column[]) { // mock a dataset const mockDataset: any[] = []; - for (let i = 0; i < 100; i++) { - const d = (mockDataset[i] = {}); - (d as any)['id'] = i; + + for (let i = 0; i < count; i++) { + const d: any = (mockDataset[i] = {}); + d['id'] = i; for (let j = 0; j < columnDefinitions.length; j++) { - (d as any)[j] = Math.round(Math.random() * 10) - 5; + d[j] = Math.round(Math.random() * 10) - 5; } } - - this.setState((state:any, props:any)=>{ - return { - ...state, - dataset: mockDataset - }; - }); - - return columnDefinitions; + return mockDataset; } render() { - return !this.state.gridOptions ? '' : ( + return !this.state.gridOptions2 ? '' : (

{this.title} @@ -230,11 +283,22 @@ export default class Example7 extends React.Component {

- this.reactGridReady($event.detail)} +
Grid 1
+ this.reactGrid1Ready($event.detail)} + /> + +
+ +
Grid 2 - with both Header Buttons & Menus
+ this.reactGrid2Ready($event.detail)} />
); diff --git a/src/examples/slickgrid/example9.tsx b/src/examples/slickgrid/example9.tsx index 95fc8b80..cdd34246 100644 --- a/src/examples/slickgrid/example9.tsx +++ b/src/examples/slickgrid/example9.tsx @@ -119,22 +119,16 @@ class Example9 extends React.Component { // we could disable the menu entirely by returning false depending on some code logic menuUsabilityOverride: () => true, - // use the click event position to reposition the grid menu (defaults to false) - // basically which offset do we want to use for reposition the grid menu, - // option1 is where we clicked (true) or option2 is where the icon button is located (false and is the defaults) - // you probably want to set this to True if you use an external grid menu button BUT set to False when using default grid menu - useClickToRepositionMenu: true, - // all titles optionally support translation keys, if you wish to use that feature then use the title properties with the 'Key' suffix (e.g: titleKey) - // example "customTitle" for a plain string OR "customTitleKey" to use a translation key - customTitleKey: 'CUSTOM_COMMANDS', + // example "commandTitle" for a plain string OR "commandTitleKey" to use a translation key + commandTitleKey: 'CUSTOM_COMMANDS', iconCssClass: 'fa fa-ellipsis-v', // defaults to "fa-bars" hideForceFitButton: true, hideSyncResizeButton: true, hideToggleFilterCommand: false, // show/hide internal custom commands menuWidth: 17, resizeOnShowHeaderRow: true, - customItems: [ + commandItems: [ // add Custom Items Commands which will be appended to the existing internal custom items // you cannot override an internal items but you can hide them and create your own // also note that the internal custom commands are in the positionOrder range of 50-60, @@ -197,7 +191,7 @@ class Example9 extends React.Component { } }, onColumnsChanged: (_e, args) => { - console.log('Column selection changed from Grid Menu, visible columns: ', args.columns); + console.log('Column selection changed from Grid Menu, visible columns: ', args.visibleColumns); } }, enableTranslate: true, diff --git a/src/index.tsx b/src/index.tsx index b223b06b..ed29333c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -15,6 +15,7 @@ import { App } from './examples/slickgrid/App'; import localeEn from './assets/locales/en/translation.json'; import localeFr from './assets/locales/fr/translation.json'; import './styles.scss'; +import './slickgrid.scss'; i18n .use(Backend) @@ -41,3 +42,7 @@ i18n const mainContainer = document.getElementById('main'); const root = createRoot(mainContainer as HTMLElement); root.render(); + +// load necessary Flatpickr Locale(s), but make sure it's imported AFTER loading Slickgrid-React plugin +// delaying the import will work for our use case +setTimeout(() => import('flatpickr/dist/l10n/fr')); diff --git a/src/slickgrid-react/components/slickgrid-react.tsx b/src/slickgrid-react/components/slickgrid-react.tsx index cfd486f1..e7bc60bf 100644 --- a/src/slickgrid-react/components/slickgrid-react.tsx +++ b/src/slickgrid-react/components/slickgrid-react.tsx @@ -324,6 +324,8 @@ export class ReactSlickgridComponent extends React.Component { - return this._eventPubSubService.dispatchCustomEvent(gridEventName, { eventData: event, args }); + this._eventHandler.subscribe(grid[prop], (event, args: any) => { + if (this.props.hasOwnProperty(prop)) { + const callback = this.props[prop]; + return typeof callback === 'function' && callback(new CustomEvent(gridEventName, { detail: { eventData: event, args } })); + } + return true; }); } } @@ -798,9 +807,13 @@ export class ReactSlickgridComponent extends React.Component { + this._eventHandler.subscribe(dataView[prop], (event, args: any) => { const dataViewEventName = this._eventPubSubService.getEventNameByNamingConvention(prop, slickgridEventPrefix); - return this._eventPubSubService.dispatchCustomEvent(dataViewEventName, { eventData: event, args }); + if (this.props.hasOwnProperty(prop)) { + const callback = this.props[prop]; + return typeof callback === 'function' && callback(new CustomEvent(dataViewEventName, { detail: { eventData: event, args } })); + } + return true; }); } } @@ -843,7 +856,6 @@ export class ReactSlickgridComponent extends React.Component { - grid.invalidate(); this.handleOnItemCountChanged(dataView.getFilteredItemCount() || 0, args.itemCount); // when user has resize by content enabled, we'll force a full width calculation since we change our entire dataset @@ -1056,7 +1068,6 @@ export class ReactSlickgridComponent extends React.Component