tallcoder
tallcoder

Reputation: 317

How to Create HTML element with onClick in React?

I am Trying to make a Simple React BMI Calculator. I am trying to implement something like when ı click the submit button i want to create new html at the bottom like

your body index is {yourindex}

everytime that i click the submit button. You can think same like in todo apps.

How can ı do that ? Thanks

import React, { Component } from 'react'

class Areas extends Component {
  constructor(props) {
    super(props)
  
    this.state = {
       kg:0,
       height:0,
    }
    this.updateKG = this.updateKG.bind(this)
    this.updateHeight = this.updateHeight.bind(this)
    this.calculateBMI = this.calculateBMI.bind(this)
  }

  updateKG(event){
    this.setState({kg:event.target.value})
  }
  
  updateHeight(event){
    this.setState({height:event.target.value})
  }

  calculateBMI(){
    this.state.totals.push(parseInt(this.state.kg) + parseInt(this.state.height))
    console.log(this.state.totals)
  }
  
  
  render() {
    return (
      <div>

        <div className="jumbotron text-center mt-3">
          <div className="container">
            <h1 className="display-4">Calculate Your BMI</h1>
            <p className="lead">Calculate How fat you are ?</p>
          </div>
        </div>
        

        <div className="container mt-5">
          <div className="row">
            
            <div className="col text-center">
              <p>Your Kg</p>
              <input type="number" min="30" onChange={this.updateKG}/>
            </div>
            
            <div className="col text-center">
              <p>Your Height in cm</p>
              <input type="number" min="60" onChange={this.updateHeight}/>
            </div>
            
            <div className="col text-center">
              <p>Calculate Your BMI</p>
              <button className="btn btn-success" type="submit" onClick={this.calculateBMI}>Submit</button>
            </div>
            
          </div>
        </div>
      </div>
    )
  }
}

export default Areas

Upvotes: 0

Views: 1573

Answers (4)

filippofilip
filippofilip

Reputation: 1721

I've updated the snippet to show the calculations.

You were almost right but you were updating totals without this.setState function.

then in render method you can just iterate over totals and thats it.

You updated snippet is here.

class Areas extends Component<any, any> {
  state = {
    kg: 0,
    height: 0,
    totals: [],
  };

  updateKG = (event: any) => {
    this.setState({ kg: parseInt(event.target.value) });
  };

  updateHeight = (event: any) => {
    this.setState({ height: parseInt(event.target.value) });
  };

  calculateBMI = () => {
    // formula https://www.cdc.gov/nccdphp/dnpao/growthcharts/training/bmiage/page5_1.html

    const bmi = Math.round(
      (this.state.kg / this.state.height / this.state.height) * 10000,
    );

    console.log(bmi);

    this.setState({
      totals: [...this.state.totals, bmi],
    });
  };

  render() {
    return (
      <div>
        <div className="jumbotron text-center mt-3">
          <div className="container">
            <h1 className="display-4">Calculate Your BMI</h1>
            <p className="lead">Calculate How fat you are ?</p>
          </div>
        </div>

        <div className="container mt-5">
          <div className="row">
            <div className="col text-center">
              <p>Your Kg</p>
              <input type="number" min="30" onChange={this.updateKG} />
            </div>

            <div className="col text-center">
              <p>Your Height in cm</p>
              <input type="number" min="60" onChange={this.updateHeight} />
            </div>

            <div className="col text-center">
              <p>Calculate Your BMI</p>
              <button
                className="btn btn-success"
                type="submit"
                onClick={this.calculateBMI}
              >
                Submit
              </button>
            </div>
          </div>
          {this.state.totals.map((total: any, i: number) => {
            return <div key={i}>Calculated BMI: {total}</div>;
          })}
        </div>
      </div>
    );
  }
}

Upvotes: 1

Sanish Joseph
Sanish Joseph

Reputation: 2256

I can see Multiple problems with your code apart from your wrong BMI formula.

  1. When you set state, you are replacing old state with a new state. In your case since you are not considering old state while setState, you are losing either height or weight in this process.

You had to set state like this.setState({…this.state, height: e.target.value}) same for weight.

  1. Type of your button is Submit but there’s no form. You may remove that.

  2. You don’t have a property total or name it bmi in your state to hold the calculated bmi

  3. In your calculations you have a total assumed to be an array and used push array method. Push will mutate the data and we have avoid those methods which will mutate data in react. Use spread operator instead.

[…oldArray, newValue] this will produce new array. You are safe to use array methods like map, filter, and reduce etc as they all return a new array and not mutate the array.

  1. You are not displaying the calculated BMI anywhere.

Upvotes: 1

Jotha
Jotha

Reputation: 428

You can collect your totals in an array in your state and render elements based on that:

class Areas extends Component {
  constructor(props) {
    super(props)
  
    this.state = {
       kg:0,
       height:0,
       totals: []
    }
    this.updateKG = this.updateKG.bind(this)
    this.updateHeight = this.updateHeight.bind(this)
    this.calculateBMI = this.calculateBMI.bind(this)
  }

  updateKG(event){
    this.setState({kg:event.target.value})
  }
  
  updateHeight(event){
    this.setState({height:event.target.value})
  }

  calculateBMI(){
    // This just adds weight and height, but you can replace it with the actual calculation
    const total = parseInt(this.state.kg) + parseInt(this.state.height)
    this.setState({totals: this.state.totals.concat([total])});
    console.log(this.state.totals)
  }
  
  render() {
    return (
      <div>

        <div className="jumbotron text-center mt-3">
          <div className="container">
            <h1 className="display-4">Calculate Your BMI</h1>
            <p className="lead">Calculate How fat you are ?</p>
          </div>
        </div>
        

        <div className="container mt-5">
          <div className="row">
            
            <div className="col text-center">
              <p>Your Kg</p>
              <input type="number" min="30" onChange={this.updateKG}/>
            </div>
            
            <div className="col text-center">
              <p>Your Height in cm</p>
              <input type="number" min="60" onChange={this.updateHeight}/>
            </div>
            
            <div className="col text-center">
              <p>Calculate Your BMI</p>
              <button className="btn btn-success" type="submit" onClick={this.calculateBMI}>Submit</button>
            </div>

            {
                // Renders one element for each element in totals
                this.state.totals.map(total => <p>Your BMI is {total}</p>)
            }
            
          </div>
        </div>
      </div>
    )
  }
}

Upvotes: 1

Aiman_Irfan
Aiman_Irfan

Reputation: 375

From your code, you can add another component or code. Here is the steps on how you can make them.

  1. create a variable to show the result. First set it to "false" because we want to hide it.

  2. create another code to display user BMI result

  3. use that variable to show the result. For example, {showResult ? Something if true : something if false}. You have to use ternary operator to show or hide the user result

  4. Inside the calculated Bmi function, use "setState" to change the variable to "true"

That is all the step that you have to do. Hope this help

Upvotes: 1

Related Questions