This is a migrated thread and some comments may be shown as answers.

How to rerender master grid when i click in button from the detail grid ?

2 Answers 1425 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Raef
Top achievements
Rank 1
Veteran
Raef asked on 11 Jun 2020, 03:01 AM

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;

 

 

 

 

2 Answers, 1 is accepted

Sort by
0
Stefan
Telerik team
answered on 11 Jun 2020, 06:34 AM

Hello, Raef,

Thank you for the provided information.

This can be done by passing a function from the parent component down to the detail component that will update the parent.

I made an example showcasing this, that will update a value in the master Grid and re-render it when a button in the child Grid is clicked:

https://stackblitz.com/edit/react-rmf7et?file=app/main.jsx

I hope this is helpful.

Regards,
Stefan
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
0
Raef
Top achievements
Rank 1
Veteran
answered on 11 Jun 2020, 05:13 PM
Thank you Stefan, this resolve my probleme.
Tags
General Discussions
Asked by
Raef
Top achievements
Rank 1
Veteran
Answers by
Stefan
Telerik team
Raef
Top achievements
Rank 1
Veteran
Share this question
or