0

I basically try to check if all input fields are valid by using the following code:

 addData (input){

   var isValid = false;    

   for (var i = 0, ii = input.length; i < ii; ++i) {          

      if ($('#' + input[i].id).hasClass('valid')) {
          isValid = true;              
      }
   }

   if (isValid) {
     //do stuff
   }
 }

In total the input.length is 3 and I want to check if all 3 input fields are valid. In my example, it just checks the last input element. In related posts, I couldn`t find a way to solve it with a for-loop. Can anybody help?

Thanks for all the helpful answers: Finally, I adjusted Máté Safranka's answer:

var isValid = input.toArray().every(element => $('#' + element.id).hasClass('valid'))

with .toArray() to convert jQuery object to an Array >> see here for more information. Defining true or false is not needed anylonger.

Nixen85
  • 1,253
  • 8
  • 24
  • 2
    If you already have the inputs in a variable, there's no need to re-find them using their ID (they may not have an id), eg: `if ($(input[i]).hasClass("valid")) { ` – freedomn-m Apr 04 '18 at 14:37
  • `var i = 0, ii = input.length; i < ii; ++i` Are you using `i` or `ii`? – Scott Marcus Apr 04 '18 at 14:37
  • 2
    Your code determines whether *any* input is valid; if at least one of them is, then `isValid` is set to `true`. – Pointy Apr 04 '18 at 14:37
  • 1
    @ScottMarcus look again, `i` is used for the loop, `ii` for the exit condition (it's an unconventional, but valid way to set the bounds) (unconventional as it some people think it's a mistake...) – freedomn-m Apr 04 '18 at 14:40
  • 1
    @freedomn-m That's why I asked. I didn't say it was a mistake, but IMHO it's an incredibly bad idea to use two variables so similar in their name. It's a bug waiting to happen. – Scott Marcus Apr 04 '18 at 14:52

5 Answers5

4

You never set isValid to false, so as long as at least one of the inputs is valid the result will be valid.

Better to swap the true/false and check for any invalid ones, eg:

addData (input){

 var isValid = true;    

 for (var i = 0, ii = input.length; i < ii; ++i) {          
   if (!$('#' + input[i].id).hasClass('valid')) {
      isValid = false;              
   }
 }

 if (isValid) {
  //do stuff
 }
}

Note: there are alternatives to using a loop, but this is to answer the explicit question of fixing the loop in OPs question.

freedomn-m
  • 27,664
  • 8
  • 35
  • 57
  • 1
    Since I asked for a solution with for-loop, this answer is correct. However, I attached my final solution to my question. Thank you! – Nixen85 Apr 04 '18 at 15:54
3

You got it wrong. You're assuming invalid until an element is valid. And you should assume valid until one element is invalid:

addData (input){
   var isValid = true;    

   for (var i = 0, ii = input.length; i < ii; ++i) {          

      if (!($('#' + input[i].id).hasClass('valid'))) {
          isValid = false;              
      }
   }

   if (isValid) {
     //do stuff
   }
}
Oscar Paz
  • 18,084
  • 3
  • 27
  • 42
3

If input is an array, you can use .every():

var isValid = input.every(it => $('#' + it.id).hasClass('valid'));

If input isn't an array, you can convert it to an array with Array.from().

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every

Note: As pointed out in the comments, this works in IE10 and later. This shouldn't be a problem most of the time (Windows 10 ships with IE11 and Edge, and theoretically every commercial end-user should have upgraded by now), but worth noting in case you have to support legacy platforms.

freedomn-m
  • 27,664
  • 8
  • 35
  • 57
Máté Safranka
  • 4,081
  • 1
  • 10
  • 22
  • Always good to see "new" features, but worth noting browser support incase it *is* an issue: https://caniuse.com/#search=every (show all) (IE10+) – freedomn-m Apr 04 '18 at 14:44
  • @freedomn-m That is why there are polyfills ;) Do not hold yourself back because of outdated browsers. – str Apr 04 '18 at 14:49
  • @str agreed, but I see so many questions here along the lines of "this code doesn't work `=>` ...") ... 500 comments later: "oh yeah, I'm using IE6"... :) – freedomn-m Apr 04 '18 at 15:12
  • I adjusted your code and now it´s working fine: I set `var isValid = true; ` and `if (!input.toArray().every(element => $('#' + element.id).hasClass('valid'))) { isValid = false; } ` – Nixen85 Apr 04 '18 at 15:41
  • 1
    That's not necessary though, `every()` returns `true` if all elements satisfy the criteria, and `false` if they don't, and that's literally what the value of `isValid` needs to be. So it should work just with `var isValid = input.toArray().every(element => $('#' + element.id).hasClass('valid'));` – Máté Safranka Apr 04 '18 at 15:45
3

As the others have said, you need to start off with isValid set to true and then as of the first invalid field, set it to false and break the loop.

But if input is really an array, I'd use input.every instead:

addData (input){
    if (input.every(function(element) { return $(element).hasClass('valid'); })) {
        // Do stuff
    }
}

Array#every calls the callback for the items in the array, returning true if the callback returns a truthy value for all of them, or returning false (and stopping immediately) if the callback ever returns a falsy value.

Or you could use jQuery's filter:

addData (input){
    if ($(input).filter(':not(.valid)').length === 0) {
        // Do stuff
    }
}

Array#every is more concise if you can use an ES2015+ arrow function:

addData (input){
    if (input.every(element => $(element).hasClass('valid'))) {
        // Do stuff
    }
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

anding true with isValid (as opposed to assigning true directly) will make it so the first false value will make the whole condition false. Just be sure to start with isValid as true before the loop.

isValid = true;

// inside the loop

isValid = isValid && true;
Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95