0

my example below works but it is not modular with a hard coded "switch" statement determining how many functions exist in my function array.

I have tried to figure out how to use forEach() and every() but I'm having troubles with passing parameters into the functions contained in the array. (At least that is my assumption at this point...

The following does not work?

_this.oData.forEach(function (oRow) {
    function foo(checksArray) {
        var meetsAll = fc.every(function (func,oRow) {
            return func(oRow);
        });
        console.log(meetsAll);
        if (meetsAll){
                _this.oFiltered.push(oRow);
        };
    };
});

Here is a complete working sample but not right because not modular.

_this = this;
// sample data
_this.oData = [
    { 'itemfk': 123, 'vdrfk': 24 },
    { 'itemfk': 13, 'vdrfk': 34 },
    { 'itemfk': 18, 'vdrfk': 77 },
    { 'itemfk': 13, 'vdrfk': 24 },
    { 'itemfk': 48, 'vdrfk': 34 }
];
_this.oItemsSelected = [
    { 'itemfk': 123 },
    { 'itemfk': 13 }
];
_this.oVendorsSelected = [
    { 'vdrfk': 234 },
    { 'vdrfk': 24 }
];


// called by cascading controls
this.filterConditions = function () {

    // build test conditions into array of functions
    var fc = [];
    // items condition
    if (_this.oItemsSelected.length > 0) {

        fc.push(
            function (oRow) {
                for (var nItem = 0; nItem < _this.oItemsSelected.length; nItem++) {
                    //console.log(_this.oItemsSelected[nItem].itemname +' row '+ oRow.itemname);
                    if (_this.oItemsSelected[nItem].itemfk === oRow.itemfk) {
                        return true;
                    }
                };
                return false;
            }
        );

    };
    // vendors condition
    if (_this.oVendorsSelected.length > 0) {

        fc.push(
            function (oRow) {
                for (var nVendor = 0; nVendor < _this.oVendorsSelected.length; nVendor++) {
                    if (_this.oVendorsSelected[nVendor].vdrfk === oRow.vdrfk) {
                        return true;
                    }
                };
                return false;
            }
        );
    };

    // loop data and apply conditions
    _this.oFiltered = [];
    _this.oData.forEach(function (oRow) {

        switch (fc.length) {
            case 1:
                if (fc[0](oRow)) {
                    _this.oFiltered.push(oRow);
                };
                break;
            case 2:
                if (fc[0](oRow) && fc[1](oRow)) {
                    _this.oFiltered.push(oRow);
                };
                break;
        };
    });

    // two oData rows (index zero and three) match conditions
    console.log(_this.oFiltered); 

};

Any help would be appreciated!

_this = this;
// sample data
_this.oData = [
    { 'itemfk': 123, 'vdrfk': 24 },
    { 'itemfk': 13, 'vdrfk': 34 },
    { 'itemfk': 18, 'vdrfk': 77 },
    { 'itemfk': 13, 'vdrfk': 24 },
    { 'itemfk': 48, 'vdrfk': 34 }
];
_this.oItemsSelected = [
    { 'itemfk': 123 },
    { 'itemfk': 13 }
];
_this.oVendorsSelected = [
    { 'vdrfk': 234 },
    { 'vdrfk': 24 }
];


// called by cascading controls
this.filterConditions = function () {

    // build test conditions into array of functions
    var fc = [];
    // items condition
    if (_this.oItemsSelected.length > 0) {

        fc.push(
            function (oRow) {
                for (var nItem = 0; nItem < _this.oItemsSelected.length; nItem++) {
                    //console.log(_this.oItemsSelected[nItem].itemname +' row '+ oRow.itemname);
                    if (_this.oItemsSelected[nItem].itemfk === oRow.itemfk) {
                        return true;
                    }
                };
                return false;
            }
        );

    };
    // vendors condition
    if (_this.oVendorsSelected.length > 0) {

        fc.push(
            function (oRow) {
                for (var nVendor = 0; nVendor < _this.oVendorsSelected.length; nVendor++) {
                    if (_this.oVendorsSelected[nVendor].vdrfk === oRow.vdrfk) {
                        return true;
                    }
                };
                return false;
            }
        );
    };

    // loop data and apply conditions
    _this.oFiltered = [];
    _this.oData.forEach(function (oRow) {

        switch (fc.length) {
            case 1:
                if (fc[0](oRow)) {
                    _this.oFiltered.push(oRow);
                };
                break;
            case 2:
                if (fc[0](oRow) && fc[1](oRow)) {
                    _this.oFiltered.push(oRow);
                };
                break;
        };
    });

    // two oData rows (index zero and three) match conditions
    console.log(_this.oFiltered); 

};
<html>
<head>
    <title></title>
 <meta charset="utf-8" />
    <script src="https://stacksnippets.net/js"></script>
</head>
<body onload="filterConditions()">

</body>
</html>
Harvey Mushman
  • 615
  • 1
  • 11
  • 23

2 Answers2

1

The way with Array.prototype.every() would be this:

_this.oFiltered = _this.oData.filter(function (oRow) {
  return fc.every(function(func) {
    return func(oRow);
  });
});

If you replace this:

// loop data and apply conditions
_this.oFiltered = [];
_this.oData.forEach(function (oRow) {

    switch (fc.length) {
        case 1:
            if (fc[0](oRow)) {
                _this.oFiltered.push(oRow);
            };
            break;
        case 2:
            if (fc[0](oRow) && fc[1](oRow)) {
                _this.oFiltered.push(oRow);
            };
            break;
    };
});

with the snippet on top of this answer and you're done.


I took the liberty of adapting your script a little bit in the following snippet - using a closure and some more Array.prototype.* methods. This will maybe a little bit confusing, but perhaps there is something useful/interesting in it :)

_this = {};
_this.oData = [{'itemfk':123,'vdrfk':24},{'itemfk':13,'vdrfk':34},{'itemfk':18,'vdrfk':77},{'itemfk':13,'vdrfk':24},{'itemfk':48,'vdrfk':34}];
_this.oItemsSelected = [{'itemfk':123},{'itemfk':13}];
_this.oVendorsSelected = [{'vdrfk':234},{'vdrfk':24}];


function createFilterFunction( /* conditions */ ) {
  var conditions = Array.prototype.slice.apply(arguments), // convert <arguments> into a real array so we can use <Array.prototype.map()>
      fc = conditions.map(function(condition) {
        // we create a new function for each "condition" passed as parameter
        return function(row) {
          // <Array.prototype.some()> returns true if one of the items in the array fulfills the predicate
          return condition.data.some(function(item) {
            return item[condition.key] === row[condition.key];
          });
        };
      });

  // the "actual" function to filter the passed data
  return function(dataToFilter) {
    return dataToFilter.filter(function(data) {
      // here we call every filter function in <fc> with every element in <dataToFilter> until one of the elements doesn't fulfill the predicate
      return fc.every(function(func) {
        return func(data);
      })
    });
  };
}

// setup the function to filter the data
var filterConditions = createFilterFunction(
   // <data> = items for comparison
   // <key>  = name of the property whose value should be compared
   { data: _this.oItemsSelected,   key: "itemfk" }
  ,{ data: _this.oVendorsSelected, key: "vdrfk" }
  // third condition
  // fourth condition
  // ...
);


var filteredConditions = filterConditions(_this.oData);
console.log(JSON.stringify(filteredConditions));
Andreas
  • 21,535
  • 7
  • 47
  • 56
  • Your first answer is awesome, simple and easy enough I almost understand what is occurring. The liberty version... it is over my head but I get the idea in principle and will need to do a lot more studying to understand. I think I will leave it for a local guru friend to explain to me, I'm to new to JavaScript to understand prototype behaviors. But thank you very much for pointing out there is a better way! – Harvey Mushman Oct 23 '17 at 20:18
  • "Better" depends on the use case^^ I added the generic approach because I thought this may be interesting for you :) – Andreas Oct 23 '17 at 20:22
  • As it is... very interesting! You are clearly an expert and I'm just a beginner. Never the less, I really appreciate your answers and owe you at least a beer or two :-) – Harvey Mushman Oct 23 '17 at 21:01
0

You can try with map and forEach method, working demo is given below

_this = this;
// sample data
_this.oData = [{
    'itemfk': 123,
    'vdrfk': 24
  },
  {
    'itemfk': 13,
    'vdrfk': 34
  },
  {
    'itemfk': 18,
    'vdrfk': 77
  },
  {
    'itemfk': 13,
    'vdrfk': 24
  },
  {
    'itemfk': 48,
    'vdrfk': 34
  }
];
_this.oItemsSelected = [{
    'itemfk': 13
  },
  {
    'itemfk': 123
  }
];
_this.oVendorsSelected = [{
    'vdrfk': 234
  },
  {
    'vdrfk': 24
  }
];
// called by cascading controls
this.filterConditions = function() {
  var arr = _this.oItemsSelected.map(function(element) {
    return Object.values(element)[0]
  });
  var arr2 = _this.oVendorsSelected.map(function(element) {
    return Object.values(element)[0]
  });
  _this.oData.forEach(function(element) {
    if (arr.indexOf(element.itemfk) != -1 && arr2.indexOf(element.vdrfk) != -1) {
      console.log(element);
    }
  });
  // two oData rows (index zero and three) match conditions


};



<!-- begin snippet: js hide: false console: true babel: false -->
<html>

<head>
  <title></title>
  <meta charset="utf-8" />
  <script src="https://stacksnippets.net/js"></script>
</head>

<body onload="filterConditions()">

</body>

</html>
  • Thank you for your answer but I do not see how it addresses my question. My question has to do with the fact that by having to hard code the if conditions, I had to supply a condition statement for every filter. If I have a possible 6 filters and only one or two are invoked in a hard coded solution all six are tested. In the dynamic testing solution I selected above only the conditions that are created get executed. Thank you for your effort. – Harvey Mushman Oct 24 '17 at 14:09