2

I need to filter my content with multiple parameters that I am taking from fields. The fields could also be empty, so I need to get all the values that are not empty. And filter by those.

What is the best way to achieve this without making a lot of if and else if conditions like this:

if (a !== '' && b !== '' && c !== '' && d !== '' && e !== ''){
    // none is empty, filter by a & b & c & d & e
}

else if ( b !== '' && c !== '' && d !== '' && e !== ''){ 
    // a is empty, filter by b & c & d & e
}

else if ( a !== '' && c !== '' && d !== '' && e !== ''){ 
    // b is empty, filter by a & c & d & e
}

else if ( b !== '' && a !== '' && d !== '' && e !== ''){ 
}

else if ( b !== '' && c !== '' && a !== '' && e !== ''){ 
}

else if ( b !== '' && c !== '' && d !== '' && a !== ''){ 
}

else if ( c !== '' && d !== '' && e !== ''){
}

else if ( b !== '' && d !== '' && e !== ''){
}

else if ( b !== '' && c !== '' && e !== ''){ 
}

else if ( b !== '' && c !== '' && d !== ''){ 
}

else if ( a !== '' && d !== '' && e !== ''){ 
}

and so on...

Alternatively, how can I get all the unique possible combination of these 5 letters?

Edit ::

The actual code would look something like this

  //a/b/c take value of dropdown items, that match with data on an object

    if (a != '' && b != '' && c != '') {

            for (const i in ParticipationList.TaskMetadata) {
                if (ParticipationList.TaskMetadata[i].attendance == a && ParticipationList.TaskMetadata[i].monitoring_status == b  && ParticipationList.TaskMetadata[i].monitoring_status == c) {
                            filteredaudience[i] = { ['id']: i }
                        }
            console.log(filteredaudience)
            // get all the items that match with the object properties
        }
    }

So if a or b or c is empty, I can't still make the same call, as it would not match anything on the object.

4 Answers4

2

The logic:

Since javascript has short-circuit evaluation, we'll just use a bunch of conditions in the format:

field === "" || (condition to filter using field)

Because of said "short-circuiting", the right side part will only be reached if the field is not empty (i.e. if the left side is false because field !== ""). However, if the field is empty then field === "" will be true and the right side part won't be reached and the whole condition will yield true resulting in the filtering for this field to be skipped.

Multiple conditions should be joined together by the logical && operator and each one of those conditions should be wrapped in parenthesis () because the operator && is higher in precedence than the || operator.

If the data to filter is an array:

For arrays, just use the conditions as the value returned from the callback of filter like so:

let filteredData = data.filter(item =>
  (a === "" || (condition for field 'a' against 'item'))
  &&
  (b === "" || (condition for field 'b' against 'item'))
  &&
  (c === "" || (condition for field 'c' against 'item'))
  &&
  (d === "" || (condition for field 'd' against 'item'))
  &&
  (e === "" || (condition for field 'e' against 'item'))
);

If the data to filter is an object:

In case the data is an object and you can't use filter like above, you can still use the same logic, you just have to use the conditions inside if like so:

let filteredaudience = {};

for (const i in ParticipationList.TaskMetadata) {
  if ((a === "" || ParticipationList.TaskMetadata[i].attendance === a)
   && (b === "" || ParticipationList.TaskMetadata[i].monitoring_status === b)
   && (c === "" || ParticipationList.TaskMetadata[i].monitoring_status === c)
   && (d === "" || ParticipationList.TaskMetadata[i].?????????? === d)
   && (e === "" || ParticipationList.TaskMetadata[i].?????????? === e)) {
    filteredaudience[i] = { id: i };
  }
}
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
0

Depending on how the actual filtering process works, it might be possible to incrementally filter your result instead of doing it simultaneously.

For example, if your data is an array, you might write:

let data = ...;
if (a != '') {
    data = data.filter(elem => checkForA(a, elem));
}
if (b != '') {
    data = data.filter(elem => checkForB(b, elem));
}
...

Maybe you can also incrementally augment the filter object itself and THEN apply the built filter.

Hero Wanders
  • 3,237
  • 1
  • 10
  • 14
  • This is not ideal, if the array is big then this will be slow as it may loop the array multiple times instead of only once. – ibrahim mahrir Aug 07 '20 at 19:17
  • ibrahim mahrir not quite, the data will get smaller with each filter. This is almost as efficient as a single search function. – speciesUnknown Aug 07 '20 at 19:37
  • 1
    Okay, I wrote my answer before the author has provided the details I needed to properly understand the question. With that information, ibrahim's answer is fine, I'll vote for it :) – Hero Wanders Aug 07 '20 at 23:18
0

Please enter more details ... For now, what I understood was that you want to get all the values that are not empty.

for this:

let allElements = [a, b, c, d, e]
let notEmpty = []

allElements.forEach(element => {
    if (element !== '')
        notEmpty.push(element)
});
console.log(notEmpty)
0

A common mistake for new developers is to create long, complicated and repetative if statements with tons of && and || symbols or long strings of if/else if

Instead of this, write a simple search predicate. This is a function which takes some parameters, and reduces them to either true or false.

Within said function, run each filter one at a time. As soon as one fails, return false.

var data = [
    { colour : "red", weight : 2, name : "Example 1"},
    { colour : "orange", weight : 15, name : "Example 2"},
    { colour : "yellow", weight : 10, name : "Test 1"},
    { colour : "green", weight : 24, name : "Test 2"}
];

console.log(search(data, "red", [], ""));

console.log(search(data, "", [5,20], ""));

console.log(search(data, "", [], "Test"));


function search(data, colour, weights, name) {
    return data.filter(row=>testRow(colour, weights, name, row));
}


// much easier to read.
function testRow(colourFilter, weightFilter, nameSearchFilter, row) {

    // run each filter one at a time. If any fail, "short circuit" out.
    if (colourFilter != "" && row.colour == colourFilter) {
        return false;
    }

    // sometimes, a double if statemnt is easier to read.
    if (weightFilter.length > 0) {
        if (row.weight < weightFilter[0] || row.weight > weightFilter[1]) {
            return false;
        }
    }

    // sometimes, the actual rule is a bit complex.
    if (nameSearchFilter != "") {
        if (row.name.indexOf(nameSearchFilter) < 0) {
            return false;
        }
    }

    // we survived all filters.
    return true;
}
speciesUnknown
  • 1,644
  • 2
  • 14
  • 27