This post summarizes a neat solution to a problem I ran into recently. Hope you find this useful!
Problem
&&
is a well-known, convenient operator for checking if all conditions are true. For example, imagine we're trying to perform validations on a input form before saving a user profile:
function saveProfileIfValid() {
if(firstNameIsValid('Jerry') && lastNameIsValid('Smith') && emailIsValid('js@email.com')) {
saveProfile(); // save only if all validations pass
}
}
The problem was, the code above would stop executing once it found a condition that returned false. I didn't want that, because my validations would add error messages to be displayed on the screen like below. How can we make all validations run regardless of the results?
let errorMessages = [];
function firstNameIsValid(firstName) {
if(firstName && firstName.length <= 10) {
return true;
} else {
// add error messages, if any
errorMessages.push('First name must be 1-10 characters');
return false;
}
}
Solution
The solution I found is below - it took some time and googling to get to it, so I'm leaving this for future reference.
function validInput() {
return [firstNameIsValid('Jerry'), lastNameIsValid('Smith'), emailIsValid('js@email.com')].every(Boolean);
}
function saveProfileIfValid() {
if(validInput()) {
saveProfile(); // save only if all validations pass
}
}
What's happening here?
-
.every
is a method that tests every element in an array against a condition and returns a boolean. It returnstrue
only if all elements pass the test. (Update: I had a misconception about.every
- please see the update below for details.)
function isTen(value) {
return value === 10;
}
const array = [10, 5, 10]
array.every(isTen) // returns false
-
Boolean
is a function that converts a value into a boolean, like the double bang (!!
). Examples below:
> Boolean(true)
true
> Boolean(false)
false
> Boolean('test')
true
> Boolean('')
false
As a result, all validations in the array get executed, and then finally a boolean value is returned based on whether all validations returned true or not.
UPDATE
According to a helpful comment I received, .every
actually exits once it finds a falsy value, just like &&
. The reason why the code above works is because all the items in the array get evaluated before .every
is executed. This can also be achieved by the code below, in a simpler manner. (Thank you Kevin!)
function saveProfileIfValid() {
const isValid = {
firstName: firstNameIsValid('Jerry'), // <- executes before if( ... )
lastName: lastNameIsValid('Smith'), // <- executes before if( ... )
email: emailIsValid('js@email.com') // <- executes before if( ... )
}
// all the validations have already happened
if(isValid.firstName && isValid.lastName && isValid.email) {
saveProfile(); // save only if all validations pass
}
}
Thank you for reading, and please let me know if you have a better solution!