0

Is there any better way to write the below code. So I want that if any of the row has invalid fields, I want to immediately return the result as "false" i.e. I do not want to execute the code or check for any further rows in the loop.

anyRowInvalid: function() {
    var items = this.get('sectionInformation.items');
    var isValid = true;

    for (let i=0; i < items.length; i++) {
      var gridItemObj = {};
      Object.keys(items[i]).forEach(function(itemkey) {
          if (typeof items[i][itemkey] === 'object') {
              if ((items[i][itemkey].valid) && (items[i][itemkey].valid === false)) {
                isValid = false;
              }
          }
      });              
    }
    return isValid;
},
copenndthagen
  • 49,230
  • 102
  • 290
  • 442
  • 2
    Use `some()`instead – epascarello Jul 13 '20 at 13:59
  • 2
    Doesn't `if ((items[i][itemkey].valid) && (items[i][itemkey].valid === false))` always evaluate to `false`? You first check if `items[i][itemkey].valid` has a truthy value. Then you check if that same value is `false`. It can never be truthy and `false` at the same time. My guess is that you meant to use `if (("valid" in items[i][itemkey]) && (items[i][itemkey].valid === false))` – 3limin4t0r Jul 13 '20 at 14:36

2 Answers2

0

I commented a few ways to improve the code and how to return instantly when you found an invalid element.

anyRowInvalid: function() {
    const items = this.get("sectionInformation.items"); // make const, as it will not be changed

    for (const item of items) { // Prettier for loop
        for (const itemkey of Object.keys(item)) { // make it a normal loop, so you can return instantly out of it
            if (typeof item[itemkey] === "object") {
                if (item[itemkey].valid && item[itemkey].valid === false) {
                    return false; // Instantly return
                }
            }
        }
    }

    return true;
}
MauriceNino
  • 6,214
  • 1
  • 23
  • 60
  • Ok...So return false; would imply other iterations would not execute ? Oh, it seems to becase of the arrow function ? – copenndthagen Jul 13 '20 at 14:08
  • My mistake, changed the code. – MauriceNino Jul 13 '20 at 14:10
  • 1
    In most use cases `for (const key of Object.keys(obj))` can also be written as `for (const key in obj)`. The only difference being that [`for...in`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) also iterates over inherited enumerable properties. An example is `a = {foo: "bar"}` and `b = Object.create(a)`. Then `Object.keys(b)` will be an empty array while `for (const key in b)` will also iterate over the `bar` property. – 3limin4t0r Jul 13 '20 at 14:19
  • 1
    This still has the same flaw as the original. `items[i][itemkey].valid` cannot be simultaneously truthy **and** strictly equal to `false`. Returning false instead of setting the flag and continuing to loop is still a good optimization though. – Wyck Jul 13 '20 at 14:48
  • 1
    seems like some issue...i is not defined – copenndthagen Jul 13 '20 at 14:52
  • Youre right! fixed that. @testndtv – MauriceNino Jul 14 '20 at 15:46
0

You could simplify your loop by using the array method every.

anyRowInvalid: function() {
    var items = this.get('sectionInformation.items');

    return items.every(item => {
      return Object.values(item).every(value => { // valid if:
        return !value                             // is falsy
            || typeof value != "object"           // or is non-objects
            || !("valid" in value)                // or without "valid" property
            || value.valid;                       // or truthy "valid" property
      });
    });
},

every automatically short circuits when the first falsy value is hit. The example below stops iterating after nr is set to 4, since that is the first time nr < 4 evaluates to a falsy value.

const array = Array.from({length: 10}, (_, index) => index);

array.every(nr => {
  console.log(nr);
  return nr < 4;
});
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52