Итого по столбцам в динамической таблице с использованием ReactJS

Моя проблема заключается в том, что когда я ввожу значения количества и цены для расчета итоговой суммы, она будет рассчитана, но когда я добавляю еще одну строку, итоговое значение рассчитывается на основе последних введенных значений количества и цены, как показано на рисунке ниже:

Итого по столбцам в динамической таблице с использованием ReactJS

Мой код ниже:

        class AjouterFacture extends Component {
          constructor(props) {
            super(props);
            this.state = {
              rowData: [],
              Produits: [],
              Quantite: "",
              Prix: ""
            };

            this.handleRowChange = this.handleRowChange.bind(this);
            this.handleRowDelete = this.handleRowDelete.bind(this);
            this.handleRowAdd = this.handleRowAdd.bind(this);
            this.getTotal = this.getTotal.bind(this);
            this.pushToCaller = this.pushToCaller.bind(this);
          }
  handleQuantiteChange(e) {
        this.setState({
          Quantite: e.target.value
        }, this.pushToCaller);
      }
      handleselectprdtChange(e) {
        this.setState({
          selectprdt: e.target.value
        }, this.pushToCaller);
      }
      handlePrixChange(e) {
        this.setState({
          Prix: e.target.value
        }, this.pushToCaller);
      }

          pushToCaller() {
            this.handleRowChange( {
              Quantite: parseInt(this.state.Quantite, 10),
              selectprdt: this.state.selectprdt,
              Prix: parseFloat(this.state.Prix),
            });
          }


          render() {

            return (<div className = "animated fadeIn">


         <h6> Veuillez ajouter au moins un produit : </h6>
                <Table  >
                <thead >
                          <tr>
                            <th>PRODUIT</th>
                            <th>QUANTITE</th>
                            <th>PRIX UNITAIRE</th>
                            <th>TOTAL</th>
                            <th></th>
                          </tr>
                          </thead>
                          <tbody>
                        {this.state.rowData.map((index) =>

                        <tr key = {index} id = {index} 
                        onChange = {this.handleRowChange}>


                 <td> <Input type = "select" name = "selectedcl" id = "selectcl"
                                  placeholder = "Veuillez sélectionner un produit"  value = {this.state.rowData.selectprdt}
                  onChange = {this.handleselectprdtChange} >
                   <option  key = {-1} hidden>Choisisr un produit</option>


                             {  this.state.Produits.map((pdt, i) => 
                             <option key = {i} >{pdt.Nomp}</option>
                             )} 


                              </Input>
                            </td>
                            <td><Input type = "number" 
                                  placeholder = "0" value = {this.state.rowData.Quantite} onChange = {this.handleQuantiteChange}/></td>
                            <td>
                                 <InputGroup ><Input type = "text" 
                                  value = {this.state.rowData.Prix} onChange = {this.handlePrixChange} />
                                  <InputGroupAddon addonType = "prepend">
                                      <InputGroupText><i ></i></InputGroupText>
                                    </InputGroupAddon>
                                         </InputGroup >
                                  </td>

                            <td >
                             <p >{this.state.Quantite * this.state.Prix}  </p>

                            </td>
                            <td>
                             <Button onClick = {this.handleRowDelete} active style = {center} >Effacer</Button>
              </td> </tr> )} 



                          <tr>

                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td><Button onClick = {this.handleRowAdd} >Ajouter une ligne</Button></td>
                  </tr>
                </tbody>

                <tfoot>
                  <tr>

                    <th></th>
                    <th >Grand total :</th>
                    <th>{this.getTotal()} </th>
                    <th></th>
                  </tr>
        </tfoot>

                </Table>


                </div>);
          }
          getTotal() {
            let grandTotal = 0;
            const rowTotals = this.state.rowData.map(row => this.state.Quantite *  this.state.Prix);
            if (rowTotals.length > 0) {
              grandTotal = rowTotals.reduce((acc, val) => acc + val);
            }
            return grandTotal;
          }
         handleRowChange(row, data) {
            const rowDataCopy = this.state.rowData.slice(0);
            rowDataCopy[row] = data;
            this.setState({
              rowData: rowDataCopy

            });
          }  
          handleRowDelete(row) {
            const rowDataCopy = this.state.rowData.slice(0);
            rowDataCopy.splice(row, 1);
            this.setState({
              rowData: rowDataCopy
            });
          }
         handleRowAdd() {
            const rowDataCopy = this.state.rowData.slice(0);
            rowDataCopy.push({selectprdt:'', Quantite : "", Prix :"" });
            this.setState({
              rowData: rowDataCopy
            });
          }

        }
        export default AjouterFacture;

Я хочу, чтобы итоговый столбец рассчитывался для каждой строки.

Как я могу это исправить?

🤔 А знаете ли вы, что...
JavaScript имеет множество библиотек и фреймворков, таких как jQuery, Angular, и Vue.js.


2 024
2

Ответы:

Попробуйте обновить код ниже.

class AjouterFacture extends Component {
          constructor(props) {
            super(props);
            this.state = {
              rowData: [],
              Produits: [],
              Quantite: "",
              Prix: "",
              id:0
            };

            this.handleRowChange = this.handleRowChange.bind(this);
            this.handleRowDelete = this.handleRowDelete.bind(this);
            this.handleRowAdd = this.handleRowAdd.bind(this);
            this.getTotal = this.getTotal.bind(this);
            this.pushToCaller = this.pushToCaller.bind(this);
          }
  handleQuantiteChange(e) {
        this.setState({
          Quantite: e.target.value
        }, this.pushToCaller);
      }
      handleselectprdtChange(e) {
        this.setState({
          selectprdt: e.target.value
        }, this.pushToCaller);
      }
      handlePrixChange(e) {
        this.setState({
          Prix: e.target.value
        }, this.pushToCaller);
      }

          pushToCaller() {
            this.handleRowChange(this.state.id, {
              Quantite: parseInt(this.state.Quantite, 10),
              selectprdt: this.state.selectprdt,
              Prix: parseFloat(this.state.Prix),
            });
          }


          render() {

            return (<div className = "animated fadeIn">


         <h6> Veuillez ajouter au moins un produit : </h6>
                <Table  >
                <thead >
                          <tr>
                            <th>PRODUIT</th>
                            <th>QUANTITE</th>
                            <th>PRIX UNITAIRE</th>
                            <th>TOTAL</th>
                            <th></th>
                          </tr>
                          </thead>
                          <tbody>
                        {this.state.rowData.map((index) =>

                        <tr key = {index} id = {index} 
                        onChange = {this.handleRowChange}>


                 <td> <Input type = "select" name = "selectedcl" id = "selectcl"
                                  placeholder = "Veuillez sélectionner un produit"  value = {this.state.rowData.selectprdt}
                  onChange = {this.handleselectprdtChange} >
                   <option  key = {-1} hidden>Choisisr un produit</option>


                             {  this.state.Produits.map((pdt, i) => 
                             <option key = {i} >{pdt.Nomp}</option>
                             )} 


                              </Input>
                            </td>
                            <td><Input type = "number" 
                                  placeholder = "0" value = {this.state.rowData.Quantite} onChange = {this.handleQuantiteChange}/></td>
                            <td>
                                 <InputGroup ><Input type = "text" 
                                  value = {this.state.rowData.Prix} onChange = {this.handlePrixChange} />
                                  <InputGroupAddon addonType = "prepend">
                                      <InputGroupText><i ></i></InputGroupText>
                                    </InputGroupAddon>
                                         </InputGroup >
                                  </td>

                            <td >
                             <p >{this.state.Quantite * this.state.Prix}  </p>

                            </td>
                            <td>
                             <Button onClick = {this.handleRowDelete} active style = {center} >Effacer</Button>
              </td> </tr> )} 



                          <tr>

                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td><Button onClick = {this.handleRowAdd} >Ajouter une ligne</Button></td>
                  </tr>
                </tbody>

                <tfoot>
                  <tr>

                    <th></th>
                    <th >Grand total :</th>
                    <th>{this.getTotal()} </th>
                    <th></th>
                  </tr>
        </tfoot>

                </Table>


                </div>);
          }
          getTotal() {
            let grandTotal = 0;
            const rowTotals = this.state.rowData.map(row => this.state.Quantite *  this.state.Prix);
            if (rowTotals.length > 0) {
              grandTotal = rowTotals.reduce((acc, val) => acc + val);
            }
            return grandTotal;
          }
         handleRowChange(row, data) {
            const rowDataCopy = this.state.rowData.slice(0);
            rowDataCopy[row] = data;
            this.setState({
              rowData: rowDataCopy

            });
          }  
          handleRowDelete(row) {
            const rowDataCopy = this.state.rowData.slice(0);
            rowDataCopy.splice(row, 1);
            this.setState({
              rowData: rowDataCopy
            });
          }
         handleRowAdd() {
            let id = this.state.id;
                id = id++;
            const rowDataCopy = this.state.rowData.slice(0);
            rowDataCopy.push({selectprdt:'', Quantite : "", Prix :"" });
            this.setState({
              rowData: rowDataCopy,
              id: id
            });
          }

        }
        export default AjouterFacture;

Решено

У вас есть несколько проблем с предоставленным вами кодом, я постараюсь перечислить большинство из них ниже:

  • Метод, который вы используете для обновления строк, не рекомендуется и, вероятно, приведет к множеству ошибок, вместо того, чтобы иметь временную цену / количество и обновлять данные позже, вы должны напрямую обновить их в состоянии.
  • Вы не связали несколько методов:

    this.handleQuantiteChange = this.handleQuantiteChange.bind(this); this.handlePrixChange = this.handlePrixChange.bind(this); this.handleselectprdtChange = this.handleselectprdtChange.bind(this);

  • В итоговом столбце вы должны вывести цену именно этой строки, а не временных переменных. Вы также должны указать цену / количество в конкретной строке.

  • Функция map вызывает с (data, index), а не только с (index).

  • Вам необходимо связать index с вызовом обработчика onChange, чтобы получить целевую строку. То же самое и с handleRowDelete.

Вот ваш исправленный код:

class AjouterFacture extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      rowData: [],
      Produits: [],
      id: 0
    };

    this.handleQuantiteChange = this.handleQuantiteChange.bind(this);
    this.handlePrixChange = this.handlePrixChange.bind(this);
    this.handleselectprdtChange = this.handleselectprdtChange.bind(this);
    this.handleRowDelete = this.handleRowDelete.bind(this);
    this.handleRowAdd = this.handleRowAdd.bind(this);
    this.getTotal = this.getTotal.bind(this);
  }
  handleQuantiteChange(index, value) {
    const rowDataCopy = this.state.rowData.slice(0);
    rowDataCopy[index] = Object.assign({}, rowDataCopy[index], {Quantite: parseInt(value, 10)});
    this.setState({
      rowData: rowDataCopy
    });
  }
  handleselectprdtChange(index, value) {
    const rowDataCopy = this.state.rowData.slice(0);
    rowDataCopy[index] = Object.assign({}, rowDataCopy[index], {selectprdt: value});
    this.setState({
      rowData: rowDataCopy
    });
  }
  handlePrixChange(index, value) {
    const rowDataCopy = this.state.rowData.slice(0);
    rowDataCopy[index] = Object.assign({}, rowDataCopy[index], {Prix: parseInt(value, 10)});
    this.setState({
      rowData: rowDataCopy
    });
  }


  render() {
    return (
      <div className = "animated fadeIn">
        <h6> Veuillez ajouter au moins un produit : </h6>
        <Table>
          <thead>
            <tr>
              <th>PRODUIT</th>
              <th>QUANTITE</th>
              <th>PRIX UNITAIRE</th>
              <th>TOTAL</th>
              <th />
            </tr>
          </thead>
          <tbody>
            {this.state.rowData.map((data, index) => (
              <tr key = {index} id = {index}>
                <td>
                  {" "}
                  <Input
                    type = "select"
                    name = "selectedcl"
                    id = "selectcl"
                    placeholder = "Veuillez sélectionner un produit"
                    value = {data.selectprdt}
                    onChange = {(e) => this.handleselectprdtChange(index, e.targe.value)}
                  >
                    <option key = {-1} hidden>
                      Choisisr un produit
                    </option>

                    {this.state.Produits.map((pdt, i) => (
                      <option key = {i}>{pdt.Nomp}</option>
                    ))}
                  </Input>
                </td>
                <td>
                  <Input
                    type = "number"
                    placeholder = "0"
                    value = {data.Quantite || 0}
                    onChange = {(e) => this.handleQuantiteChange(index, e.target.value)}
                  />
                </td>
                <td>
                  <InputGroup>
                    <Input
                      type = "text"
                      value = {data.Prix || 0}
                      onChange = {(e) => this.handlePrixChange(index, e.target.value)}
                    />
                    <InputGroupAddon addonType = "prepend">
                      <InputGroupText>
                        <i />
                      </InputGroupText>
                    </InputGroupAddon>
                  </InputGroup>
                </td>
                <td>
                  <p>{(data.Quantite || 0) * (data.Prix || 0)} </p>
                </td>
                <td>
                  <Button
                    onClick = {(e) => this.handleRowDelete(index)}
                    active
                    style = {"center"}
                  >
                    Effacer
                  </Button>
                </td>{" "}
              </tr>
            ))}

            <tr>
              <td />
              <td />
              <td />
              <td />
              <td>
                <Button onClick = {this.handleRowAdd} style = {center}>Ajouter une ligne</Button>
              </td>
            </tr>
          </tbody>

          <tfoot>
            <tr>
              <th />
              <th>Grand total :</th>
              <th>{this.getTotal()} </th>
              <th />
            </tr>
          </tfoot>
        </Table>
      </div>
    );
  }
  getTotal() {
    let grandTotal = 0;
    const rowTotals = this.state.rowData.map(
      row => (row.Quantite * row.Prix) || 0
    );
    if (rowTotals.length > 0) {
      grandTotal = rowTotals.reduce((acc, val) => acc + val);
    }
    return grandTotal;
  }

  handleRowDelete(row) {
    const rowDataCopy = this.state.rowData.slice(0);
    rowDataCopy.splice(row, 1);
    this.setState({
      rowData: rowDataCopy
    });
  }
  handleRowAdd() {
    let id = this.state.id;
        id = id++;
    const rowDataCopy = this.state.rowData.slice(0);
    rowDataCopy.push({
      selectprdt: "",
      Quantite: 0,
      Prix: 0
    });
    this.setState({
      rowData: rowDataCopy,
      id: id
    });
  }
}

export default AjouterFacture;