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

3 posts, 0 answers
  1. Raef
    Raef avatar
    6 posts
    Member since:
    May 2020

    Posted 10 Jun 2020 Link to this post

    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. Stefan
    Admin
    Stefan avatar
    3034 posts

    Posted 11 Jun 2020 Link to this post

    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.
  3. Raef
    Raef avatar
    6 posts
    Member since:
    May 2020

    Posted 11 Jun 2020 in reply to Stefan Link to this post

    Thank you Stefan, this resolve my probleme.
Back to Top