skip to Main Content

I have a form. In the form I getting brandName, supplierName, and date of expiry from the user.
I am usinf TextField from mui library and submit button.
I want to disable submit button on empty form fields and enable it when user filled all the inputs
here is my code for declaring useStates

       const[brandName, setBrandName] = useState("");
       const[supplierName, setSupplierName] = useState("");
       const[expiryDate, setExpiryDate] = useState(null);
       const[brandNameError, setBrandNameError] = useState(false);
       const[supplierNameError, setSupplierNameError] = useState(false);
       const[expiryDateError, setExpiryDateError] = useState(false);

       const[submitButton, setSubmitButton] = useState(true);

and here is all function which i used to validate my inputs

       // checking brandName Error
        const brandNameValidateOnBlur = ()=>{
          if(brandName === ""){
            setBrandNameError(true);
          }
       }

       // checking supplier name error
       const supplierNameValidateOnBlur = ()=>{
        if(supplierName === ""){
            setSupplierNameError(true);
        }
       }
       // checking expiry date
       const expiryDateValidateOnBlur = ()=>{
        if(expiryDate === ""){
            setExpiryDateError(true);
        }
       }
 
        // now checking all inputs again if all inputs are good then
        // button should be enabled 

        const checkAllInputs = ()=>{
            if(brandName !== "" && supplierName !== "" && expiryDate !== ""){
                setSubmitButton(false);
            }else{
                setSubmitButton(true);
            }
        }

and here is the rest of code

       <TextField  fullWidth id="productName" label="Product Name" 
        value={brandName.toLowerCase()} variant="outlined" 
      onChange={(data)=>{setBrandName(data.target.value.toUpperCase());checkAllInputs()}}
      onBlur={brandNameValidateOnBlur}
      onFocus={()=>setBrandNameError(false)}
      error={brandNameError}
      helperText = {brandNameError ? "Enter Brand Name" : ""}
      />
      <TextField id="supplierName"  
      label="Supplier Name" 
      value={supplierName.toLowerCase()} variant="outlined"
      onBlur={supplierNameValidateOnBlur}
      onFocus={()=>setSupplierNameError(false)}
      error={supplierNameError}
      helperText={supplierNameError ? "Enter Supplier Name " : ""}
      onChange={(data)=>{setSupplierName(data.target.value.toUpperCase());checkAllInputs()}} />
      <LocalizationProvider dateAdapter={AdapterDayjs}>
      <DesktopDatePicker
          label="Date Expiry"
          inputFormat="MM/DD/YYYY"
          value={expiryDate}
          onBlur={expiryDateValidateOnBlur}
          onFocus={()=>setExpiryDateError(false)}
          error={expiryDateError}
          helperText={expiryDateError ? "Enter Expiry Date ": ""}
          onChange={(selectedDate)=>
          {setExpiryDate(selectedDate.format("MM/DD/YYYY"));checkAllInputs()}}
          renderInput={(params) => <TextField {...params} />}
        />
     </LocalizationProvider>
      <Button type='button' variant='contained' id="submitButton" disabled={submitButton}
      style={{backgroundColor:'orangered'}} onClick={addData}>Add Data</Button>

now problem is when i enter a single word my useState is updated but my checkAllInputs not working as i want to be like if i enter a word my checkAllInputs method runs before setting of state as i enter second entry then it works like I want to be so i did not know what i am doing wrong

I TRY useEffect hook like that

       useEffect(()=>{
        checkAllInputs();
       },[brandName, supplierName, expiryDate]);

its working fine as i accepted but I read that it should be a expensive to use useEffect

and an other approach which i use

         const checkAllInputsWithDom = ()=>{
         let brandNameEntry = document.getElementById("brandName").value;
         let supplierNameEntry = document.getElementById("supplierName").value;
         let expiryDateEntry = document.getElementById("expiryDate").value;
         if(brandNameEntry !=="" && supplierNameEntry !== ""  && expiryDateEntry !== ""){
            setSubmitButton(false);
         }else{
            setSubmitButton(true);
         }
      }

it is working out of box but I thing in react this is against react principles to direct manipulate
dome elements can I do it with out using useeffect hook like only with my metohd and one more thing
this did not set expiryDate error in date field

3

Answers


  1. Chosen as BEST ANSWER

    as suggested by Eduardo Motta de Moraes I used this for making my button enabled after all inputs validate

    const disabled= brandName.length === 0 || supplierName.length === 0 || expiryDate.length === 0;
    

    this solve my problem thanks for Eduardo Motta de Moraes for this


  2. As long as you’re keeping the input values in state, you don’t need another variable storing the button state as well. You can calculate it at render time. (Read more about avoiding redundant state here.)

    You could do something like this:

    const Component = () => {
      const[brandName, setBrandName] = useState("");
      const[supplierName, setSupplierName] = useState("");
      const[expiryDate, setExpiryDate] = useState("");
    
      const disabled = brandName.length === 0 && supplierName.length === 0 && expiryDate.length === 0
    
      return (
        <>
          <input value={brandName} onChange={(e) => setBrandName(e.target.value)}/>
          <input value={supplierName} onChange={(e) => setSupplierName(e.target.value)}/>
          <input value={expiryDate} onChange={(e) => setExpiryDate(e.target.value)}/>
          <button disabled={disabled}>Button</button>
        </>
      )
    }
    
    
    
    Login or Signup to reply.
  3. here is the link for codesandbox I have a suggestion for you to refactor this 6 use States with just one useState as an object having all the values like the following:

      const initialValues = {
      brandName: "",
      supplierName: "",
      expiryDate: "",
      brandNameError: "",
      supplierNameError: "",
      expiryDateError: ""
    };
    

    and then update it with a generic handleInputChange like below:

      const handleInputChange = (e) => {
        //const name = e.target.name
        //const value = e.target.value
        const { name, value } = e.target;
    
        setValues({
          ...values,
          [name]: value
        });
        let isEmpty = Object.values(values).some((x) => x === "");
        console.log(isEmpty);
        setIsDisabled(isEmpty);
      };
    

    FOR YOUR SOLUTION

    You will have to just check all the values and just create a boolean with isDisabled so when all of those values are empty then it will only set to false.

    I have created a code snippet for you, it needs some improvement but it will serve your purpose. Link already at the top and here as well

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search