Search code examples
reactjsformsbootstrap-4react-hooksreact-modal

React Input Validation Not Working in Form


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;
        });
    }

Solution

  • 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>