1

I have a form with 3 number fields. The user can enter a quantity and unit price. Which will then show the total price in the last field as a disabled field.

My current code sets the value correctly in the Total Price input field, however it fails to set the state.

So for example if the user inputs Quantity equal to 4 and UnitPrice to 25. this.state.TotalPrice should be 100

handleChangeQuantity(event) {
    const { value } = event.target;
    this.setState({ Quantity: value }); 
}   

handleChangeUnitPrice(event) {
    const { value } = event.target;
    this.setState({ UnitPrice: value }); 
}

handleChangeTotalPrice(event) {
    const { TotalPrice } = event.target.value;
    this.setState({ 
        TotalPrice: this.state.Quantity * this.state.UnitPrice
    }); 
}   


<div>
    <label>
        Quantity
    </label>
    <input
        value={this.state.Quantity}
        onChange={this.handleChangeQuantity}
        type="number"
        className="phone validate"
        name="Quantity #1"
        maxLength={9}
        pattern='[0-9]{0,5}'
    />
</div>

<div>
    <label>
        Unit Price
    </label>
    <input
        value={this.state.UnitPrice}
        onChange={this.handleChangeUnitPrice}
        type="number"
        className="phone validate"
        name="Unit Price #1"
        maxLength={15}
        pattern='[0-9]{0,5}'
    />
</div>

<div>
    <label>
        Total Price
    </label>
    <input
        value={this.state.Quantity * this.state.UnitPrice}
        onChange={this.handleChangeExtendedPrice}
        type="number"
        className="phone validate"
        name="Estimated Extended Price #1"
        disabled
    />
</div>
hisusu32
  • 437
  • 7
  • 22
  • Check this that triggers ```handleChangeTotalPrice``` function on change of quantity and unit price.. https://codesandbox.io/s/react-typescript-starter-41ef3 – Maniraj Murugan Apr 22 '20 at 02:55
  • @ManirajMurugan it does not. When I change the quantity or unit price the `handleChangeTotalPrice` doesn't trigger – hisusu32 Apr 22 '20 at 03:44
  • It won't trigger unless you call that function.. No where you are calling ```handleChangeTotalPrice``` , then how will that function run?? Fork the above codesandbox and include your exact issue and explain in detail about the need.. Look at the console of the above sandbox provided while changing the value in quantity and price.. The ```TotalPrice``` value in state will be logged.. – Maniraj Murugan Apr 22 '20 at 04:00
  • @ManirajMurugan I'm having trouble with creating a sandbox. My question to you is using a `handleChangeTotalPrice` necessary? All I want to do is when the user inputs a quantity and unit price to set the state of the total price. So is there a better approach to save this? – hisusu32 Apr 22 '20 at 04:57
  • As you could see in the example provided, whenever there is a change in quantity and price , you can call ```handleChangeTotalPrice``` which will do the calculation and set the state value to ```TotalPrice``` as like you have, ```this.setState({ TotalPrice: this.state.Quantity * this.state.UnitPrice, })``` .. So in the input you just set the value like, ``` – Maniraj Murugan Apr 22 '20 at 05:08
  • Again please look into https://codesandbox.io/s/react-typescript-starter-2iob3 for better understanding.. I strongly believe this is what you want.. – Maniraj Murugan Apr 22 '20 at 05:09
  • @ManirajMurugan this worked!! If you would like to post this as an answer I can thumb it up as an answer. – hisusu32 Apr 22 '20 at 15:11
  • 1
    I have posted as an answer.. Glad to help you.. – Maniraj Murugan Apr 22 '20 at 15:18

2 Answers2

1

For starters I would put the jsx into a render method:

render() {
  const { Quantity, UnitPrice } = this.state;
  return (
  <>
    <div>
      <label>
        Quantity
      </label>
      <input
        value={Quantity}
        onChange={this.handleChangeQuantity}
        type="number"
        className="phone validate"
        name="Quantity #1"
        maxLength={9}
        pattern='[0-9]{0,5}'
      />
    </div>

    <div>
      <label>
        Unit Price
      </label>
      <input
        value={UnitPrice}
        onChange={this.handleChangeUnitPrice}
        type="number"
        className="phone validate"
        name="Unit Price #1"
        maxLength={15}
        pattern='[0-9]{0,5}'
      />
    </div>

    <div>
      <label>
        Total Price
      </label>
      <input
        value={Quantity * UnitPrice}
        onChange={this.handleChangeExtendedPrice}
        type="number"
        className="phone validate"
        name="Estimated Extended Price #1"
        disabled
      />
    </div>
  </>
  );
}

This should help with solving your problem: React setState not updating state

Here is a code pen link to a working version of your code. I took out the classNames and other things. Feel free to play around with it. https://codepen.io/maksimmamrikov/pen/jObVKbZ?editors=1010

eagercoder
  • 526
  • 1
  • 10
  • 23
  • thank you for this! It looks like in my case `handleChangeTotalPrice(event)` never gets triggered. And i get an error saying `const { ExtendedPrice }` is never read. – hisusu32 Apr 21 '20 at 22:31
  • try this inside of your input : `onChange={(e) => this.handleChangeUnitPrice(e)}`. that should trigger it – eagercoder Apr 22 '20 at 00:24
  • weird... I still can't get that function to trigger. In my render when I do `{this.state.this.state.TotalPrice}` it changes the price as I adjust the other fields. Just won't trigger the handler to set the state. – hisusu32 Apr 22 '20 at 00:35
  • I added a code pen link to my answer. I works + updates the total price when you adjust the qty or unit price. If this solves your issue an upvote and check would be appreciated. thanks! – eagercoder Apr 22 '20 at 02:22
  • Thank you! can you double check the link you sent? Looks like it's an empty code pen. – hisusu32 Apr 22 '20 at 02:31
  • @eagercoder, There is a possibility to enter text in the second input box which results in ```NaN``` in final input box.. – Maniraj Murugan Apr 22 '20 at 02:36
  • @eagercoder so that is what I currently have. But even in your example `TotalPrice` never gets set. So if I were to `console.log('"test")` or `console.log(this.state.TotalPrice)` it never triggers. I don't know why. – hisusu32 Apr 22 '20 at 02:40
  • @eagercoder, You don't need to check OP already provides that as ```type="number"``` and you missed to add it.. Also he mentioned the tag as typescript as well which also needs to be considered.. – Maniraj Murugan Apr 22 '20 at 02:43
  • @hisusu32 it has to do with the `handleChangeTotalPrice` method. https://codepen.io/maksimmamrikov/pen/jObVKbZ?editors=1010 looks like totalPrice is being logged with state in the above version – eagercoder Apr 22 '20 at 02:48
  • @eagercoder Yea.. I'm not sure why it's still not triggering. I added a console.log inside the handle and when I change the quantity or unit price it doesn't trigger. The value works but the handle doesn't – hisusu32 Apr 22 '20 at 03:47
1

In the last input field totalPrice , you could set the value as,

value={this.state.TotalPrice}

So you can set the state value in,

handleChangeTotalPrice = () => {
    this.setState({
      TotalPrice: this.state.Quantity * this.state.UnitPrice,
    })
    console.log(this.state.TotalPrice)
  }

So you can call the handleChangeTotalPrice function whenever there is a change in quantity and price..

The state value of TotalPrice would gets updated accordingly.

You could change your code like the following,

import React from 'react'

export class App extends React.Component {
  state = {
    Quantity: 0,
    UnitPrice: 0,
    TotalPrice: 0,
  }

  handleChangeQuantity = async (event: any) => {
    const { value } = event.target
    await this.setState({ Quantity: value })
    this.handleChangeTotalPrice()
  }

  handleChangeUnitPrice = async (event: any) => {
    const { value } = event.target
    await this.setState({ UnitPrice: value })
    this.handleChangeTotalPrice()
  }

  handleChangeTotalPrice = () => {
    this.setState({
      TotalPrice: this.state.Quantity * this.state.UnitPrice,
    })
    console.log(this.state.TotalPrice)
  }

  render() {
    return (
      <div>
        <div>
          <label>Quantity</label>
          <input
            value={this.state.Quantity}
            onChange={this.handleChangeQuantity}
            type="number"
            className="phone validate"
            name="Quantity #1"
            maxLength={9}
            pattern="[0-9]{0,5}"
          />
        </div>

        <div>
          <label>Unit Price</label>
          <input
            value={this.state.UnitPrice}
            onChange={this.handleChangeUnitPrice}
            type="number"
            className="phone validate"
            name="Unit Price #1"
            maxLength={15}
            pattern="[0-9]{0,5}"
          />
        </div>

        <div>
          <label>Total Price</label>
          <input
            value={this.state.TotalPrice}
            type="number"
            className="phone validate"
            name="Estimated Extended Price #1"
            disabled
          />
        </div>
      </div>
    )
  }
}

Working Sandbox

Maniraj Murugan
  • 8,868
  • 20
  • 67
  • 116