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;
