Hi Kendo team,
I'm exploring ways to convert Figma component designs directly into code. Has your component been convertable and what tools or methods would you recommend? I'm particularly interested in solutions that support React or other modern frameworks.
Problem summary: When including the ability to reorder columns and toggle column visibility on a grid ColumnMenu, the column order gets corrupted despite the correct order being stored and retrieved from session storage.
Detailed description: We want our users to be able to persist their grid column order and visibility. We also want the column order to be updated in the column menu. The column menu context keeps track of the order with a list of GridColumnProps. We save the column menu filter context and the column order into session storage.
Grid
ColumnMenuContext
Session storage
Because GridColumnProps doesn't contain an order index parameter, on our 'onColumnsReorder' event, I take the the GridColumnProps lists and order them based on the orderIndex of the columns passed to the events. This works as expected for when I only reorder the columns or I only toggle column visibility. However, if I reorder the columns and then toggle visibility without refreshing, I lose the original column order. I have verified multiple times in the console that the order being saved to session storage is correct. When I refresh after the column order is lost, it then loads the columns with the correct order.
I've seen this same behavior on other Telerik demos where you set reorderable={true} on a grid with a column menu. Easy steps to reproduce are always to switch the first two columns in the grid, and then toggle the first column's visibility to off. I've included text files (originally tsx files) with our data-grid component implementation and its component dependencies for reference. 'data-grid.tsx' contains the logic for saving the filter order and column order/visibility in the 'onColumnsChange' and the 'onColumnsReorder' event handlers.
If this can't be done with GridColumnProps, is there a different object we could save to the ColumnMenu's lists that would enable direct index tracking?
Hi.
Is it somehow possible to restrict the DatePicker component to only show the month or the year view (see attached screenshots) ?
In my component I have two fields. The first one should only allow a month / year input and the second one should only allow to choose a year. So I would like to use the DatePicker component but as it allows to also select a specific date in a month, that's more than I want to allow to the user.
Thanks,
Greetings,
Bernd
Is there a way to make the filter input (search box) appear at the top of the dropdown list in a multiselect exactly like it does in the dropdownlist component. The expected behavior is this:
Hello,
I am experiencing an issue with Kendo React PDF, as shown in the attached image. The problem is that the last row of content is being shifted to the next page, even though there is some space left on the previous page. This results in unnecessary empty spaces, which affects the overall layout of the document.
Here is a summary of the issue:
{
"ProductID": 9,
"ProductName": "Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku Mishi Kobe Niku ",
"SupplierID": 4,
"CategoryID": 6,
"QuantityPerUnit": "18 - 500 g pkgs.",
"UnitPrice": 97.0,
"UnitsInStock": 29,
"UnitsOnOrder": 0,
"ReorderLevel": 0,
"Discontinued": true,
"Category": {
"CategoryID": 6,
"CategoryName": "Meat/Poultry",
"Description": "Prepared meats"
}
}
I would appreciate any guidance or solutions to resolve this issue.
Thank you in advance for your help!
Best regards,
Aman
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>
);
};