'React how to disable submit button until form values are input

I'd like to keep the submit button in my form disabled until the values of the each input are at least one character, not including white space. I tried using trim() and it seems to work until I click submit.

Here is my Form component:

export function Form(props) {
  const { form, inputChange, postQuiz } = props;

  const onChange = () => {

    inputChange()
  }

  const onSubmit = evt => {
    evt.preventDefault()
    const question_text_input = document.getElementById("newQuestion");
    const question_text = question_text_input.value
    const true_answer_text_input = document.getElementById("newTrueAnswer");
    const true_answer_text = true_answer_text_input.value
    const false_answer_text_input = document.getElementById("newFalseAnswer");
    const false_answer_text = false_answer_text_input.value
    postQuiz({ question_text, true_answer_text, false_answer_text })
  }

  return (
    <form id="form" onSubmit={onSubmit}>
      <h2>Create New Quiz</h2>
      <input onChange={onChange} placeholder="Enter question" />
      <input onChange={onChange} placeholder="Enter true answer" />
      <input onChange={onChange} placeholder="Enter false answer" />
      <button 
      id="submitNewQuizBtn"
      disabled={
        form.newFalseAnswer.trim().length >= 1
        && form.newTrueAnswer.trim().length >= 1
        && form.newQuestion.trim().length >= 1
        ? ""
        : "disabled"
      }
      >
        Submit new quiz
      </button>
    </form>
  )
}

export default connect(st => st, actionCreators)(Form)

With the code above, the submit button stays disabled until I type at least one character in each input (doesn't count whitespace, like I wanted), but as soon as I click submit I get the error: Uncaught TypeError: Cannot read properties of undefined (reading 'trim').

I don't understand why that happens. Is using trim() on the form Object incorrect?



Solution 1:[1]

You can achieve that using two states in your component. One for input and another for the button.

const App = () => {
  const [input, setInput] = useState('') // For input
  const [isdisabled, setIsDisabled] = useState(false) // For button

  // when input is changing this function will get called
  const onChange = (e) => {
    setInput((prevState) => (e.target.value))
    if(e.target.value.trim().length < 1) {   // Checking the length of the input
      setIsDisabled(true)  // Disabling the button if length is < 1
    } else {
      setIsDisabled(false)
    }
  }

  const onSubmit = (e) => {
    e.preventDefault()
    // Code...
  }

  return (
    <div className="App">
     <form onSubmit={onSubmit}>
      <input type='text' placeholder='email' value={input} onChange={onChange} />
      <button id='button' type='submit' disabled={isdisabled}>Submit</button>
     </form>
    </div>
  );
}

If you have multiple inputs change the onChange function and input state accordingly.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dharmik Patel