salamanka44 salamanka44 - 6 days ago 6
AngularJS Question

How to write a filter to search nested json in angular?

I wrote a little program in angular using ui-select. And I want to write a filter that do an OR search in different fields (that can be nested fields in a json). In the github of ui-select I found this filter that can do a similar things (but only with simple fields) :

/**
* AngularJS default filter with the following expression:
* "person in people | filter: {name: $select.search, age: $select.search}"
* performs an AND between 'name: $select.search' and 'age: $select.search'.
* We want to perform an OR.
*/
app.filter('propsFilter', function() {
return function(items, props) {
var out = [];

if (angular.isArray(items)) {
var keys = Object.keys(props);

items.forEach(function(item) {
var itemMatches = false;

for (var i = 0; i < keys.length; i++) {
var prop = keys[i];
var text = props[prop].toLowerCase();
if (item[prop].toString().toLowerCase().indexOf(text) !== -1) {
itemMatches = true;
break;
}
}

if (itemMatches) {
out.push(item);
}
});
} else {
// Let the output be the input untouched
out = items;
}

return out;
};
});


My json object where I want to apply this filter has this structure :

$scope.contracts = [{
name: "contract1.00",
value: 10,
id :{
id : 8000,
code : 2
},
policy : {
info : {
name : "test1",
country : "test"
}
}
}
//other elements....


The problem is that this 'propsFilter' only works with simple fields. So, if I write this :

propsFilter: {name: $select.search, value : $select.search}


It will work correcly and do an OR search in these two fields (name OR values). But in my example, I want to do the OR search with two others fields : id.id and policy.info.name.

So, what I want to do is to use a line like this :

propsFilter: {name: $select.search, value : $select.search, id.id : $select.search, policy.info.name : $select.search }


Finally, here is my plunker : http://plnkr.co/edit/ej2r7XqeTPOC5d1NDXJn?p=preview

How can I do that in the same search filter??

Answer

I've updated your plunker. First of all, break from the loop caused the filter to work only on first property name, I've also added a condition in the if item[prop] && so your code doesn't throw an error when the property does not exist on the item

http://plnkr.co/edit/CwNANzodvjnuMCNyJYtA?p=preview

app.filter('propsFilter', function($parse) {
  return function(items, props) {
    var out = [];

    if (angular.isArray(items)) {
      var keys = Object.keys(props);

      items.forEach(function(item) {
        var itemMatches = false;

        for (var i = 0; i < keys.length; i++) {
          var prop = $parse(keys[i])(item);
          var text = props[keys[i]].toLowerCase();

          if (prop && prop.toString().toLowerCase().indexOf(text) !== -1) {
            itemMatches = true;
          }
        }

        if (itemMatches) {
          out.push(item);
        }
      });
    } else {
      // Let the output be the input untouched
      out = items;
    }

    return out;
  };
});
Comments