3

I've created this method that gets the state of the calculator input and checks if its empty or not. I need help with two things:

  • What's the cleanest way to add here a validation to check if each input is also a number and outputs and error "Input must be a number"
  • Currently I have one error message that fires whether all the inputs are present or not, where what I want is for it to validate each input separately and fire an error under each one. How do I do it but still keep this function concise?

           constructor(props) {
            super(props);
            this.state = {
                price: 0,
                downP: 0,
                term: 0,
                interest: 0,
                error: ''
            };
        }
    
     handleValidation = () => {
                    const {
                        price,
                        downP,
                        loan,
                        interest,
                    } = this.state;
                    let error = '';
                    let formIsValid = true;
                        if(!price || 
                            !downP ||
                            !loan ||
                            !interest){
                            formIsValid = false;
                            error = "Input fields cannot be empty";
                        } 
    
           this.setState({error: error});
          return formIsValid;
        }
    

    And then this is the error message

         <span style={{color: "red"}}>{this.state.error}</span>
    
2

4 Answers 4

8

If you want to keep your error messages separate I would recommend to reorganize your state.

So scalable solution (you may add more controls by just adding them to state) may look like:

class NumberControlsWithErrorMessage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      inputs: [
        { name: 'price', value: 0, error: ''},
        { name: 'downP', value: 0, error: '' },
        { name: 'term', value: 0, error: '' },
        { name: 'interest', value: 0, error: '' }
      ]
    };
  }

  handleInputChange = (idx, event) => {
    const target = event.target;
    const name = target.name;
    let error = '';

    if (isNaN(target.value)) {
      error = `${name} field can only be number`
    }

    if (!target.value) {
      error = `${name} field cannot be empty`
    }

    this.state.inputs[idx] = {
      ...this.state.inputs[idx],
       value: target.value,
      error
    }

    this.setState({
      inputs: [...this.state.inputs]
    });
  }

  render() {
    return (
      <form>
        {this.state.inputs.map((input, idx) => (
          <div>
          <label htmlFor="">{input.name}</label>
          <input type="text" value={input.value} onChange={(e) => this.handleInputChange(idx, e)}/>
          {input.error && <span>{input.error}</span> }
          </div>
        ))}
      </form>
    );
  }
}

Working example

Also if you are building a complex form, you may want to try some React solution for forms, where all the mechanism for listening to events, state updates, validatoin are already handled for you. Like reactive-mobx-form

Sign up to request clarification or add additional context in comments.

Comments

4

A straightforward way of handling multiple objects needing validation is to store an errors object in your state that has a property for each input field. Then you conditionally render the error underneath each input field depending on whether or not it has an error. Here is a very basic example:

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      price: 0, downP: 0, term: 0, interest: 0,
      errors: { price: '', downP: '', term: '', interest: '' }
    };
  }

  handleValidation = () => {
    const { price, downP, loan, interest } = this.state;
    let errors = { price: '', downP: '', term: '', interest: '' };

    if (!price) {
     errors.price = 'Price is required';
    } else if (isNaN(price)) {
      errors.price = 'Price must be a number';
    }

    if (!downP) {
      errors.downP = 'Down Payment is required';
    }

    // Rest of validation conditions go here...

    this.setState({ errors });
  }

  render() {
    const { errors } = this.state;

    return (
      <form>
        <input name="price" value={this.state.price} onChange={this.handleChange} />
        {errors.price != '' && <span style={{color: "red"}}>{this.state.errors.price}</span>}
        <input name="downP" value={this.state.downP} onChange={this.handleChange} />
        {errors.downP != '' && <span style={{color: "red"}}>{this.state.errors.downP}</span>}

        {/** Rest of components go here */}
      </form>
    );
  }
}

You can choose whether or not to run validation once the form submits or on every keypress and that will affect how when those messages appear and disappear, but this should give you an idea on how you would manage error messages specific to each input field.

Comments

2

You can do this:

  handleValidation() {
      const { price, downP,loan, interest} = this.state;

      // only each block with generate error
      if (!price || isNaN(price)) {
        this.setState({ error: 'price is not valid' });
      } else if (!downP || isNaN(downP)) {
        this.setState({ error: 'downP is not valid' });
      } else {
        this.setState({error: ""})
        // submit code here
      }
  }

Note: you dont need to return anything. It will update the error state and only submit the form if it goes into no error (else{}) part

and for render() part add this:

{(this.state.error !== '')
      ? <span style={{color: "red"}}>{this.state.error}</span>
      : ''
}

If you want validation msg on each add errPrice, errDownP and so on to the state, and check for them in render like (this.state.errPrice!== '') {} and so on.

Comments

1

One solution assuming you want a one size fits all error message only checking if it was a number or not would be to put them into an array and set error if the input is not a number.

const inputs = [ price, downP, loan, interest ]

inputs.map(input => {
  if (!input || isNaN(input)){
    error = "Input must be a number"
    formIsValid = false
  }
}

this.setState({error}) 

Something like that maybe.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.