Skip to content

Updated Excel edit style sample to functional component (React v19) #777

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: v19-updates
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 104 additions & 112 deletions samples/grids/grid/editing-excel-style/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,146 +1,138 @@
import React from 'react';
import React, { useRef, useEffect } from 'react';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The React import is unused and should be removed

import ReactDOM from 'react-dom/client';
import './index.css';

import { IgrGridModule } from 'igniteui-react-grids';
import { IgrActiveNodeChangeEventArgs, IgrGridModule } from 'igniteui-react-grids';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IgrActiveNodeChangeEventArgs isn't used - either remove the import or better yet - use the type for the event handler

import { IgrGrid, IgrColumn } from 'igniteui-react-grids';
import { ComponentRenderer, WebGridDescriptionModule } from 'igniteui-react-core';
import NwindData from './NwindData.json';
import { IgrGridKeydownEventArgs } from 'igniteui-react-grids';

import 'igniteui-react-grids/grids/combined';
import 'igniteui-react-grids/grids/themes/light/bootstrap.css';

const mods: any[] = [
IgrGridModule
];
mods.forEach((m) => m.register());
// Register modules once
IgrGridModule.register();
Comment on lines +12 to +13
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer needed and can be removed as visible if ran with the 19 package:
image


export default class Sample extends React.Component<any, any> {
private grid1: IgrGrid
private grid1Ref(r: IgrGrid) {
this.grid1 = r;
this.setState({});
}
const nwindData = NwindData;

constructor(props: any) {
super(props);
const Sample = () => {
const gridRef = useRef<IgrGrid>(null);
const shouldAppendValue = useRef(false);

this.grid1Ref = this.grid1Ref.bind(this);
this.webGridEditingExcelStyle = this.webGridEditingExcelStyle.bind(this);
}
useEffect(() => {
const gridElement = gridRef.current;

public render(): JSX.Element {
return (
<div className="container sample ig-typography">

<div className="container fill">
<IgrGrid
autoGenerate={false}
data={this.nwindData}
primaryKey="ProductID"
gridKeydown={this.webGridEditingExcelStyle}
ref={this.grid1Ref}>
<IgrColumn
field="ProductID"
header="Product ID"
editable={true}
groupable={true}
hidden={true}>
</IgrColumn>
<IgrColumn
field="ProductName"
header="Product Name"
dataType="string"
editable={true}>
</IgrColumn>
<IgrColumn
field="UnitPrice"
header="Unit Price"
dataType="number"
editable={true}>
</IgrColumn>
<IgrColumn
field="QuantityPerUnit"
header="Quantity Per Unit"
groupable={true}
dataType="string"
editable={true}>
</IgrColumn>
<IgrColumn
field="ReorderLevel"
header="Reorder Level"
dataType="number"
groupable={true}
editable={true}>
</IgrColumn>
</IgrGrid>
</div>
</div>
);
}

private _nwindData: any[] = NwindData;
public get nwindData(): any[] {
return this._nwindData;
}

private _componentRenderer: ComponentRenderer = null;
public get renderer(): ComponentRenderer {
if (this._componentRenderer == null) {
this._componentRenderer = new ComponentRenderer();
var context = this._componentRenderer.context;
WebGridDescriptionModule.register(context);
if (!gridElement) {
return undefined;
}
return this._componentRenderer;
}

public webGridEditingExcelStyle(sender: IgrGrid, args: IgrGridKeydownEventArgs): void {
var key = (args.detail.event as any).keyCode;
var grid = args.detail.target.grid;
var activeElem = grid.navigation.activeNode;
const handleKeyDown = (event: KeyboardEvent) => {
var code = event.code;
var activeElem = gridRef.current.selectedCells[0];

if ((event.code >= 'Digit0' && event.code <= 'Digit9') ||
(event.code >= 'KeyA' && event.code <= 'KeyZ') ||
(event.code >= 'Numpad0' && event.code <= 'Numpad9') &&
event.code !== 'Enter' && event.code !== 'NumpadEnter') {

if (activeElem && activeElem.editMode === false) {
activeElem.editMode = true;
activeElem.editValue = event.key;
shouldAppendValue.current = true;
gridRef.current.markForCheck();
} else

if (activeElem && activeElem.editMode && shouldAppendValue.current) {
event.preventDefault();
activeElem.editValue = activeElem.editValue + event.key;
shouldAppendValue.current = false;
}
}

if ((key >= 48 && key <= 57) || (key >= 65 && key <= 90) || (key >= 97 && key <= 122)) {
var columnName = grid.getColumnByVisibleIndex(activeElem.column).field;
var cell = grid.getCellByColumn(activeElem.row, columnName);
if (code === 'Backspace') {
if(activeElem == null) {
return;
}
const rowIndex = activeElem.row.index;
const columnKey = activeElem.column.field;

gridRef.current.data[rowIndex][columnKey] = '';
gridRef.current.markForCheck();

if (cell && !grid.crudService.cellInEditMode) {
grid.crudService.enterEditMode(cell);
cell.editValue = key;
}
}

if (key == 13) {
var thisRow = activeElem.row;
var column = activeElem.column;
var rowInfo = grid.dataView;
if (code === 'Enter' || code === 'NumpadEnter') {

if(activeElem == null) {
return;
}

const thisRow = activeElem.row.index;
const dataView = gridRef.current.dataView;
const nextRowIndex = getNextEditableRowIndex(thisRow, dataView, event.shiftKey);

gridRef.current.navigateTo(nextRowIndex, activeElem.column.visibleIndex, (obj: any) => {

requestAnimationFrame(() => {
gridRef.current.endEdit(true, obj);
gridRef.current.clearCellSelection();
obj.target.activate();

});
});

var nextRow = this.getNextEditableRowIndex(thisRow, rowInfo, (args.detail.event as any).shiftKey);
}
};

grid.navigateTo(nextRow, column, (obj: any) => {
obj.target.activate();
grid.clearCellSelection();
});
}
}
gridElement.addEventListener("keydown", handleKeyDown);
Comment on lines +41 to +86
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple points:

  • Why is this stuck in useEffect? The old sample used gridKeydown which should now be onGridKeydown and should be used instead
  • What's with the gridRef.current.markForCheck();, requestAnimationFrame and endEdit calls? Those aren't needed in the original source (ng) and shouldn't be here as well. If they are, we might want to investigate why. Especially the rAF since it's in the already delayed navigateTo callback


return () => {
gridElement.removeEventListener("keydown", handleKeyDown);
};
}, []);

public getNextEditableRowIndex(currentRowIndex: number, dataView: any, previous: boolean) {

const getNextEditableRowIndex = (currentRowIndex: number, dataView: any, previous: boolean) => {
if (currentRowIndex < 0 || (currentRowIndex === 0 && previous) || (currentRowIndex >= dataView.length - 1 && !previous)) {
return currentRowIndex;
}
if (previous) {
return dataView.findLastIndex((rec: any, index: number) => index < currentRowIndex && this.isEditableDataRecordAtIndex(index, dataView));
return dataView.findLastIndex((rec: any, index: number) => index < currentRowIndex && isEditableDataRecordAtIndex(index, dataView));
}
return dataView.findIndex((rec: any, index: number) => index > currentRowIndex && this.isEditableDataRecordAtIndex(index, dataView));
}
return dataView.findIndex((rec: any, index: number) => index > currentRowIndex && isEditableDataRecordAtIndex(index, dataView));
};

public isEditableDataRecordAtIndex(dataViewIndex: number, dataView: any) {
const isEditableDataRecordAtIndex = (dataViewIndex: number, dataView: any) => {
const rec = dataView[dataViewIndex];
return !rec.expression && !rec.summaries && !rec.childGridsData && !rec.detailsData;
};

function gridEndEdit(event: CustomEvent<any>): void {
gridRef.current.endEdit(true, event.detail);
}

}
return (
<div className="container sample ig-typography">
<div className="container fill">
<IgrGrid
autoGenerate={false}
data={nwindData}
primaryKey="ProductID"
ref={gridRef}
onActiveNodeChange={gridEndEdit}
>
<IgrColumn field="ProductID" header="Product ID" editable={true} groupable={true} hidden={true} />
<IgrColumn field="ProductName" header="Product Name" dataType="string" editable={true} />
<IgrColumn field="UnitPrice" header="Unit Price" dataType="number" editable={true} />
<IgrColumn field="QuantityPerUnit" header="Quantity Per Unit" groupable={true} dataType="string" editable={true} />
<IgrColumn field="ReorderLevel" header="Reorder Level" dataType="number" groupable={true} editable={true} />
</IgrGrid>
</div>
</div>
);
};

export default Sample;

// rendering above component in the React DOM
// Render the component
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Sample/>);
root.render(<Sample />);