Guna Guna - 26 days ago 13
JSON Question

How to filter the JSON data using AngularJS?

I have three

dropdown
boxes. I need to filter the data and need to be displayed in the table based on my checkbox selection(either with
single checkbox
or
two checkboxes
or
three checkboxes
).

I have done the following, but if we observe it clearly, I am not able to filter the data properly using
AngularJS
.

Like:

a. It should work for
individual checkbox selection
: means if I select any
single checkbox
either from
Name
or
Description
or
Field4
, then respective matched filtered data should be displayed in the table, otherwise it shouldn't be displayed any data(i.e if it doesn't match our checkbox selection means it won't display any data)

b. It should work for
multiple(two) checkbox selection
: means if I select any multiple checkboxes like either
one from Name
and
one from Description
or
one from Description
and
one from Field4
or
one from Field4
and
one from Name
, then respective matched filtered data should be displayed in the table, otherwise it shouldn't be displayed any data(i.e if it doesn't match our checkbox selection means it won't display any data)

c. It should work for
multiple(three) checkbox selection
: means if I select the three checkboxes like
one from Name
and
one from Description
and
one from Field4
, then respective matched filtered data should be displayed in the table, otherwise it shouldn't be displayed any data(i.e if it doesn't match our checkbox selection means it won't display any data)

It is working fine for the first time
checkbox
selection only, means: after loading the above code/app, if we
check
either any one of the above selections(like whether
single checkbox
selection or
two checkbox
selection or
three checkbox
selection) then it's working fine, later it is not working(means if we
uncheck
the above any criteria and then if we select any
checkbox
again then it's not working, for that again we need to refresh the app/code then only it's working).

Example: if I select one from Name, then respective matched data will be displayed. Then again if I
uncheck
the same and
check
the
some other checkbox
like from
Description
then it's not working. Similarly for all the above criteria. You can
observe
it clearly.

Please let me know that what I have done wrong here and let me know how to filter it properly. Created Fiddle. Thanks in advance !

Answer

The problem is the convoluted filtering logic. Anytime you find yourself nesting lots of if statements, think about reorganizing the branching logic. By breaking it into smaller components, you can make it easier to manage, and if you can avoid using if altogether, then you only have to test one path, instead of several.

Every time a user checks a box, we need to make sure that we only display items that match however many boxes are checked. So we need to know 1) how many boxes are checked, n, and 2) how many items can be found with n matching fields.

We can take advantage of the fact that Boolean variables can be cast to integers (0 = false, true = 1) and use that to count the number of checked boxes, as well as the number of matches found.

We can also put the field names into an array, so that we don't have a lot of repetition in our functions.

Fiddle example here.

var fields = ["name", "description", "field4"];

//for each field, count how many fields the item matches
function getMatches(item, matchesNeeded) {
    var foundMatches = 0;
    fields.forEach(field => {
      foundMatches += item[field] === $scope.pagedItems[field]
    });

    //make sure found at least one match and found desired minimum
    return foundMatches && foundMatches >= matchesNeeded;
}

//count how many boxes are checked
//this will tell us how many different fields we are matching on
function numChecked() {
    var count = 0;
    fields.forEach(field => {
        //this will auto convert falsy to 0.
        //truthy values will be 1
        count += Boolean($scope.pagedItems[field]);
    });
    return count;
}

$scope.filterItems = function(item) {
    return getMatches(item, numChecked());
};
Comments