Search code examples
javascriptarraysfor-loopcheckvalidity

Looping through array in if statement to check if all values pass


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

Solution

  • 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) {
       ...
    }