React Input Validation Not Working in Form

18.2k Views Asked by At

I have a component in React that has required in its fields. The idea is onClick will trigger a separate function that adds a soccer player to two different stores (similar to a TODO app). However, it appears that the validation does not work -name for example is a required string, but the form seems to add a player even if the string is empty. The same goes for the two number inputs.

I don't want to use onSubmit because this seems to refresh the page every time, which causes me to lose data.

I'm using the react-modal library for my forms. To start with here's a function that opens the modal:

    function renderAddButton() {
        return (
            <Row
                horizontal='center'
                vertical='center'
                onClick={openModal}
            >
                Add Player
            </Row>
        );
    }

Here's the modal and its hooks:

    const [playerName, setPlayerName] = useState('');
    const [totalGoals, setTotalGoals] = useState(0);
    const [goalPercentage, setGoalPercentage] = useState(0);

    function openModal() {
        setIsOpen(true);
    }
    function closeModal() {
        setIsOpen(false);
    }

                    <Modal
                        isOpen={modalIsOpen}
                        onRequestClose={closeModal}
                        style={modalStyles}
                        contentLabel='Player Form Modal'
                    >
                        <h3>Create Player</h3>
                        <form>
                            <label>Name</label>
                            <input
                                type='string'
                                id='playerNameId'
                                name='playerName'
                                defaultValue=''
                                onChange={(e) => setPlayerName(e.target.value)}
                                required
                            />
                            <label>Total Goals</label>
                            <input
                                type='number'
                                id='totalGoalsId'
                                name='totalGoals'
                                defaultValue='0'
                                min='0'
                                onChange={(e) => setTotalGoals(e.target.value)}
                                required
                            />
                            <label>Goal Percentage</label>
                            <input
                                type='number'
                                id='goalPercentageId'
                                name='playerGoalPercentage'
                                defaultValue='0'
                                min='0'
                                step ='0.01'
                                max='1'
                                onChange={(e) => setGoalPercentage(e.target.value)}
                                required
                            />
                            <button onClick={(e) => onAddButtonClick(e)}>Submit</button>
                        </form>

                        <button onClick={closeModal}>close</button>
                    </Modal>

And now when this function is triggered, the validations don't seem to work. Empty playerId and totalGoals and goalPercentage seem to go through fine. How do I validate the inputs and stop this function from running if the inputs are empty?

    function onAddButtonClick(e) {
        e.preventDefault();

        setItems((prev) => {

            const newItems = [...prev];

            const uuid= uuidv4();

            newItems.push({
                name: playerName,
                playerId:uuid,
                teamId: currentTeam[0].teamId,
                totalGoals: totalGoals,
                goalPercentage: goalPercentage
            });

            playersStore.push({
                name: playerName,
                playerId:uuid,
                teamId: currentTeam[0].teamId,
                totalGoals: totalGoals,
                goalPercentage: goalPercentage
            });

            return newItems;
        });
    }
3

There are 3 best solutions below

0
On BEST ANSWER

The required attribute only works with default form actions. You'll need to do your own validation in the handler. You should also explicitly define the button type attribute as well since buttons by default are type="submit".

Create a validation function and pass your state values to it. Return true if input is valid, false otherwise.

const validateInput = ({ goalPercentage, playerName, totalGoals }) => {
  if (!playerName.trim()) {
    return false;
  }

  // other validations

  return true;
};

Check the input in onAddButtonClick and only update state if input is valid.

function onAddButtonClick(e) {
  e.preventDefault();

  const validInput = validateInput({ goalPercentage, playerName, totalGoals });

  if (!validInput) {
    return null;
  }

  setItems((prev) => {
    const newItems = [...prev];
    const uuid= uuidv4();

    newItems.push({
      name: playerName,
      playerId: uuid,
      teamId: currentTeam[0].teamId,
      totalGoals: totalGoals,
      goalPercentage: goalPercentage
    });

    playersStore.push({
      name: playerName,
      playerId: uuid,
      teamId: currentTeam[0].teamId,
      totalGoals: totalGoals,
      goalPercentage: goalPercentage
    });

    return newItems;
  });
}

Update the button to have an explicit type.

<button
  type="button"
  onClick={onAddButtonClick}
>
  Submit
</button>
0
On

you can do something like this

    function onAddButtonClick(e) {
        e.preventDefault();

     if(playerName.trim()===''){ //you can make more validations here
       return;
     } 
    //down here use the rest of logic
   }
0
On

yeah you can't use required from html, you must to handle it in your reactjs. for form select this is my code or example for you, this is simple case. choice status: employee or student (as value)

function handleSubmit(event) {
    event.preventDefault();
    if (!status) {
        return;
    }
    router.get(`/content/notes/${status}`);
}