I decide to use webpack external to dynamically load the scipt files using CDN links. But, I am getting the below script error.
react-dom.production.min.js:125 TypeError: Cannot read property 'Button' of undefined
at c (main.js:1)
at we (react-dom.production.min.js:84)
at zj (react-dom.production.min.js:226)
at Th (react-dom.production.min.js:152)
at tj (react-dom.production.min.js:152)
at Te (react-dom.production.min.js:146)
at Ja (react-dom.production.min.js:224)
at md (react-dom.production.min.js:173)
at react-dom.production.min.js:175
at Rh (react-dom.production.min.js:147)
Me @ react-dom.production.min.js:125
react-dom.production.min.js:161 Uncaught TypeError: Cannot read property 'Button' of undefined
at c (main.js:1)
at we (react-dom.production.min.js:84)
at zj (react-dom.production.min.js:226)
at Th (react-dom.production.min.js:152)
at tj (react-dom.production.min.js:152)
at Te (react-dom.production.min.js:146)
at Ja (react-dom.production.min.js:224)
at md (react-dom.production.min.js:173)
at react-dom.production.min.js:175
at Rh (react-dom.production.min.js:147)
I know that Kendo React components could loaded only with script files but I want maintain the TypeScript standard. So, it is not possible.
I have attached the simple example application. Please help me to clear this. I have gone through multiple resource but not able to get it worked with Kendo component. Without Kendo there is no issue.
Hi everybody
I was wondering how to style the tooltip, preferrably with styled components. It should have a white background and black font color. The text should spread over 3 lines and the tooltip should have a drop shadow.
But this looks not at all what I expect.
const StyledTooltip = styled(Tooltip)`
background
:
white
;
color
:
black
;
height
:
116px
;
`;
I don't need a full solution, but a hint, how to style the tooltip.
Thanks in advance
Lukas
Hi,
I'm trying to figure out how to package my solution based on the "Create-React-App" template (TypeScript). I want to use the Externals node in the webpack configuration to ensure the KendoReact packages are excluded from the packaging procedures.
I saw this article: https://www.telerik.com/kendo-react-ui/components/installation/scripts-only . However, this approach means i need to reference all controls via the Window object. I rather keep the code base as is, so using import statements like
import { Grid, GridColumn as Column } from "@progress/kendo-react-grid
and use the control in Jsx. Is this possible?
Best regards,
Ruud
Does anyone know where I could find an example of a Kendo React Grid that is databound programmatically to an API Endpoint data source.
The paging would be done by passing a page number to the Endpoint.
I have no idea how to sort or filter the entire dataset if the grid is only showing a subset (page) of the data.
data using functional state variable. Could you please provide a Kendo React Grid functional component (using useState, useEffect..) example?
Below is code i'm working on:
import React, { useEffect, useState } from "react";
import { getAllFmsForms } from "../../apis/fmsFormApi";
import { Grid, GridColumn } from "@progress/kendo-react-grid";
import { process } from "@progress/kendo-data-query";
import "@progress/kendo-theme-bootstrap/dist/all.css";
const Forms = () => {
const [formsList, setFormsList] = useState([]);
const dataStateObj = {
skip: 0,
take: 20,
sort: [{ field: "formNumber", dir: "desc" }],
group: [{ field: "formNumber" }],
};
useEffect(() => {
const getAllForms = async () => {
try {
const response = await getAllFmsForms();
setFormsList(response);
} catch (error) {
console.log("error in getAllForms ===> ", error);
};
getAllForms();
}, []);
return (
<>
<
h3
>List</
h3
>
<
Grid
sortable
filterable
pageable={{ buttonCount: 4, pageSizes: true }}
data={process(formsList,dataState)} ---> error
onDataStateChange={(e) => {}}
>
<
GridColumn
field
=
"formNumber"
title
=
"Form Number"
/>
<
GridColumn
field
=
"formTitle"
title
=
"Form Title"
/>
<
GridColumn
field
=
"revisionDate"
title
=
"Revision Date"
/>
<
GridColumn
field
=
"formStatus"
title
=
"Form Status"
/>
<
GridColumn
field
=
"responsibleOffice"
title
=
"Office"
/>
</
Grid
>
</>
);
};
export default Forms;
I've tried below way too:
const [dataState, setDataState] = useState({
dataResult: process(formsList, dataStateObj), ----> error with dataStateObj
dataState: dataStateObj,
});
Hello,
https://imgur.com/a/1zohd9u
I ask how to rerender master grid when i click in button from the detail grid (look the picture).
Once i click in Rejected/Accepted button in detail grid, the database will be updated and the statut field of master grid change (in database).
but the new value not displayed because i have to manually refresh the page.
I need to setState the data of the master grid to refresh it and display the updated value of Statut field knowing that the button is in detail grid, so how to get access to function that update the state of master grid data ?
Thank you
master grid :
import { GridColumn as Column, Grid, GridDetailRow } from
'@progress/kendo-react-grid'
;
import MyCustomCell from
'../grids/CustomCell'
;
import React from
'react'
;
import axios from
"axios"
;
import { filterBy } from
'@progress/kendo-data-query'
;
import gridDetailInputSecondLevel from
'../gridsDetails/gridDetailInputSecondLevel'
;
const loadingPanel = (
<div className=
"k-loading-mask"
>
<span className=
"k-loading-text"
>Loading</span>
<div className=
"k-loading-image"
></div>
<div className=
"k-loading-color"
></div>
</div>
);
const dataStateDetail1 = {
posts: [],
sort: [],
take: 25,
skip: 0,
total_record: 10000,
pageNumber: 1,
filterUrl:
''
};
class gridDetailInputFirstLevel extends GridDetailRow {
terminalid = window.SERVER_DATA.terminalid;
functionid = window.SERVER_DATA.functionid;
hostname = window.SERVER_DATA.hostname;
jobId =
this
.props.dataItem.jobId;
state = {
filter: {
logic:
"and"
,
filters: []
},
filterInUrl:
''
,
dataStateDetail1: dataStateDetail1,
isLoading:
true
};
// constructeur
constructor(props) {
super
(props);
this
.CustomCell = MyCustomCell(
this
.getPostsDetailLevl1);
}
componentDidMount() {
this
.getPostsDetailLevl1();
}
// MycustomParam = (props) => <MyCustomCell {...props} myfonct = {this.getPostsDetailLevl1}/>
// {...props} spread operator
render() {
const { isLoading, dataStateDetail1 } =
this
.state;
return
(
<div>
{isLoading && loadingPanel}
<Grid
data={filterBy(dataStateDetail1.posts,dataStateDetail1.filter)}
skip={dataStateDetail1.skip}
take={dataStateDetail1.take}
total={dataStateDetail1.total_record}
pageable
filterable
sortable
onPageChange={
this
.pageChange}
filter={
this
.state.filter}
onFilterChange={
this
.onFilterChange}
total={
this
.state.dataStateDetail1.total_record}
detail={gridDetailInputSecondLevel}
expandField=
"expanded"
onExpandChange={
this
.expandChange}
>
<Column field=
"jobId"
title=
"JOB ID"
filterable={
false
} width=
"120px"
/>
<Column field=
"PurchaseOrderNumber"
title=
"PO NUMBER"
width=
"170px"
/>
<Column field=
"Statut"
title=
"STATUS"
width=
"170px"
/>
<Column filter=
"date"
format=
"{0:yyyy-MM-dd}"
field=
"PODate"
title=
"PO DATE"
width=
"170px"
/>
<Column field=
"ReceiverISA"
title=
"PARTNER"
/>
<Column field=
"POType"
title=
"PO TYPE"
width=
"170px"
/>
<Column
width=
"200px"
filterable={
false
}
cell={
this
.CustomCell}/>
</Grid>
</div>
);
}
// cette fct permet d'ouvrir une sous grid
expandChange = (event) => {
event.dataItem.expanded = event.value;
let jobId = event.dataItem.jobId;
this
.setState({ ...
this
.state });
if
(!event.value || event.dataItem.tt_order_line) {
return
;
}
}
/* // par la programmation laisser le row expanded
keepExpanded = (dataItem) => {
dataItem.expanded = true;
this.setState({});
} */
// formatter les dates dans le fichier json
replacerDateinJSON (key, value) {
if
(key ===
'podate'
) {
var
d =
new
Date(value);
d.setDate(d.getDate() + 1);
return
new
Date(d);
}
return
value;
}
formatDateForFiltre = (e) => {
if
(e.field ===
"podate"
)
{
var
d =
new
Date(e.value);
var
month =
""
+ (d.getMonth() + 1);
var
day =
""
+ d.getDate();
var
year = d.getFullYear();
if
(month.length < 2) month =
"0"
+ month;
if
(day.length < 2) day =
"0"
+ day;
return
[day,month,year].join(
"/"
);
}
return
e.value;
}
getPostsDetailLevl1 = () => {
/* let ji;
if (d != undefined) {
ji = d.tt_order[0].jobId;
} */
axios
.get(
this
.hostname+`edipo/xediPurchaseOrder.p?terminalid=` +
this
.terminalid +
"&Funct=bb1.EdiManager"
+
"&FunctionID="
+
this
.functionid +
"&pageSize=25"
+
"&skip="
+
this
.state.dataStateDetail1.skip +
"&take="
+
this
.state.dataStateDetail1.take +
"&page="
+
this
.state.dataStateDetail1.pageNumber +
"&lastRecord=false"
+
"&filter[logic]=and&filter[filters][0][field]=jobId&filter[filters][0][operator]=eq&filter[filters][0][value]="
+
this
.jobId +
(
this
.state.filterUrl ?
this
.state.filterUrl :
''
)
)
.then(response => {
let pos = response.data.ProDataSet.tt_order ? response.data.ProDataSet.tt_order:[];
// let pos = response.data.ProDataSet.tt_order ? response.data.ProDataSet.tt_order.map(dataItem => ji===dataItem.jobId?Object.assign({ expanded: !dataItem.expanded }, dataItem):dataItem):[];
// format date to dd/MM/yyyy
pos = JSON.parse(JSON.stringify(pos),
this
.replacerDateinJSON);
this
.setState({
dataStateDetail1: {
...
this
.state.dataStateDetail1,
posts: pos,
total_record: response.data.ProDataSet.tt_Misc[0].total_record,
},
isLoading:
false
});
})
.
catch
(error =>
this
.setState({ error, isLoading:
false
}));
}
pageChange = (event) => {
this
.setState({
dataStateDetail1: {
...
this
.state.dataStateDetail1,
skip: event.page.skip,
take: event.page.take,
pageNumber: (event.page.skip + event.page.take) / 25
},
isLoading:
true
},()=>{
this
.getPostsDetailLevl1();});
}
onFilterChange = (event) => {
let filterUrl =
''
;
// créer le filtre à ajouter dans l'url
if
(event.filter !=
null
){
const filters = event.filter.filters;
filters.map((filedValue,index) => {
filterUrl = filterUrl +
"&filter[filters]["
+ (index + 1) +
"][operator]="
+ filedValue.operator +
"&filter[filters]["
+
(index + 1) +
"][value]="
+
this
.formatDateForFiltre (filedValue) +
"&filter[filters]["
+ (index + 1) +
"][field]="
+ filedValue.field;
}
);
}
console.log(
"filterUrl"
,filterUrl);
this
.setState({
dataStateDetail1: {
...
this
.state.dataStateDetail1,
skip: 0},
filter: event.filter,
filterUrl,
isLoading:
true
},()=>{
this
.getPostsDetailLevl1()});
}
}
export
default
gridDetailInputFirstLevel;
detail grid :
import { GridColumn as Column, Grid, GridDetailRow } from
'@progress/kendo-react-grid'
;
import { Dialog, DialogActionsBar } from
'@progress/kendo-react-dialogs'
;
import React, { useState } from
'react'
;
import { Button } from
"@progress/kendo-react-buttons"
;
import MyCustomCell from
'../grids/CustomCell'
;
import axios from
"axios"
;
import { filterBy } from
'@progress/kendo-data-query'
;
const loadingPanel = (
<div className=
"k-loading-mask"
>
<span className=
"k-loading-text"
>Loading</span>
<div className=
"k-loading-image"
></div>
<div className=
"k-loading-color"
></div>
</div>
);
const dataStateDetail2 = {
posts: [],
sort: [],
take: 25,
skip: 0,
total_record: 10000,
pageNumber: 1,
filterUrl:
''
};
const ConfirmAcceptPoLine = (props) => {
return
(
<td>
<Button
icon=
"track-changes-enable"
title=
"Confirm"
primary={
true
}
className=
"k-button"
onClick={props.myProp}
style={{ paddingLeft:55, paddingRight:55 }}
>
Envoyer
</Button>
</td>
);
}
class gridDetailInputSecondLevel extends GridDetailRow {
terminalId = window.SERVER_DATA.terminalid;
functionId = window.SERVER_DATA.functionid;
hostname = window.SERVER_DATA.hostname;
PurchaseOrderNumber =
this
.props.dataItem.PurchaseOrderNumber;
rowRender(trElement, props) {
const st = props.dataItem.Statut;
const green = { backgroundColor:
"rgb(55, 180, 0,0.32)"
};
const red = { backgroundColor:
"rgb(243, 23, 0, 0.32)"
};
const defau = {};
let val = {};
switch
(st) {
case
'Accepted'
: val = green;
break
;
case
'Rejected'
: val = red;
break
;
default
: val = defau;
}
const trProps = { style: val };
return
React.cloneElement(trElement, { ...trProps }, trElement.props.children);
}
state = {
filter: {
logic:
"and"
,
filters: []
},
filterInUrl:
''
,
dataStateDetail2: dataStateDetail2,
isLoading:
true
,
visible:
false
};
// constructeur
constructor(props) {
super
(props);
this
.CustomCell = MyCustomCell(
this
.getPostsDetailLevl2);
}
toggleDialog = () => {
this
.setState({
visible: !
this
.state.visible
});
}
toggleDialogNo = () => {
this
.setState({
visible: !
this
.state.visible
});
console.log(
"Nooooo"
);
}
toggleDialogYes = () => {
this
.setState({
visible: !
this
.state.visible
});
this
.processOrdre();
}
componentDidMount() {
this
.getPostsDetailLevl2();
}
MyCell = (props) => <ConfirmAcceptPoLine {...props} myProp={
this
.toggleDialog} />
render() {
const { isLoading, dataStateDetail2 } =
this
.state;
return
(
<div>
{isLoading && loadingPanel}
<Grid
data={filterBy(dataStateDetail2.posts,dataStateDetail2.filter)}
skip={dataStateDetail2.skip}
take={dataStateDetail2.take}
total={dataStateDetail2.total_record}
pageable
filterable
sortable
// height="200px"
onPageChange={
this
.pageChange}
filter={
this
.state.filter}
onFilterChange={
this
.onFilterChange}
total={
this
.state.dataStateDetail2.total_record}
rowRender={
this
.rowRender}
>
<Column field=
"PurchaseOrderNumber"
title=
"PO Number"
filterable={
false
}/>
<Column field=
"POLineNumber"
title=
"PO Line Number"
/>
<Column field=
"Statut"
title=
"STATUS"
/>
<Column field=
"VendorProductNumberCode"
title=
"ITEM"
/>
<Column field=
"Descriptionsequence"
title=
"DESCRIPTION"
/>
<Column field=
"OrderedQty"
title=
"ORDERED QTY"
/>
<Column field=
"SellingPrice"
title=
"SELLING PRICE"
/>
<Column
width=
"200px"
filterable={
false
}
cell={
this
.CustomCell }
footerCell={
this
.MyCell}
/>
</Grid>
{
this
.state.visible && <Dialog title={
"Please confirm"
} onClose={
this
.toggleDialog}>
<p style={{ margin:
"25px"
, textAlign:
"center"
}}>Are you sure you want to
continue
?</p>
<DialogActionsBar>
<button className=
"k-button"
onClick={
this
.toggleDialogNo}>No</button>
<button className=
"k-button"
onClick={
this
.toggleDialogYes}>Yes</button>
</DialogActionsBar>
</Dialog>}
</div>
);
}
// formatter les dates dans le fichier json
replacerDateinJSON (key, value) {
if
(key ===
'deliveryreq'
) {
var
d =
new
Date(value);
d.setDate(d.getDate() + 1);
return
new
Date(d);
}
return
value;
}
formatDateForFiltre = (e) => {
if
(e.field ===
"deliveryreq"
)
{
var
d =
new
Date(e.value);
var
month =
""
+ (d.getMonth() + 1);
var
day =
""
+ d.getDate();
var
year = d.getFullYear();
if
(month.length < 2) month =
"0"
+ month;
if
(day.length < 2) day =
"0"
+ day;
return
[day,month,year].join(
"/"
);
}
return
e.value;
}
getPostsDetailLevl2 = () => {
axios
.get(
this
.hostname+`edipo/xediPurchaseOrderLine.p?terminalid=` +
this
.terminalId +
"&Funct=bb1.EdiManager"
+
"&FunctionID="
+
this
.functionId +
"&pageSize=25"
+
"&skip="
+
this
.state.dataStateDetail2.skip +
"&take="
+
this
.state.dataStateDetail2.take +
"&page="
+
this
.state.dataStateDetail2.pageNumber +
"&lastRecord=false"
+
"&filter[logic]=and&filter[filters][0][field]=PurchaseOrderNumber&filter[filters][0][operator]=eq&filter[filters][0][value]="
+
this
.PurchaseOrderNumber +
(
this
.state.filterUrl ?
this
.state.filterUrl :
''
)
)
.then(response => {
let pos = response.data.ProDataSet.tt_order_line ? response.data.ProDataSet.tt_order_line:[];
// format date to dd/MM/yyyy
pos = JSON.parse(JSON.stringify(pos),
this
.replacerDateinJSON);
this
.setState({
dataStateDetail2: {
...
this
.state.dataStateDetail2,
posts: response.data.ProDataSet.tt_order_line,
total_record: response.data.ProDataSet.tt_Misc[0].total_record,
},
isLoading:
false
},()=>{console.log(
this
.state.dataStateDetail2.posts);});
})
.
catch
(error =>
this
.setState({ error, isLoading:
false
}));
}
pageChange = (event) => {
this
.setState({
dataStateDetail2: {
...
this
.state.dataStateDetail2,
skip: event.page.skip,
take: event.page.take,
pageNumber: (event.page.skip + event.page.take) / 25
},
isLoading:
true
},()=>{
this
.getPostsDetailLevl2();});
}
onFilterChange = (event) => {
let filterUrl =
''
;
// créer le filtre à ajouter dans l'url
if
(event.filter !=
null
){
const filters = event.filter.filters;
filters.map((filedValue,index) => {
filterUrl = filterUrl +
"&filter[filters]["
+ (index + 1) +
"][operator]="
+ filedValue.operator +
"&filter[filters]["
+
(index + 1) +
"][value]="
+ filedValue.value +
"&filter[filters]["
+ (index + 1) +
"][field]="
+ filedValue.field;
}
);
}
this
.setState({
dataStateDetail2: {
...
this
.state.dataStateDetail2,
skip: 0},
filter: event.filter,
filterUrl,
isLoading:
true
},()=>{
this
.getPostsDetailLevl2()});
}
processOrdre = () => {
const SESSION = window.SERVER_DATA;
let url = SESSION.hostname +
"edipo/xediPurchaseOrder.p?terminalid="
+
SESSION.terminalid +
"&Funct=bb1.EdiManager"
+
"&FunctionID="
+
SESSION.functionid +
"&po="
+
this
.PurchaseOrderNumber +
"&processed=yes"
axios
.post(url)
.then((res) => {console.log(
"Processed"
);});
}
}
export
default
gridDetailInputSecondLevel;
Hello.
We are testing with selenium and jest and the pattern we use to identify elements is through the use of data-* attributes. We are trying to follow this same pattern with the Kendo React components but, at least for the Grid component so far, any custom props that we pass in are ignored by the component. From a design pattern perspective I totally understand why this would happen but I am wondering if there is some way to achieve what is described below:
React Component
<Grid className="grid" data={data} data-testName="reactGrid" ...> ... </Grid>
Rendered Output
<div class="k-grid" data-testName="reactGrid">
...data...
</div>
Reading through the API documentation I couldn't seem to find anything.
Thanks!
Hi,
is there a (complete) list of the classnames used in Kendo UI / React components?
Thanks.
Best Regards
Yahia
01.
<Tooltip openDelay={100} position=
"right"
anchorElement=
"element"
>
02.
<Grid
03.
data={process(
this
.state.managers.map((manager) => ({...manager, selected: manager[
"mail"
] ==
this
.state.selectedID}) ),
this
.state.gridDataState)}
04.
{...
this
.state.gridDataState}
05.
onDataStateChange={
this
.handleGridDataStateChange}
06.
style={{ height:
"300px"
}}
07.
pageable={
true
}
08.
sortable={
true
}
09.
selectedField=
"selected"
10.
onRowClick={(e) => {
11.
this
.setState({ selectedID: e.dataItem.mail });
12.
this
.props.callback(e.dataItem.mail);
13.
}}
14.
>
15.
16.
<Column field=
"mail"
title=
"email"
filter={
'text'
} headerCell={MailHeader} columnMenu={ColumnMenu} headerClassName=
"k-header-filtered"
/>
17.
<Column field=
"givenName"
title=”first name” filter={
'text'
} columnMenu={ColumnMenu} headerClassName=
"k-header-filtered"
/>
18.
<Column field=
"sn"
title=”last name” filter={
'text'
} columnMenu={ColumnMenu} headerClassName"k-header-filtered”/>
19.
<Column field=
"managerOf"
title=”manager of” filter={
'text'
} columnMenu={ColumnMenu} headerClassName=
"k-header-filtered"
/>
20.
21.
</Grid>
22.
</Tooltip>
The above is how I have implemented my Grid with tooltips. My MailHeader component looks like:
1.
class MailHeader extends React.Component<Readonly<MailHeaderProps>, {}> {
2.
render() {
3.
return
(
4.
<span title={
this
.props.title}>{
this
.props.title}</span>
5.
);
6.
}
7.
}
But I get this error:
TS2326: Types of property 'headerCell' are incompatible.
Type 'typeof MailHeader' is not assignable to type 'ComponentType<GridHeaderCellProps>'.
Type 'typeof MailHeader' is not assignable to type 'StatelessComponent<GridHeaderCellProps>'.
Type 'typeof MailHeader' provides no match for the signature '(props: GridHeaderCellProps & { children?: ReactNode; }, context?: any):ReactElement<any>'.
Can anyone point me in the right direction to an answer or a possible clue?