I've got an application where I show a list of items with AngularJS. I'm trying to make an easy search on this list but it searches on everything inside that item. An example of an item:
{
id: 283727893,
name: 'Item A',
parent: {
id: 239495838,
name: 'Item B'
},
user: 'User C'
}
In the list I'm only writing the name of the root item, so parent.name
does not appear.
However, if I search using an AngularJS filter by 'Item B', it still appears, because an inner property has this string.
I've put an object reference such as the following (where val
is the text of the input):
vm.searchObj = {
name: val,
user: val
};
And then, on my DOM:
<li data-ng-repeat="[...] | filter: Ctrl.searchObj | orderBy: Ctrl.orderBy">
...
</li>
However, this works with conditional AND, so it only shows if both, name
and user
have val
.
I'd like to take an input text and make a search to filter this list on given object properties (in plural).
So, in this example, this item should appear if I write 'Item A' or 'User C' (or just 'A' or just 'C' and so on), but not if I write 'B', because none of name
and user
have this letter.
I'd need it to take the reference object, in this case Ctrl.searchObj
, and check if any of the given properties of the object contains val
into the same structure of the filtered objects.
That, of course, should work into deeper levels of the object, so I could define the searchObj
as follows and still be able to get if the filtered object has that structure inside:
vm.searchObj = {
parent: {
name: 'Item'
}
};
In this case, it should show those items where its parent.name
property contains the word 'Item'.
If you need more information, please, let me know!
Thank you!
If I understand correctly, an object being searched (we'll call it target
) is a match if:
both searchObj
and target
share at least one property name at the same level
The value of target
's property is equal to or contains the value of searchObj
's property
The code below (which includes your edits) should do what you need. I'll leave it to you to fill in any edge cases (checks for hasOwnProperty
, comparison of different types, etc.). I think filtering like this should only happen when necessary, like when a user types. Creating an Angular filter out of this could be too expensive, since it runs on each digest cycle:
function objectContains(searchObj, target) {
for (var property in searchObj) {
var searchVal = searchObj[property];
var targetVal = target[property];
if (isObject(searchVal) && isObject(targetVal)) {
if(objectContains(searchVal, targetVal)){
return true;
}
}
if (
!isObject(searchVal) && !isObject(targetVal) &&
!isUndefinedOrNull(targetVal) &&
!isUndefinedOrNull(searchVal) &&
targetVal.toString().indexOf(searchVal.toString()) !== -1
) {
return true;
}
}
return false;
}
function isUndefinedOrNull(x) {
return typeof x === "undefined" || x === null;
}
function isObject(x) {
return typeof x === "object";
}
var filtered = list.filter(function(item) {
return objectContains(searchObj, item);
});