DEV Community

Cover image for Form validation using javascript

Form validation using javascript

Adam Nagy on October 31, 2021

Working with forms is an every day task for almost every web developer. No matter what site you'll create it will use forms. Validating the form da...
Collapse
 
rkallan profile image
RRKallan • Edited

Your solution and example is very static and not dynamic.

to make it dynamic i would suggest to use after submitting the form
event.currentTarget.elements

with event.currentTarget.elements you will get all the formElements as object

and based on data attribute validation (for example) i would set the validation type. Maybe better is to create a js array of object for your form. On each item you can set the validation type. This is what you can use for validation for the field and form

If you want to have a example let me know

Collapse
 
javascriptacademy profile image
Adam Nagy

Thanks @rkallan for writing this comment!
Yes, the solution is very static, intentionally. This tutorial’s target audience are the beginners, and I think they get the hang of how it works more easil if the validation is static and not dynamic. Probably would worth to create and advanced form validation tutorial too πŸ€”

Collapse
 
rkallan profile image
RRKallan

I understand your explanation and I can agree about the static validation as a start

But to get the values of your form elements I would suggest to use event.currentTarget.elements

The 2 functions setError and setSucces I would created as 1 function

const setValidationClassName = (element, isValid = true, message = β€˜β€™) => {
    const inputControl = element.parentElement;
    const errorDisplay = inputControl.querySelector('.error');
    const validationClassNames = [β€˜error’, β€˜succes’];

    errorDisplay.innerText = message;
    inputControl.classList.replace(validationClassNames[!isValid], validationClassNames[isValid]);
}
Enter fullscreen mode Exit fullscreen mode

The if statements for validation I would created functions. And avoiding if elseif else statements
And return value would be a object

return {
    isValid: true,
    message: β€˜β€™,
};
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
anil027 profile image
Anil Kumar Venugopal

Hi RRKallan,Thanks for explaining this, can you provide real time working example on the same !!

Thread Thread
 
rkallan profile image
RRKallan

@anil027

<div class="container">
    <form id="form" action="/" method="post" novalidate>
        <h1>Registration</h1>
        <div class="input-control">
            <label for="username">Username</label>
            <input id="username" name="username" type="text" required data-validation="username" />
            <div class="error"></div>
        </div>
        <div class="input-control">
            <label for="email">Email</label>
            <input id="email" name="email" type="email" required data-validation="email" />
            <div class="error"></div>
        </div>
        <div class="input-control">
            <label for="password">Password</label>
            <input id="password" name="password" type="password" required data-validation="password" />
            <div class="error"></div>
        </div>
        <div class="input-control">
            <label for="password2">Password again</label>
            <input id="password2" name="password2" type="password" required data-validation="passwordConfirm" />
            <div class="error"></div>
        </div>
        <button type="submit">Sign Up</button>
    </form>
</div>
Enter fullscreen mode Exit fullscreen mode
const getType = (value) => {
    const type = Object.prototype.toString.call(value).slice(1, -1).split(" ");

    return type && type[1].toLowerCase();
};

const validations = {
    isEmpty: ({ value }) => {
        const valueIsType = getType(value);

        if (valueIsType === "string") return !value.trim().length;
        if (valueIsType === "array") return !value.length;
        if (valueIsType === "object") return !Object.keys(value).length;
        if (valueIsType === "number") return Number.isNaN(value);
        if (valueIsType === "boolean") return false;

        return true;
    },
    email: ({ value }) => {
        const isEmpty = validations.isEmpty({ value });
        const returnValue = {
            isValid: false,
            message: null,
        };

        if (isEmpty === true) {
            returnValue.message = "Email is required";
            return returnValue;
        }

        const pattern =
            /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        const isValid = pattern.test(String(value).toLowerCase());

        if (isValid === false) {
            returnValue.message = "Provide a valid email address";
        }
        returnValue.isValid = isValid;

        return returnValue;
    },
    username: ({ value }) => {
        const isEmpty = validations.isEmpty({ value });
        const returnValue = {
            isValid: !isEmpty,
            message: null,
        };

        if (isEmpty === true) {
            returnValue.message = "Username is required";
        }
        return returnValue;
    },
    password: ({ value }) => {
        const isEmpty = validations.isEmpty({ value });
        const returnValue = {
            isValid: false,
            message: null,
        };

        if (isEmpty === true) {
            returnValue.message = "Password is required";
            return returnValue;
        }

        if (value.length < 8) {
            returnValue.message = "Password must be at least 8 character.";
            return returnValue;
        }

        returnValue.isValid = true;
        return returnValue;
    },
    passwordConfirm: ({ value, valueToMatch }) => {
        const isEmpty = validations.isEmpty({ value });
        const valueToMatchIsEmpty = validations.isEmpty(valueToMatch);
        const returnValue = {
            isValid: false,
            message: null,
        };

        if (valueToMatchIsEmpty === true) {
            return returnValue;
        }

        if (isEmpty === true) {
            returnValue.message = "Please confirm your password";
            return returnValue;
        }

        if (value !== valueToMatch) {
            returnValue.message = "Passwords doesn't match";
            return returnValue;
        }

        returnValue.isValid = true;
        return returnValue;
    },
};

const setInputControlClassName = ({ element, isValid = true, message = null }) => {
    const inputControl = element.parentElement || {};
    inputControl.classList.toggle("error", !isValid);
    inputControl.classList.toggle("succes", isValid);

    const errorDisplay = inputControl.querySelector(".error") || {};
    errorDisplay.innerText = message || "";
};

const onSubmitForm = (event) => {
    event.preventDefault();

    const formObject = event.currentTarget;
    const formElements = formObject.elements;

    Array.prototype.slice.call(formElements).forEach((element) => {
        const { type, required, dataset } = element;

        if (["submit", "reset", "button"].includes(type) || !required) return;

        const validationType = dataset.validation;
        const value = element.value?.trim();
        const valueToMatch = validationType === "passwordConfirm" ? formElements.password?.value?.trim() : null;
        const { isValid, message } = validations[validationType]({ value, valueToMatch });

        setInputControlClassName({ element, isValid, message });
    });
};

const formElement = document.querySelector("#form");
formElement.addEventListener("submit", onSubmitForm);
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
anil027 profile image
Anil Kumar Venugopal

Thank you !!

Collapse
 
pauladeleke profile image
PaulAdeleke

Not sure we need such as your extravagant example. I think the OP was trying to teach it at its basic level.
I would rather applaud him for being basic and simple.

Collapse
 
rkallan profile image
RRKallan

The OP replayed and explained it why he used the static way. I can agree with the arguments

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ

You're probably better off using the in-built HTML field validation

Collapse
 
javascriptacademy profile image
Adam Nagy

That can work for simple use cases, but most of the time there are Specific validation conditions. For example the password should contain lowercase, uppercase letters numbers and should not contain special characters (like ?*%). This example can surely be done with built in HTML valodators, but the aim is to get an idea how you can do more advanced validations.

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ

Your password example can be done with built-in validation

Thread Thread
 
javascriptacademy profile image
Adam Nagy

Okay lets get into a specific use case I faced a few years earlier. On a registration site we had to validate if an email address is a real existing address. To do that we had to call an API to validate the email address. There’s no way to do that eith built in html.

Thread Thread
 
jonrandy profile image
Jon Randy πŸŽ–οΈ

All the in-built stuff can be called with JS. You just need to augment it a little for cases like this - not re-invent the wheel

Thread Thread
 
rkallan profile image
RRKallan

When a user use inspect element and change the pattern or and the type the build in validation would result in a false isValid

Thread Thread
 
jonrandy profile image
Jon Randy πŸŽ–οΈ • Edited

Similarly, any JS-only validation can be bypassed (breakpoints, changing values etc.)

Far too many sites these days forget this. I've lost count of the number of forms I've 'fooled' into letting me continue as all the validation is done client-side. I've even seen 'server-side' validation fail as the result of a server-side check whose result was being checked on the client-side - something like this:

const formIsValid = validateFormServerSide()

// make a breakpoint here, change formIsValid to true ...
// Voila! 'server-side' validation bypassed

if (formIsValid) {
  // Do stuff
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
rkallan profile image
RRKallan

True submitting a form needs also to be validate on server side.

Collapse
 
psndoc23 profile image
psnDoc23

Thanks, Adam. This is exactly what I was looking for. A simple JavaScript validation that teaches me the basics of how to do this in a static way with JS, not an elaborate program with all the bells and whistles. And thanks for pointing out the backend validation too, I may have let that slip by without thinking all the way through how people can evade the front end pretty easily.

Collapse
 
ashleyjsheridan profile image
Ashley Sheridan

Please don't ever just remove the focus styles from form elements like this:

.input-control input:focus {
    outline: 0;
}
Enter fullscreen mode Exit fullscreen mode

Some people rely on the visual indicator of focused elements, especially those who use a keyboard to navigate the form.

One thing I noticed in your HTML is that you're not using the native form element types where they exist. For example, the email field should be of type email. Not only does this present the user with an appropriate keyboard (device dependent) but you can hook into the default validation provided by the browser, and then remove the regular expression checking from the code.

In-fact, by using the HTML form validation attributes (type="", required, pattern, etc), you can make your Javascript validation far more generic. That way, you can target all input elements as you need, and the validation will still work across the entire form regardless of whatever form elements are added or removed in the future.

Collapse
 
vikasjk profile image
Vikas-jk

For simple checkbox validation
//checkbox validation starts here
if(document.SimpleForm.gender[0].checked==false && document.SimpleForm.gender[1].checked==false)
{
alert('Select your gender');
return false;
}

When HTML
<input type="checkbox" name="gender" value="Male"> Male <br/>
<input type="checkbox" name="gender" value="Female"> Female <br/>

Source: Form validation in javascript