DEV Community

Risa Fujii
Risa Fujii

Posted on • Updated on

Evaluate all values in an array in Javascript

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

What's happening here?

  1. .every is a method that tests every element in an array against a condition and returns a boolean. It returns true 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
Enter fullscreen mode Exit fullscreen mode
  1. 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
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

Thank you for reading, and please let me know if you have a better solution!

References:

Top comments (12)

Collapse
 
wolverineks profile image
Kevin Sullivan

I'd avoid using Array.prototype.every in this way.
It too will exit as soon as an entry returns false.
MDN - array.prototype.every

It's not because of .every that all of the validations run.
It's because the array is created and all of its items are evaluated, before .every executes

You would get the same result with

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

Hope this helps

Collapse
 
vjoao profile image
Victor Nascimento

I thought the same! Good catch. All array methods that rely on the iteratee to return a boolean will stop execution as soon as possible.

Collapse
 
risafj profile image
Risa Fujii

I am still relatively new to Javascript so I appreciate this (I guess Stack Overflow doesn't always have the best solution haha). I will update my code. Thank you both!

Collapse
 
latsuj profile image
Latsuj

Actually, reading at your code. It seems the thing you care about is to show the different error messages.
I guess, it's for showing inside a form.

So the condition for me before saving would be to check if errorMessage is empty or not.

However, like this way of using "every".

Collapse
 
risafj profile image
Risa Fujii

Thanks for reading and for the comment!

Collapse
 
katnel20 profile image
Katie Nelson

Will your solution work if the person only has a first name like Cher or Madonna?

Collapse
 
risafj profile image
Risa Fujii • Edited

In that case, you could customize your lastNameIsValid to something like this, so it allows for blank last names :)

function lastNameIsValid(lastName) {
  if(!lastName || lastName.length <= 10) {
    return true;
  } else {
    errorMessages.push('Last name cannot be longer than 10 characters');
    return false;
  }
}

Results:

> lastNameIsValid('Smith')
true
> lastNameIsValid('')
true
> lastNameIsValid(null)
true
> lastNameIsValid('TooLongToPassValidation')
false
Collapse
 
mzahraei profile image
Ardalan

Good Tipps 👌🏻

Collapse
 
risafj profile image
Risa Fujii

Thank you!

Collapse
 
haycuoilennao19 profile image
Niemvuilaptrinh • Edited

Thanks for sharing.

Collapse
 
risafj profile image
Risa Fujii

Thanks for reading :)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.