Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Fix(filter): Filter objects with circular references #6319

15 changes: 11 additions & 4 deletions src/ng/filter/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ function filterFilter() {
if (!isArray(array)) return array;

var comparatorType = typeof(comparator),
predicates = [];
predicates = [],
evaluatedObjects = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want to use the hashKey api from src/api.js for this, rather than an array (this would work for 1.2.x as well)


predicates.check = function(value) {
for (var j = 0; j < predicates.length; j++) {
Expand Down Expand Up @@ -165,9 +166,15 @@ function filterFilter() {
case "object":
return comparator(obj, text);
default:
for ( var objKey in obj) {
if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
return true;
for (var objKey in obj) {
var value = obj[objKey];
if (typeof value == 'object' || typeof value == 'function') {
if (evaluatedObjects.indexOf(value) == -1) {
evaluatedObjects.push(value);
if (objKey.charAt(0) !== '$' && search(value, text)) { return true; }
}
} else {
if (objKey.charAt(0) !== '$' && search(value, text)) { return true; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we can simplify this block a bit:

for (var objKey in obj) {
  if (objKey.charAt(0) !== '$') {
    var value = obj[objKey];

    // Will avoid adding `null` to the collection (typeof null === "object")
    if (isObject(value) || isFunction(value)) {
      // If it's a circular reference, just proceed to the next property
      if (evaluatedObjects.indexOf(value) >= 0) continue;
      evaluatedObjects.push(value);
    }
    // No need to duplicate this call in two branches
    if (search(value, text)) {
      return true;
    }
  }
}

}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

free up references with evaluatedObjects.length = 0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nevermind, that won't do anything. ignore :)

break;
Expand Down
12 changes: 12 additions & 0 deletions test/ng/filter/filterSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ describe('Filter: filter', function() {
expect(filter(items, 'misko').length).toBe(0);
});

it('should not re-evaluate circular references', function() {
var originalItem = {name: 'misko'};
var referencedItem = {originalItem: originalItem};
originalItem.referencedItem = referencedItem;

var items = [originalItem];
expect(function() { filter(items, 'not misko') })
.not.toThrow();

expect(filter(items, 'misko')).toEqual([originalItem]);
});

it('should filter on specific property', function() {
var items = [{ignore: 'a', name: 'a'}, {ignore: 'a', name: 'abc'}];
expect(filter(items, {}).length).toBe(2);
Expand Down