0

I have a React form with dynamic input fields that a user can add and remove input fields. All inputs are required. If all input fields are filled and the form is submitted then i console.log() an array with the values, else empty input gets focused. The problem is that if i whitespace(backspace) inside input fields, the form can be submitted and i don't want this. How can i fix this? I tried to use the trim() method (const registriesIsValid = registryValues.every((registry)=>registry.name.trim() !== "" && registry.code.trim() !== "");) but im getting "typeError Cannot read properties of undefined (reading 'trim')".

typeError

Below my code without trim method.

Edit react dynamic form input fields

App.js

import React, { useState, useRef } from "react";
import Wrapper from "./Wrapper";
import "./styles.css";

export default function App() {
  const [registryValues, setRegistryValues] = useState([]);
  const [registryValuesTouched, setRegistryValuesTouched] = useState(false);
  const fieldRef = useRef();
  // const registriesRef = useRef();

  const registriesIsValid = registryValues.every(
    (registry) => registry.name !== "" && registry.code !== ""
  );
  const registriesInputIsInvalid = !registriesIsValid;

  let handleRegistryChange = (i, event) => {
    setRegistryValuesTouched(true);
    let newRegistryValues = [...registryValues];
    if (event.target.name === "name") {
      newRegistryValues[i].registry["name"] = event.target.value;
    }
    if (event.target.name === "code") {
      newRegistryValues[i].code = event.target.value;
    }
    // newRegistryValues[i][event.target.name] = event.target.value;
    setRegistryValues(newRegistryValues);
  };

  let addRegistryFields = (event) => {
    event.preventDefault();
    setRegistryValues([
      ...registryValues,
      { registry: { name: "" }, code: "" }
    ]);
  };

  let removeRegistryFields = (i, event) => {
    event.preventDefault();
    let newRegistryValues = [...registryValues];
    newRegistryValues.splice(i, 1);
    setRegistryValues(newRegistryValues);
  };

  const submitHandler = (event) => {
    event.preventDefault();
    setRegistryValuesTouched(true);

    for (let elem of fieldRef.current.elements) {
      if (elem.dataset.required && !elem.value) {
        elem.focus();
        return;
      }
    }

    console.log(registryValues);

    setRegistryValuesTouched(false);
  };

  return (
    <Wrapper>
      <form onSubmit={submitHandler} ref={fieldRef}>
        <fieldset>
          <legend>
            <h3 className="govgr-heading-m margin-top">Registries</h3>
          </legend>
          <div
            className={`${
              registriesInputIsInvalid ? "govgr-form-group__error" : ""
            }`}
          >
            {registriesInputIsInvalid && (
              <p className="govgr-error-message">
                <span className="govgr-visually-hidden">Λάθος:</span>All fields
                are required.
              </p>
            )}
            {registriesInputIsInvalid && (
              <p className="govgr-error-message">
                <span className="govgr-visually-hidden">Λάθος:</span>You must
                fill in registry Name and registry Code.
              </p>
            )}
            {registryValues.map((element, index) => (
              <div key={index} className="flex-row registry-margin-bottom">
                <div className="registry-flex-basis">
                  <div className="govgr-form-group">
                    <label
                      className="govgr-label govgr-!-font-weight-bold"
                      htmlFor="name"
                    >
                      Registry Name*
                    </label>
                    <input
                      className={`govgr-input govgr-!-width-three-quarter ${
                        element.registry["name"].trim() === ""
                          ? "govgr-error-input"
                          : ""
                      }`}
                      type="text"
                      name="name"
                      data-required="true"
                      value={element.registry["name"] || ""}
                      onChange={(e) => handleRegistryChange(index, e)}
                    />
                  </div>

                  <div className="govgr-form-group">
                    <label
                      className="govgr-label govgr-!-font-weight-bold"
                      htmlFor="code"
                    >
                      Registry Code*
                    </label>
                    <input
                      className={`govgr-input govgr-!-width-three-quarter ${
                        element.code.trim() === "" ? "govgr-error-input" : ""
                      }`}
                      type="text"
                      name="code"
                      data-required="true"
                      value={element.code || ""}
                      onChange={(e) => handleRegistryChange(index, e)}
                    />
                  </div>
                </div>
                <button
                  className="govgr-btn govgr-btn-warning remove-registry"
                  onClick={(e) => removeRegistryFields(index, e)}
                >
                  X
                </button>
              </div>
            ))}
          </div>
        </fieldset>
        <button
          className="govgr-btn govgr-btn-secondary button-registry"
          onClick={addRegistryFields}
        >
          Add Registry
        </button>

        <button
          className="govgr-btn govgr-btn-primary btn-center"
          type="submit"
        >
          Save
        </button>
      </form>
    </Wrapper>
  );
}

2 Answers 2

0

Seems pretty straightforward with simple check:

if (registry.name && registry.name.trim() !== "")
... 

Right hand of the && will only be evaluated if the left hand returns true.
This differs from || where left and right hand will always both be evaluated.

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

2 Comments

I fixed it. Actually, inside my submitHandler i forgot to check (if !registriesIsValid) {return;} . Also, my registry object has different structure. So i change validation to const registriesIsValid = registryValues.every((registry)=>registry.registry["name"].trim() !== "" && registry.code.trim() !== "");
All the same. It should just not be undefined or null (falsey). Good on you.
0

I fixed it. Actually, inside my submitHandler i forgot to check (if !registriesIsValid){...} .

Also, my registry object has different structure. So i change validation to:

const registriesIsValid = registryValues.every((registry)=>registry.registry["name"].trim() !== "" && registry.code.trim() !== "");

App.js

import React, { useState, useRef } from "react";
import Wrapper from "./Wrapper";
import "./styles.css";

export default function App() {
  const [registryValues, setRegistryValues] = useState([]);
  const [registryValuesTouched, setRegistryValuesTouched] = useState(false);
  const fieldRef = useRef();
  // const registriesRef = useRef();
   
  //1st change
  const registriesIsValid = registryValues.every(
    (registry) => registry.registry["name"].trim() !== "" && registry.code.trim() !== ""
  );
  const registriesInputIsInvalid = !registriesIsValid;

  let handleRegistryChange = (i, event) => {
    setRegistryValuesTouched(true);
    let newRegistryValues = [...registryValues];
    if (event.target.name === "name") {
      newRegistryValues[i].registry["name"] = event.target.value;
    }
    if (event.target.name === "code") {
      newRegistryValues[i].code = event.target.value;
    }
    // newRegistryValues[i][event.target.name] = event.target.value;
    setRegistryValues(newRegistryValues);
  };

  let addRegistryFields = (event) => {
    event.preventDefault();
    setRegistryValues([
      ...registryValues,
      { registry: { name: "" }, code: "" }
    ]);
  };

  let removeRegistryFields = (i, event) => {
    event.preventDefault();
    let newRegistryValues = [...registryValues];
    newRegistryValues.splice(i, 1);
    setRegistryValues(newRegistryValues);
  };

  const submitHandler = (event) => {
    event.preventDefault();
    setRegistryValuesTouched(true);


    //2nd change
    if (!registriesIsValid) {
      for (let elem of fieldRef.current.elements) {
        if (elem.dataset.required && !elem.value.trim()) {
          elem.focus();
          return;
        }
      }
      return;
    }
    
    console.log(registryValues);

    setRegistryValuesTouched(false);
  };

  return (
    <Wrapper>
      <form onSubmit={submitHandler} ref={fieldRef}>
        <fieldset>
          <legend>
            <h3 className="govgr-heading-m margin-top">Registries</h3>
          </legend>
          <div
            className={`${
              registriesInputIsInvalid ? "govgr-form-group__error" : ""
            }`}
          >
            {registriesInputIsInvalid && (
              <p className="govgr-error-message">
                <span className="govgr-visually-hidden">Λάθος:</span>All fields
                are required.
              </p>
            )}
            {registriesInputIsInvalid && (
              <p className="govgr-error-message">
                <span className="govgr-visually-hidden">Λάθος:</span>You must
                fill in registry Name and registry Code.
              </p>
            )}
            {registryValues.map((element, index) => (
              <div key={index} className="flex-row registry-margin-bottom">
                <div className="registry-flex-basis">
                  <div className="govgr-form-group">
                    <label
                      className="govgr-label govgr-!-font-weight-bold"
                      htmlFor="name"
                    >
                      Registry Name*
                    </label>
                    <input
                      className={`govgr-input govgr-!-width-three-quarter ${
                        element.registry["name"].trim() === ""
                          ? "govgr-error-input"
                          : ""
                      }`}
                      type="text"
                      name="name"
                      data-required="true"
                      value={element.registry["name"] || ""}
                      onChange={(e) => handleRegistryChange(index, e)}
                    />
                  </div>

                  <div className="govgr-form-group">
                    <label
                      className="govgr-label govgr-!-font-weight-bold"
                      htmlFor="code"
                    >
                      Registry Code*
                    </label>
                    <input
                      className={`govgr-input govgr-!-width-three-quarter ${
                        element.code.trim() === "" ? "govgr-error-input" : ""
                      }`}
                      type="text"
                      name="code"
                      data-required="true"
                      value={element.code || ""}
                      onChange={(e) => handleRegistryChange(index, e)}
                    />
                  </div>
                </div>
                <button
                  className="govgr-btn govgr-btn-warning remove-registry"
                  onClick={(e) => removeRegistryFields(index, e)}
                >
                  X
                </button>
              </div>
            ))}
          </div>
        </fieldset>
        <button
          className="govgr-btn govgr-btn-secondary button-registry"
          onClick={addRegistryFields}
        >
          Add Registry
        </button>

        <button
          className="govgr-btn govgr-btn-primary btn-center"
          type="submit"
        >
          Save
        </button>
      </form>
    </Wrapper>
  );
}

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.