Home > Software design >  Pass error variable as inner html of element
Pass error variable as inner html of element

Time:10-16

I have some front-end validation for formatting some inputs on a form. Currently my errors message print to the console. I would like it so that these error message became the innerHTML of a heading in the component.

I have already tried assigning the innerHTML with document.getElementByID but it hasnt worked. Ive additionally tried defining the error variable outside of scope or adding it between the h2 tags as {error}

I would like any suggestions to make these error messages display as text on the front-end rather than being printed to console as they are now. The blank h2 element is the element im trying to target the error text towards.

import React, {useState} from 'react';
import {useNavigate} from 'react-router-dom';
import axios from 'axios';
import Helmet from 'react-helmet';
import Button from '@mui/material/Button';

export default function Register() {
    const navigate = useNavigate();
    const [firstName, setFirstName] = useState('');
    const [lastName, setLastName] = useState('');
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    const [confirmPassword, setConfirmPassword] = useState('');

    const inputs = [
        {
            placeholder: 'First name',
            setState: setFirstName
        },
        {
            placeholder: 'Last name',
            setState: setLastName
        },
        {
            placeholder: 'Email',
            setState: setEmail
        },
        {
            placeholder: 'Enter a password',
            setState: setPassword,
        },

        {
            placeholder: 'Confirm password',
            setState: setConfirmPassword,
        },
    ]

    //Insert into database api request
    const insertRow = () => {
        axios.post('/users/insert', {
            firstName: firstName,
            lastName: lastName,
            email: email,
            password: password,
        })
    };

    //#region Validation
        const atSymbol = '@';

        //Checks for numbers in string
        function containsNumber(str) {
            return /[0-9]/.test(str);
        }

        //Checks for capital in string
        function containsCapital(str) {
            return /[A-Z]/.test(str);
        }

        const submitHandler = (e) => {
            e.preventDefault(); //Prevents page refresh

            let error = ''

            //If no @ symobol in email
            if (!email.includes(atSymbol)) {
                error = 'Please enter a valid email';
                console.log(error);    
                return;
            }

            //If password doesn't contain a capital
            if (!containsCapital(password)) {
                error = 'Password must contain at least one uppercase letter';
                console.log(error);    
                return;
            }
          
            //If password doesn't contain a number
            if (!containsNumber(password)) {
                error = 'Password must contain at least one number';
                console.log(error);    
                return;

            }
          
            //If password is less than 8 characters
            if (password.length < 8) {
                error = 'Password must be at least 8 characters long';
                console.log(error);    
                return;
            }
          
            //If passwords don't match
            if (confirmPassword !== password) {
                error = 'Passwords do not match';
                console.log(error);    
                return;
            }

            //If all validation passes
            insertRow();
            navigate('/login');
        }
    //#endregion

    return (
        <>
            <Helmet>
                <title>Title | Register</title>
            </Helmet>

            <div className="pt-36 sm:pt-44 pb-20 md:pb-48 max-w-[1200px] mx-5 lg:mx-auto space-y-5">
                <div className="bg-red-300 max-w-[500px] p-1 mx-auto">
                    <h2 className="text-lg text-red-900 font-semibold"></h2>
                </div>

                <h1 className="text-2xl font-semibold text-center">Register</h1>
                <form onSubmit={submitHandler} className="flex flex-col space-y-5 max-w-[500px] mx-auto">
                    {inputs.map((items, index) => (
                        <input 
                            key={index}
                            type="text" 
                            className="border-2 border-black p-1"
                            placeholder={`${items.placeholder} *`} 
                            required 
                            onChange={(e) => {
                                items.setState(e.target.value);
                            }}
                        />
                    ))}

                    <Button
                        type="submit"
                        sx={{
                                border: '2px solid #000000',
                                color: '#000000',
                                marginLeft: 'auto',
                                marginRight: 'auto',

                                ':hover': {
                                    bgcolor: '#ffffff',
                                    color: '#000000',
                                },
                            }}
                    >
                    Submit
                    </Button>
                </form>
            </div>
        </>
    )
}

CodePudding user response:

You cannot do directly {error} as error is not defined as a state property in the component.

You have to declare it

const [error, setError] = useState('');

and whenever you set error you have to use setError

if (!email.includes(atSymbol)) {
    setError('Please enter a valid email');
    console.log(error);    
    return;
}

then in JSX you can use

{error.length>0 && <p>{error}</p>}

although it will be a common error for all the inputs

CodePudding user response:

To keep track of the errors for every field you could take this approach.

An object for all the errors with the field name as object key. Update the state with the new error. Now this will not keep track of multiple errors for every field but will eventually pass all of them. Before insertRow check if there are any errors, if any return.

const [errors, setErrors] = useState({ email: "", password: "" });

const inputs = [
  {
    email: 'email', // key to get value from errors
    placeholder: 'Email',
    setState: setEmail
  },
  ...
]

const submitHandler = (e) => {
  e.preventDefault(); //Prevents page refresh

  setErrors({ email: "", password: "" }); // reset the errors on every submit

  //If no @ symobol in email
  if (!email.includes(atSymbol)) {
    setErrors((prevError) => ({
      ...prevError,
      email: "Please enter a valid email",
    }));
    // no return needed
  }

  // ... at the end before navigating check if there are errors

  if (errors.email || errors.password) return;

  //If all validation passes
  insertRow();
  navigate('/login');
};

The extra name prop comes into play when we want to display the errors. After every input we check if there is an error for that field and display it if any.

return (
  ...

  {inputs.map((items, index) => (
    <>
      <input
        key={index}
        type="text"
        className="border-2 border-black p-1"
        placeholder={`${items.placeholder} *`}
        required
        onChange={(e) => {
          items.setState(e.target.value);
        }}
      />
      { errors[items.name] && <div>{errors[items.name]}</div>}
    </>
  ))}

  ...
);

CodePudding user response:

You cannot do directly {error} as error is not defined as a state property in the component.

You have to declare it

const [error, setError] = useState('');

and whenever you set error you have to use setError

if (!email.includes(atSymbol)) {
    setError('Please enter a valid email');
    console.log(error);    
    return;
}

then in JSX you can use

{error.length>0 && <p>{error}</p>}

although it will be a common error for all the inputs


for the solution of @kaneki21 i prefer this solution for JSX

{error?.length>0? <p>{error}</p>:null}

in case if error is "undefined" or "null"

  • Related