3

I have a variable 'fieldCount' that is equal to 5 (the number of fields I have). How can I write the following out without specifically stating each index:

if (
   fields[0].checkValidity() && fields[1].checkValidity() && fields[2].checkValidity()
   && fields[3].checkValidity() && fields[4].checkValidity()
) {
    fieldsPass = true;
}
ErikE
  • 48,881
  • 23
  • 151
  • 196
JordanBarber
  • 2,041
  • 5
  • 34
  • 62
  • Please see my answer, which you may have missed. I believe it may be of use to you (and note that I recommend the `every` or `some` methods as they express your intent clearer to the next developer. – ErikE Dec 02 '16 at 23:18

5 Answers5

4

You can use a loop, or some fairly standard built-in browser functions.

Loop

Here's how to do it with a loop. This should be the fastest code, but you probably don't need the fastest code unless you are checking a huge number of fields on a huge number of items. I recommend instead the "correct, clear, concise, fast" priorities, so think you should start with the built-in browser functions. But here it is for reference:

var fieldsPass = true;
var i, l = fields.length;
for (i = 0; i < l; i += 1) {
   if (fields[i].checkValidity()) continue;
   fieldsPass = false;
   break;
}

Note that declaring the i variable outside of the loop and capturing the field length outside the loop are optional.

The first I did because many people don't know about hoisting, and the fact that for (var i ... does NOT create a variable only available inside the for loop, it is the same as having declared var i at the top of the function, and this behavior can lead to bugs.

The second I did out of habit, though as I said you can put it inside the loop check. See this discussion. If you do use the loop method, you're probably looking for better performance, so might want to use the captured length way for the best possible performance. (And if it really matters that much, you can do the var i = fields.length; while (i--) { } method.)

Browser Function Array.Every

You can use Array.prototype.every() (from ECMAScript 2015 6th edition):

Mozilla Developer Network

The every() method tests whether all elements in the array pass the test implemented by the provided function.

fieldsPass = fields.every(function(field) {
   return field.checkValidity();
});

It returns truewhen the passed-in function, when run on every item in the array, returns true for all of them. If any one returns false, it stops and returns false. In some languages, they call the same concept all, if you're familiar with that.

Alternately, it might be better to declare your checkValidity function once, instead of putting it on every field. This may not be possible, depending on how you implemented it (perhaps it has access to private variables?). Notice that the first argument of the callback function you provide (see the documentation in the links above) is the currentValue of the iteration, the field you want to check. If your function thus looks like this, it will work:

function checkValidity(field) { /* check validity */ }

fieldsPass = fields.every(checkValidity);

Browser Function Array.Some

You can use also Array.prototype.some() (from ECMAScript 2015 6th edition):

Mozilla Developer Network

The some() method tests whether some element in the array passes the test implemented by the provided function.

fieldsPass = !fields.some(function(field) {
   return !field.checkValidity();
});

Notice that it is basically just the inverse of every, as "ALL VALID" is the same as "NOT (ANY INVALID)". It just means that it checks for any one item in the array that passes the function, and if so, returns true. In some languages, they call the same concept any, if you're familiar with that.

General Browser Compatibility Notes

Note that for these two functions, browser compatibility is pretty good. If you don't care about IE below version 9 then you're pretty much safe. If you do, then you would want to use a polyfill, which is available on the above-linked MDN pages. You would include that code in the global scope of your javascript file, and then would be able to use it as normally in IE 8 and below. (I'm talking about the code block starting like this:)

if (!Array.prototype.every) {
   Array.prototype.every = function(callbackfn, thisArg) {
   ...
}
Community
  • 1
  • 1
ErikE
  • 48,881
  • 23
  • 151
  • 196
3

You have an array of fields, and you want to iterate them, and invoke a validity check method on each of them. Only if all of them pass, the flag fieldsPass would be true.

This is exactly the behavior of Array#every. According to MDN:

The every() method tests whether all elements in the array pass the test implemented by the provided function.


Use Array.every to invoke checkValidity() on each field. If all fields are valid, the result would be true. If one field fails checkValidity(), the loop would return false immediately, without checking the other fields.

var fieldPass = fields.every(function(field) {
  return field.checkValidity();
})
ErikE
  • 48,881
  • 23
  • 151
  • 196
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • Thanks for the link. Still, how about a word on which browsers/versions it's available in, and the MDN polyfill for those browsers that don't have it? – ErikE Dec 02 '16 at 21:48
  • 2
    @ErikE Seems excessive, no? Almost every browser under the sun has `every` and if you find yourself needing a polyfill, it's easy to search for one or write one yourself. – Mike Cluck Dec 02 '16 at 21:49
2

Like you said, use a loop.

var fieldsPass = true;
for (var i = 0; i < fields.length; i++) {
  // Exit early if one of them fails
  if (!fields[i].checkValidity()) {
    fieldsPass = false;
    break;
  }
}
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91
1

You can use the .some() method and reverse the logic to tell if all passed like so:

var allPassed = !fields.some(function (field) {
  return !field.checkValidity();
});
mhodges
  • 10,938
  • 2
  • 28
  • 46
  • 2
    Browser compatibility table and polyfill are on the MDN link. Should I quote the ECMAScript specification as well? – mhodges Dec 02 '16 at 21:50
  • 1
    @ErikE A 25k user trolling posts with < 50 views is hardly entertaining. – mhodges Dec 02 '16 at 22:06
  • 1
    @ErikE Agitating and nit-picking just for the sake of agitation and nit-picking and then making fun of people because they defend themselves is basically the definition of trolling... – mhodges Dec 02 '16 at 22:07
  • I wasn't agitating, nor was I nit-picking. That's the thing that's funny. I was trying to help you make a better answer. – ErikE Dec 02 '16 at 22:08
  • Actually, I would love to see a quote from the ECMAScript 2015 Language Specification @mhodges. I think that would definitely amplify the usefulness of this answer, depending on the pertinence of the quote of course. –  Dec 02 '16 at 22:11
1

You can do it like this:

fieldsPass = true;
for (i = 0; i < fieldCount; i++)
{
     if(!fields[i].checkValidity())
     {
          fieldsPass = false;
          break;
     }
}
Boby
  • 856
  • 7
  • 9
  • Yeah you're right, a break; after fieldsPass = false; should do the job. – Boby Dec 02 '16 at 21:49
  • Well JordanBarber said he had a 'fieldCount' variable somewhere in the code(probably hard-coded) so I thought to use that instead of a length computation. – Boby Dec 02 '16 at 21:54
  • True! I missed that. Removing comment. – ErikE Dec 02 '16 at 22:23