in Kendo excel export version 5, I was able to use the CellOptions interface found in CellOptions.d.ts. This allowed me to create a shortcut const that could be used across my app for standard cellOptions:
export const cellOptions: CellOptions = { verticalAlign: "center", textAlign: "center" };
then use it like this:
However, in version 7 (and I'm guessing 8), that CellOptions interface has been moved to index.d.ts and is not exported from the types.
Is there some way I can export or use this to create the same kind of shortcut? Thank you.
I saw an example of setting focus on a new row in the table: https://stackblitz.com/edit/react-dym3qj?file=app%2Fmain.jsx. I tried adding a custom cell editor and setting it to focus, but it failed.
page.tsx:
"use client";
import * as React from 'react';
import {
Grid,
GridColumn as Column,
GridToolbar,
GridCellProps,
GridRowClickEvent,
GridItemChangeEvent
} from '@progress/kendo-react-grid';
import { sampleProducts } from './sample-products';
import { DropDownCell } from './myDropDownCell';
interface Product {
ProductID: number;
ProductName?: string;
FirstOrderedOn?: Date;
UnitsInStock?: number;
Discontinued?: boolean;
}
const App: React.FC = () => {
const [data, setData] = React.useState<Product[]>(sampleProducts);
const [editID, setEditID] = React.useState<number | null>(null);
const [newRecordID, setNewRecordID] = React.useState<number | null>(null); // 新增状态变量
const rowClick = (event: GridRowClickEvent) => {
setEditID(event.dataItem.ProductID);
};
const itemChange = (event: GridItemChangeEvent) => {
const inEditID = event.dataItem.ProductID;
const field = event.field || '';
const newData = data.map((item) =>
item.ProductID === inEditID ? { ...item, [field]: event.value } : item
);
setData(newData);
};
const closeEdit = (event: React.MouseEvent<HTMLDivElement>) => {
if (event.target === event.currentTarget) {
setEditID(null);
}
};
const addRecord = () => {
const nextID = data.length + 1;
const newRecord: Product = {
ProductID: nextID,
};
setData([newRecord, ...data]);
setEditID(newRecord.ProductID);
setNewRecordID(newRecord.ProductID); // 设置新增行的 ID
};
const cellRender = (td: React.ReactElement, props: GridCellProps) => {
if (!newRecordID || newRecordID !== props.dataItem.ProductID || props.field !== 'ProductName') {
return td;
}
return (
<td
{...td.props}
ref={(tdElement) => {
const input = tdElement && tdElement.querySelector('input');
const activeElement = document.activeElement as HTMLElement;
const isButton = activeElement.className.indexOf('k-button') >= 0;
if (
!input ||
!activeElement ||
input === activeElement ||
(!activeElement.contains(input) && !isButton)
) {
return;
} else {
setTimeout(() => {
input.select();
});
}
}}
></td>
);
};
return (
<Grid
cellRender={cellRender}
style={{
height: '420px',
}}
data={data.map((item) => ({
...item,
inEdit: item.ProductID === editID,
}))}
editField="inEdit"
onRowClick={rowClick}
onItemChange={itemChange}
>
<GridToolbar>
<div onClick={closeEdit}>
<button
title="Add new"
className="k-button k-button-md k-rounded-md k-button-solid k-button-solid-primary"
onClick={addRecord}
>
Add new
</button>
</div>
</GridToolbar>
<Column field="ProductID" title="Id" width="50px" editable={false} />
<Column field="FirstOrderedOn" title="First Ordered" editor="date" format="{0:d}" />
<Column field="ProductName" title="Name" cell={DropDownCell} />
<Column field="UnitsInStock" title="Units" width="150px" editor="numeric" />
<Column field="Discontinued" title="Discontinued" editor="boolean" />
</Grid>
);
};
const TestPage6: React.FC = () => {
return <App />;
};
export default TestPage6;
sample-products.tsx:
exportconst sampleProducts = [{
"ProductID": 1,
"ProductName": "Chai",
"SupplierID": 1,
"CategoryID": 1,
"QuantityPerUnit": "10 boxes x 20 bags",
"UnitPrice": 18,
"UnitsInStock": 39,
"UnitsOnOrder": 0,
"ReorderLevel": 10,
"Discontinued": false,
"Category": {
"CategoryID": 1,
"CategoryName": "Beverages",
"Description": "Soft drinks, coffees, teas, beers, and ales"
},
"FirstOrderedOn": newDate(1996, 8, 20)
}, {
"ProductID": 2,
"ProductName": "Chang",
"SupplierID": 1,
"CategoryID": 1,
"QuantityPerUnit": "24 - 12 oz bottles",
"UnitPrice": 19,
"UnitsInStock": 17,
"UnitsOnOrder": 40,
"ReorderLevel": 25,
"Discontinued": false,
"Category": {
"CategoryID": 1,
"CategoryName": "Beverages",
"Description": "Soft drinks, coffees, teas, beers, and ales"
},
"FirstOrderedOn": newDate(1996, 7, 12)
}, {
"ProductID": 3,
"ProductName": "Aniseed Syrup",
"SupplierID": 1,
"CategoryID": 2,
"QuantityPerUnit": "12 - 550 ml bottles",
"UnitPrice": 10,
"UnitsInStock": 13,
"UnitsOnOrder": 70,
"ReorderLevel": 25,
"Discontinued": false,
"Category": {
"CategoryID": 2,
"CategoryName": "Condiments",
"Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
},
"FirstOrderedOn": newDate(1996, 8, 26)
}, {
"ProductID": 4,
"ProductName": "Chef Anton's Cajun Seasoning",
"SupplierID": 2,
"CategoryID": 2,
"QuantityPerUnit": "48 - 6 oz jars",
"UnitPrice": 22,
"UnitsInStock": 53,
"UnitsOnOrder": 0,
"ReorderLevel": 0,
"Discontinued": false,
"Category": {
"CategoryID": 2,
"CategoryName": "Condiments",
"Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
},
"FirstOrderedOn": newDate(1996, 9, 19)
}, {
"ProductID": 5,
"ProductName": "Chef Anton's Gumbo Mix",
"SupplierID": 2,
"CategoryID": 2,
"QuantityPerUnit": "36 boxes",
"UnitPrice": 21.35,
"UnitsInStock": 0,
"UnitsOnOrder": 0,
"ReorderLevel": 0,
"Discontinued": true,
"Category": {
"CategoryID": 2,
"CategoryName": "Condiments",
"Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
},
"FirstOrderedOn": newDate(1996, 7, 17)
}, {
"ProductID": 6,
"ProductName": "Grandma's Boysenberry Spread",
"SupplierID": 3,
"CategoryID": 2,
"QuantityPerUnit": "12 - 8 oz jars",
"UnitPrice": 25,
"UnitsInStock": 120,
"UnitsOnOrder": 0,
"ReorderLevel": 25,
"Discontinued": false,
"Category": {
"CategoryID": 2,
"CategoryName": "Condiments",
"Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
},
"FirstOrderedOn": newDate(1996, 9, 19)
}, {
"ProductID": 7,
"ProductName": "Uncle Bob's Organic Dried Pears",
"SupplierID": 3,
"CategoryID": 7,
"QuantityPerUnit": "12 - 1 lb pkgs.",
"UnitPrice": 30,
"UnitsInStock": 15,
"UnitsOnOrder": 0,
"ReorderLevel": 10,
"Discontinued": false,
"Category": {
"CategoryID": 7,
"CategoryName": "Produce",
"Description": "Dried fruit and bean curd"
},
"FirstOrderedOn": newDate(1996, 7, 22)
}, {
"ProductID": 8,
"ProductName": "Northwoods Cranberry Sauce",
"SupplierID": 3,
"CategoryID": 2,
"QuantityPerUnit": "12 - 12 oz jars",
"UnitPrice": 40,
"UnitsInStock": 6,
"UnitsOnOrder": 0,
"ReorderLevel": 0,
"Discontinued": false,
"Category": {
"CategoryID": 2,
"CategoryName": "Condiments",
"Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
},
"FirstOrderedOn": newDate(1996, 11, 1)
}, {
"ProductID": 9,
"ProductName": "Mishi Kobe Niku",
"SupplierID": 4,
"CategoryID": 6,
"QuantityPerUnit": "18 - 500 g pkgs.",
"UnitPrice": 97,
"UnitsInStock": 29,
"UnitsOnOrder": 0,
"ReorderLevel": 0,
"Discontinued": true,
"Category": {
"CategoryID": 6,
"CategoryName": "Meat/Poultry",
"Description": "Prepared meats"
},
"FirstOrderedOn": newDate(1997, 1, 21)
}, {
"ProductID": 10,
"ProductName": "Ikura",
"SupplierID": 4,
"CategoryID": 8,
"QuantityPerUnit": "12 - 200 ml jars",
"UnitPrice": 31,
"UnitsInStock": 31,
"UnitsOnOrder": 0,
"ReorderLevel": 0,
"Discontinued": false,
"Category": {
"CategoryID": 8,
"CategoryName": "Seafood",
"Description": "Seaweed and fish"
},
"FirstOrderedOn": newDate(1996, 8, 5)
}];
MyDropDownCell.tsx:
import * as React from 'react';
import { MultiColumnComboBox } from '@progress/kendo-react-dropdowns';
import { GridCellProps } from '@progress/kendo-react-grid';
// 定义员工数据和列
const employees = [
{
id: 1,
name: "Daryl Sweeney",
reportsTo: null,
phone: "(555) 924-9726",
extension: 8253,
hireDate: new Date("2012-02-07T20:00:00.000Z"),
fullTime: true,
position: "CEO",
timeInPosition: 2,
},
{
id: 2,
name: "Guy Wooten",
reportsTo: 1,
phone: "(438) 738-4935",
extension: 1155,
hireDate: new Date("2010-03-03T20:00:00.000Z"),
fullTime: true,
position: "Chief Technical Officer",
timeInPosition: 1,
}
];
const columns = [
{ field: 'id', header: 'ID', width: '100px' },
{ field: 'name', header: 'Name', width: '300px' },
{ field: 'position', header: 'Position', width: '300px' }
];
// 创建 DropDownCell 组件
export const DropDownCell = (props: GridCellProps) => {
const { dataItem, field, onChange } = props;
const dataValue = dataItem[field];
const handleChange = (e: any) => {
if (onChange) {
onChange({
dataItem,
field,
syntheticEvent: e.syntheticEvent,
value: e.target.value
});
}
};
return (
<td>
{dataItem.inEdit ? (
<MultiColumnComboBox
data={employees}
columns={columns}
textField="name"
style={{ width: '300px' }}
placeholder="Please select ..."
value={employees.find(emp => emp.name === dataValue)}
onChange={handleChange}
/>
) : (
dataValue
)}
</td>
);
};
Hi All,
I used grid with filter, and found that the filter pop up of grid move along with the horizontal scroll bar, This seems a bit strange, can't the filter panel automatically collapse when scrolling?
Hello,
Using the ThemeBuilder, we would like to change the default theme for all the buttons in the application.
There is a way to setup the buttons for the "Secondary" and "Primary" theme.
And it seems that some components use the "Secondary" theme, instead of the "Primary" theme. Like here, with the ListBox:
How can we setup our buttons in the ThemeBuilder, so that the default theme used by the components is the "Primary" theme?
I would like to dynamically load the sub-items of a TreeList whenever the triangle infront of an element is clicked to open the sub-item and then fetch the sub-items from an API. I guess I need to use the onExpandChange event for this, correct? Do you have an example on how I would have to extend the original tree when the sub-items have loaded?
Any hints would be greatly appreciated.
Thanks,
Bernd
hi, I'm using DatePicker & TimePicker components. Seems like they use browser's time zone.
I need to customize time zone to one which is used on my backend.
Is there any way to do it?