fix(filterFilter): correctly handle deep expression objects #9757

Closed
wants to merge 4 commits into
from

Projects

None yet

10 participants

@gkalpak
Member
gkalpak commented Oct 23, 2014

Previously, trying to use a deep expression object (i.e. an object whose properties can be objects themselves) did not work correctly. This commit refactors filterFilter, making it simpler and adding support for filtering collections of arbitrarily deep objects.

Closes #9698


BTW, I used "non-IE8" stuff (like `Array.prototype.some/every`) for the sake of conciseness and clarity, so this is not directly back-portable to 1.2.x. If there is interest, I can create a IE8 compatible version (using `for-loops` etc).
@gkalpak
Member
gkalpak commented Oct 23, 2014

Some considerations:

  1. Should we mention in the docs that deep objects can be also filtered (or is it redundant) ?
  2. Should there be inline comments at certain parts explaining that whats and the whys (or is it clear enough).
  3. None of the previous test-cases broke. Yet, since the filter was heavily refactored, one can't be really sure that all corner-cases are handled the same as before.
    (The documented stuff does seem to still work as expected, so this shouldn't introduce a breaking change (in the "formal" sense).)
@mary-poppins mary-poppins added cla: yes and removed cla: no labels Oct 23, 2014
@Narretz
Contributor
Narretz commented Oct 23, 2014

Great work!
So the fix is for with deep expression objects with multiple properties and the feat is that these objects can be nested arbitrarily deep?

I don't want to piggyback on the PR or anything, but can you check if this PR can be incorporated in your fix? It seems like a good fit. #6623

We could also check other filter issues for possible tests to add.

@caitp caitp commented on an outdated diff Oct 23, 2014
test/ng/filter/filterSpec.js
@@ -79,7 +78,6 @@ describe('Filter: filter', function() {
expect(filter(items, {'first.name':'misko', 'last.name':''})).toEqual([items[0]]);
});
-
@caitp
caitp Oct 23, 2014 Contributor

stop removing these =)

@caitp caitp commented on an outdated diff Oct 23, 2014
test/ng/filter/filterSpec.js
@@ -157,7 +165,7 @@ describe('Filter: filter', function() {
{key: 1, nonkey: 1},
{key: 2, nonkey: 2},
{key: 12, nonkey: 3},
- {key: 1, nonkey:14}
+ {key: 1, nonkey: 14}
@caitp
caitp Oct 23, 2014 Contributor

unrelated change :x

@caitp caitp commented on an outdated diff Oct 23, 2014
src/ng/filter/filter.js
};
}
+
+// Helper functions for `filterFilter`
@caitp
caitp Oct 23, 2014 Contributor

so I like the way this is re-organized, but I will have to work a bit to review this.

@caitp caitp added this to the 1.3.x milestone Oct 23, 2014
@caitp caitp self-assigned this Oct 23, 2014
@caitp
Contributor
caitp commented Oct 23, 2014

So yeah, I would just ditch the first commit --- 2 lines between specs are nice, and used in most of the test suite --- removing them just makes it more inconsistent. As for the minor whitespace changes, those should be picked up by jscs once we get it doing that, but who really cares if we're honest?

@gkalpak
Member
gkalpak commented Oct 23, 2014

@caitp:
I am totally OK with two lines between specs as I am with one line.
What I can't stand is inconsistency (2 lines between some specs and 1 line between others). I just removed 3 double-lines to make it consistent across the test-suite (which mostly uses 1 line between specs).

I also removed empty new lines before a closing }); in 3 cases to make it consistent across the test-suite (which also mostly doesn't have empty lines before closing });).

Anyway, those changes (along with a few white-space changes, to make things consistent and inline with the new jscs rules) are placed in a separate commit, so they can't be ignored (only...you know...they really shouldn't, because consistency is a good thing).
If it makes you feel better, I can add double-lines between all specs in the test-suite :)

@caitp
Contributor
caitp commented Oct 23, 2014

these are test cases, consistency for minor things like that doesn't matter aw hole lot, so long as they are at least following the formal style guidelines imo. I suggest opening a separate bug for fixing style nits unrelated to this functional change so that it's easier to review (less gunk in the diff)

@gkalpak
Member
gkalpak commented Oct 23, 2014

@caitp: Hm...I thought putting those changes in a separate commit was enough, but it apparently isn't. I'll remove the commit and put it in a separate PR then.

@Narretz: I am not sure if it's a fix or a feat. It depends on how it was supposed to work. If filterFilter was supposed to handle deep expressions (and filter deep objects) then it's a fix. If it wasn't supposed to support that in the first place then it's a feat :)
Will look into other filterFilter related issues, but I can't be sure which ones you want to get in and which you don't. If you can point out PRs that should get merged, I will gladly "adapt" them to feet the refactored filterFilter.

Regarding #6623:
It sure could be incorporated, but I want to point out that:
Right now, it is possible to use {somekey: undefined} to match objects that do not have a somekey property (or have it with a value of undefined). If we merge #6623 this will be only possible using a custom function. So, we might be removing a feature :)
But, if you think it should get merged, I am totally OK with that as well.

@caitp
Contributor
caitp commented Oct 24, 2014

@gkalpak you probably need to rebase now that the other part is merged. yeah you do

@Narretz
Contributor
Narretz commented Oct 24, 2014

@gkalpak Regarding #6623; didn't think about that, good point. Leave it as is. :)

@gkalpak gkalpak commented on the diff Oct 25, 2014
test/ng/filter/filterSpec.js
@@ -129,6 +141,7 @@ describe('Filter: filter', function() {
expect(filter(items, '!isk')[0]).toEqual(items[1]);
});
+
@gkalpak
gkalpak Oct 25, 2014 Member

Unrelated newline change (but I promise it is just this one @caitp 😃).

@gkalpak
Member
gkalpak commented Oct 25, 2014

@caitp: Rebased !

I am in the process of reviewing other open issues related to filterFilter (as @Narretz), in order to find tests or test-cases that might fit in or issues that would be solved once this lands or PRs made obsolete by this one etc.
I will post my findings soon (yeah, hold your breath 😛).

@gkalpak
Member
gkalpak commented Oct 25, 2014

Here it is: #9788
I didn't find anything that could be ported into this commit. Most of the issues should be closed anyway (imo).

There is still the feature request for supporting the filtering of objects (in addition to arrays).
There are PRs already submitted for this feature (which should be updated if this one lands of course). In any case, I believe we should not try to put more features into this one.

So, as far as I am concerned, this should be good to review/land. WDYT ?

@albertboada

Amazing refactor. Make it land ASAP, please. Filtering with deep expressions has been broken for too much time now!!

@caitp
Contributor
caitp commented Oct 27, 2014

We have a fan of this fix =)

@caitp
Contributor
caitp commented Oct 27, 2014

Anyways, I admit I haven't done a thorough review of this (I've tried, but it's hard to get through the whole thing in unified diffs, and text is just unreadable in the split view). I think it's probably good since tests are green, but we really don't want any surprises

@gkalpak
Member
gkalpak commented Nov 10, 2014

Christmas came early this year:

  • Neat fix/feat for filter filter (properly supporting deep expression objects).
  • + Tests.
  • + 9 closable issues/PRs (see #9788) - 10 including this one.
  • + Improved code readability/maintanability.
  • + ~20% LOC reduction for filter filter.

All for a tiny review (80 LOC) !
The first reviewer to give a LGTM wins a free review !!!*

🎅 Ho ! Ho ! Ho ! 🎅

_\_*: max. 100 LOC, core AngularJS-related code, must be claimed by the end of 2014
@caitp
Contributor
caitp commented Nov 10, 2014

very amusing =)

@gkalpak
Member
gkalpak commented Nov 11, 2014

caitp wrote:

We have a fan of this fix =)

Seems like we have a second fan !

o- Becoming a collector/classifier for related issues/PRs --- **[check](https://github.com/angular/angular.js/issues/9788)** o- Founding a fan-club --- **[che](https://github.com/angular/angular.js/pull/9757#issuecomment-60682368)[ck](https://github.com/angular/angular.js/pull/9984#issuecomment-62536697)** o- Setting up prizes --- **[check](https://github.com/angular/angular.js/pull/9757#issuecomment-62380524)** I think I am exploring the limits of my social engineering skills...
@caitp caitp and 1 other commented on an outdated diff Nov 11, 2014
test/ng/filter/filterSpec.js
@@ -129,6 +155,27 @@ describe('Filter: filter', function() {
expect(filter(items, '!isk')[0]).toEqual(items[1]);
});
+
+ it('should not consider the expression\'s inherited properties', function() {
@caitp
caitp Nov 11, 2014 Contributor

I still don't feel like this is correct.

It's a breaking change to not care about inherited properties --- and the fact that the property is inherited isn't really the issue, the issue is that we care about properties which are functions at all (they're hard coded to always return false).

I haven't checked how your patch is addressing this, but I think it's important that we A) keep the existing behaviour of looking at inherited properties, and B) don't do the wrong thing for function values.

@gkalpak
gkalpak Nov 12, 2014 Member

@caitp:
My patch does indeed not care about inherited properties (only own properties).

Checking inherited properties (either on the items or on the expression object) is not documented, so it is debatable if it is a feature or a bug 😺.

That said, since we support setting a function as expression (whereby the function is called with the item as an argument and the (boolean) result determines if it belongs to the filtered list or not), if we want to properly support deep expression objects we should handle function properties in a similar way. Explaining with an example (this is what my patch does):

var items = [{
    name: 'George',
    role: 'SuperDuperAdmin'
}];
var expr = {
    name: 'G',
    role: function (val) { return /admin/i.test(val); }
};
console.log($filter('filter')(items, expr).length);   // Prints: 1

This is how I think is more consistent (but there is a good chance you might think otherwise 😄).

In any case, I don't really like taking into account inherited (enumerable) properties (neither on items nor on the expression object). It feels like it is mostly going to lead to unexpected results. If anyone wishes to do it though, they can use a custom comparator or expression function.


Additonally, what the current implementation does is convert expression 'some string' to {$: 'some string'}. IMO, passing a string should not be affected by inherited Object properties (just because we choose to convert it to an object internally).


Finally, let me point out that the current implementation does take into account inherited properties on the expression object, but ignores inherited properties on the items (which seems at the very least inconsistent).

@caitp
caitp Nov 12, 2014 Contributor

My patch does indeed not care about inherited properties (only own properties).

What I'm saying is that previously, we did support properties from the prototype chain, so removing support for this would be a breaking change, regardless of whether it was documented or not.

Since we can't land a breaking change at this point, the right thing to do is not to break this, but instead to make sure that enumerable functions in the prototype chain don't break filtering.

@gkalpak
gkalpak Nov 12, 2014 Member

What I'm saying is that previously, we did support properties from the prototype chain, so removing support for this would be a breaking change, regardless of whether it was documented or not.

I disagree that any bug-fix is a breaking change, unless the behaviour was explicitly documented.
There are behaviours that are obvious/reasonable and therefore expected (even if not explicitly documented).

Taking into account inherited properties of the expression object (but ignoring inherited properties of the items) makes absolutely no sense to me.
E.g.

Object.prototype.someProp = '123';

var items = [{test: 'hello'}];
var expr = {text: 'hell'};
var filtered = filterFilter(items, expr);

console.log(filtered.length);   // Prints: 0

This is totally unexpected and a bug if you ask me (even of it is not documented to work otherwise), because both the items and the expression have the same inherited property (yet we only take it into account in the expression object).
So, right now, inherited properties are neither supported nor documented to be supported. If we want to fix this, we need to decide what to do about it (ignore them or not), document it, implement it and test it. Whatever path we decide to take, it will not be a breaking change (because the feature is not working (or expected to be working) right now.


I am not really sure what you mean by "Since we can't land a breaking change at this point" (because I've seen small breaking changes landing 😄).


This whole thing sounds to me a lot like the following scenario, which we have seen enough in the 1.x series imo:

We have this thing that is broken and we know it is broken.
Yet, we don't want to introduce a tiny "breaking change" (which is actually a bug-fix), because it will break it's "brokeness".
So we keep patching it up, until it is so broken that we are sick of it.
Then, whenever a new issue is brought to light (and they unavoidably will), we complain about the brokeness of the thing.

So, instead of making filterFilter on of those "so broken that makes us sick and will do better in 2.x" thing, lets fix its brokeness while it's still a bug-fix 😃

This is just me thinking out loud. I do understand the whole "no breaking changes" reasoning and (although I very much like to break my things) I am very conservative when it comes to breaking other people's things (aka apps). But when things are broken, then fixing them is not a breaking change (although some apps inevitably have found ways to work-around (and therefore rely) on the previous brokeness of things). Just m2c...
@caitp
caitp Nov 12, 2014 Contributor

I disagree that any bug-fix is a breaking change, unless the behaviour was explicitly documented.

For better or worse, this is not how the world works. People are writing applications now, and this change would make an observable difference, which could break applications. Whether it's documented as supported or not, does not really matter here, it's still an observable difference that can break applications.

Besides that, it's kind of the "default behaviour of javascript", so it's sort of implicitly documented due to not being documented as "not supported".

We can't break this.

@gkalpak
gkalpak Nov 12, 2014 Member

I am not in a position to decide, so... 😈

My previous statement was kind of incorrect:
The current implementation does consider inherited properties on items and the expression object (on the first level). It ignores inherited properties on nested objects. (But handling of nested objects is broken anyway, so no worries.)

So, to sum it up, you think that:
A) Inherited properties should be taken into account (both on the items and the expression object and even on nested objects).
B) When specifying expression as a string (which gets internally converted to {$: '...'}, should the new object inherit from Object ?
C) Functions should...actually, I am not sure what should happen with functions (own or inherited).

Regarding (C):

  • If the expression object and/or the item has an own property that is a function, comparing against that property should always return false (even if the value to compare against is the exact same function or an "identical" function) ?
  • What should happen with inherited properties that are functions ? Consider that item and expression could have different prototypes.
@caitp
caitp Nov 12, 2014 Contributor

B) When specifying expression as a string (which gets internally converted to {$: '...'}, should the new object inherit from Object ?

createMap() is fine for these, in cases where we create the object.

If the expression object and/or the item has an own property that is a function, comparing against that property should always return false (even if the value to compare against is the exact same function or an "identical" function) ?
What should happen with inherited properties that are functions ? Consider that item and expression could have different prototypes.

I think we should just not have a predicate for properties that are functions, regardless of where they are in the prototype chain

@petebacondarwin
Member

Let's get this in - once the review is complete - moving to 1.3.4.

@petebacondarwin petebacondarwin modified the milestone: 1.3.4, 1.3.x Nov 12, 2014
@gkalpak
Member
gkalpak commented Nov 18, 2014

Added a new commit that takes care of the following issues (let me know if it is better to squash the commits into one):

  1. Considering inherited properties (both on expression and on items).
  2. Ignoring function properties (both own and inherited).
  3. Added corresponding tests.

(/ping caitp)

@caitp
Contributor
caitp commented Nov 18, 2014

The fix for the other issue looks great to me. The rest of it is soooo hard to compare with the original text, but tests are passing and it looks cleaner --- nothing sticks out as bad to me here.

So, LGTM. I think 3 separate commits should be okay here unless @petebacondarwin says otherwise. I'll merge this later today.

@petebacondarwin
Member

Is this a fix or a feature?
Otherwise LGTM

@caitp
Contributor
caitp commented Nov 18, 2014

well the third commit is a fix, not sure about the first

@gkalpak
Member
gkalpak commented Nov 18, 2014

@caitp: Basically, it is impossible/meaningless to compare it with the original code, because it has very little resemblance (and because the original wasn't working for deep objects 😃).

W...wait ! Did you say LGTM ? Woohoo !   👯   👯   👯
(Don't forget to claim your prize before it expires !)

Let me kindly remind you of #9788 (nifty collection of related (potentially closable) issues/PRs).


@petebacondarwin: I've wondered myself whether this is a feature or fix. I guess it depends on whether deep expression objects were supposed to be handled in the first place.

@gkalpak
Member
gkalpak commented Nov 18, 2014

Hm...now that it LGTY, I have some considerations of my own (what an irony 😈):

1.

I am not thrilled about calling deepCompare recursively. (What if we are passed a very deep object, or an object with many properties ? (Not to mention an object with cyclic references :/))
Not sure if/how it could be refactored to avoid recursion and still remain reasonably readable and maintainable.
Do you think it would make sense to add a ttl of some short and document that only objects of ttl depth/(breadth) are supported ?
(Needless to mention a circular object leads to stack overflow exceptions.)


2.

Actually, now that deep objects are supported, there are some "design decisions" to be made (and documented probably). Consider the following case:

var items = [{k1: {k2: 'test'}}];
var expr = {k1: 'test'};

This is what happens with my current implementation:

deepCompare({k1: {k2: 'test'}}, {k1: 'test'}, ...)
// boils down to...
deepCompare({k2: 'test'}, 'test', ...)
// which is interpreted equivalently to...
deepCompare({k2: 'test'}, {$: 'test'}, ...)
// which returns true

So, basically, at any level, the same filter rules apply (which might not be what we want). I.e. having to deepCompare an item against a boolean/string/number expression will try to match the expression against any property of the item. Similarly, trying to match a sub-item against a boolean/string/number sub-expression will do the same.
This will result in filterFilter([{k1: {k2: 'test'}}], {k1: 'test'}).length === 1, which might not be expected (or wanted).

I see two possible interpretations of expression {k1: 'test'} (assuming non-strict comparison):

  1. Match an object with a k1 property, whose value includes test.
  2. Match an object with a k1 property, whose value either includes test or is an object that has at least one property that includes test (or whose values is an object that has one property...).

Trying to mimic the top-level implementation in deeper levels, my current approach uses the 2nd interpretation, but I believe you might prefer the 1st (and I find it more "predictable" too).

So, here is what I suggest the implementation should do (if you agree, I will make the necessary changes in the code):

  • Let expr be the expression object and item an object we are trying to match it against.
    Each key (k) in expr indicates that item mush have a corresponding key (k) and that expr[k] should match item[k].
  • If expr[k] and item[k] are both objects, the same logic is applied recursively on their keys.
  • Any expr[k] that is a function should be ignored.
    Any item[k] that is a function should not be considered matching against it's corresponding expr[k].
  • If either expr[k] or item[k] is neither object nor function, they should be passed to the comparator and the result of their comparison determines if they constitute a match.

Special cases:

  • For any k === '$' (at a specific level), the corresponding (sub)item must have at least one property (regardless its name) so that expr[k] matches item[xyz].
  • A boolean/number/string expr at the top level only is equivalent to {$: expr}. (This does not hold for deeper nested sub-expressions.)
  • A function expr at the top level only will be used as the filtering function (equivalent to calling items.filter(expr)).

WDYT @caitp, @petebacondarwin ?

OMG ! Such a long post and only 1 emoticon. I've taken this stuff too seriously 😛
@caitp
Contributor
caitp commented Nov 18, 2014

If worried about deep objects or recursion, could create our own stack (to avoid a stack overflow) --- but realistically a depth of about 8 non-cyclic properties should be good for most things. I think we should stick with recursion until someone complains about overflows, tbh. I expect the only overflows we'd see are from cyclic references, and we've already discussed this (Igor didn't like the performance implications of worrying about cycles)

@googlebot

Thanks for your pull request.

It looks like this may be your first contribution to a Google open source project, in which case you'll need to sign a Contributor License Agreement (CLA) at https://cla.developers.google.com/.

If you've already signed a CLA, it's possible we don't have your GitHub username or you're using a different email address. Check the information on your CLA or see this help article on setting the email on your git commits.

Once you've done that, please reply here to let us know. If you signed the CLA as a corporation, please let us know the company's name.

@googlebot googlebot added cla: no and removed cla: yes labels Nov 21, 2014
@adi-ads adi-ads commented on an outdated diff Nov 21, 2014
src/ng/filter/filter.js
};
+
+ return predicateFn;
+}
+
+function deepCompare(actual, expected, comparator, keyWasDollar) {
+ var actualType = typeof actual;
+ var expectedType = typeof expected;
+
+ if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
+ return !deepCompare(actual, expected.substring(1), comparator);
@adi-ads
adi-ads Nov 21, 2014

possibly can merge code from #10141

@gkalpak
Member
gkalpak commented Nov 21, 2014

@googlebot: Can you confirm I have updated my CLA already ?

@googlebot

CLAs look good, thanks!

@googlebot googlebot added cla: yes and removed cla: no labels Nov 21, 2014
@gkalpak
Member
gkalpak commented Nov 21, 2014

2nd bullet from #9757 (comment) still needs to be addressed :(

@gkalpak gkalpak added a commit to gkalpak/angular.js that referenced this pull request Nov 24, 2014
@gkalpak gkalpak fix(filterFilter): don't match primitive sub-expressions against any …
…prop

Basically, implement the logic detailed in the 2nd point of
angular#9757 (comment)
1d37dc2
@gkalpak gkalpak added a commit to gkalpak/angular.js that referenced this pull request Nov 24, 2014
@gkalpak gkalpak fix(filterFilter): don't match primitive sub-expressions against any …
…prop

Basically, implement the logic detailed in the 2nd point of
angular#9757 (comment)
945d75a
@gkalpak
Member
gkalpak commented Nov 24, 2014

So, I went on and implemented what I described in the 2nd point of #9757 (comment) (since that seemed pretty reasonable and nobody disagreed 😄).

The tests are still passing (note I did not alter any of the original tests; just added 11 new tests).
Nothing should be fundamentally broken.

The only think that works a little different than before (besides supporting deep objects and expressions) is this:

If either expr[k] or item[k] is neither an object nor a function, they should be passed to the comparator and the result of their comparison determines if they constitute a match.

Previously, if we ended up to match an object against a string, they would _not_ be considered a match. For the default (case-insensitive, substring comparator) and the strict-equality comprator this will behave the same as before. The difference is that when you pass a custom comparator, you are allowed to determine if the "things" are equal or not.
So, the expression object's job is to determine what values should be compared and the comparator's job is to determine if they are actually considered "equal" or not. I believe this is the right implementation and not the one currently in master.

/cc @petebacondarwin, @caitp

@lgalfaso lgalfaso modified the milestone: 1.3.4, 1.3.5 Nov 25, 2014
@gkalpak gkalpak added a commit to gkalpak/angular.js that referenced this pull request Nov 27, 2014
@gkalpak gkalpak fix(filterFilter): don't match primitive sub-expressions against any …
…prop

Basically, implement the logic detailed in the 2nd point of
angular#9757 (comment)
122c228
@gkalpak gkalpak added a commit to gkalpak/angular.js that referenced this pull request Dec 1, 2014
@gkalpak gkalpak fix(filterFilter): don't match primitive sub-expressions against any …
…prop

Basically, implement the logic detailed in the 2nd point of
angular#9757 (comment)
2664892
@gkalpak gkalpak added a commit to gkalpak/angular.js that referenced this pull request Dec 1, 2014
@gkalpak gkalpak fix(filterFilter): don't match primitive sub-expressions against any …
…prop

Basically, implement the logic detailed in the 2nd point of
angular#9757 (comment)
d27f4c5
@pkozlowski-opensource pkozlowski-opensource modified the milestone: 1.3.5, 1.3.6 Dec 1, 2014
gkalpak added some commits Oct 23, 2014
@gkalpak gkalpak fix(filterFilter): correctly handle deep expression objects
Previously, trying to use a deep expression object (i.e. an object whose
properties can be objects themselves) did not work correctly.
This commit refactors `filterFilter`, making it simpler and adding support
for filtering collections of arbitrarily deep objects.

Closes #7323
Closes #9698
4710182
@gkalpak gkalpak test(filter): test expression object with inherited properties
Related to #9984
d9b710a
@gkalpak gkalpak fix(filterFilter): ignore function properties and account for inherit…
…ed properties

Closes #9984
999ab01
@gkalpak gkalpak fix(filterFilter): don't match primitive sub-expressions against any …
…prop

Basically, implement the logic detailed in the 2nd point of
angular#9757 (comment)
5d40a89
@caitp
Contributor
caitp commented Dec 2, 2014

So I know I threatened to land this a few weeks ago --- I think we want this, but it looks like some stuff has been added since, and it's really hard to keep track of this diff u_u

Generally I trust @gkalpak's judgement though, so it's probably good. @petebacondarwin can we land this today?

@petebacondarwin
Member

It's a big diff but I like that there are only additions in the test file and this is not the most central part of Angular. Let's get this in.

@caitp
Contributor
caitp commented Dec 2, 2014

Alright *fingers crossed no regressions*

@caitp
Contributor
caitp commented Dec 2, 2014

IT IS DONE

@gkalpak gkalpak added a commit that closed this pull request Dec 2, 2014
@gkalpak @caitp gkalpak + caitp fix(filterFilter): correctly handle deep expression objects
Previously, trying to use a deep expression object (i.e. an object whose
properties can be objects themselves) did not work correctly.
This commit refactors `filterFilter`, making it simpler and adding support
for filtering collections of arbitrarily deep objects.

Closes #7323
Closes #9698
Closes #9757
f7cf846
@gkalpak gkalpak closed this in f7cf846 Dec 2, 2014
@gkalpak gkalpak added a commit that referenced this pull request Dec 2, 2014
@gkalpak @caitp gkalpak + caitp fix(filterFilter): don't match primitive sub-expressions against any …
…prop

Basically, implement the logic detailed in the 2nd point of
#9757 (comment)
a75537d
@gkalpak
Member
gkalpak commented Dec 2, 2014

OMG

I think I'm gonna 😂

@gkalpak gkalpak deleted the gkalpak:filterFilter-deep-expr-obj branch Dec 7, 2014
@shuhei shuhei pushed a commit to shuhei/angular.js that referenced this pull request Dec 10, 2014
Shuhei Kagawa fix(filterFilter): filter deep object by string
Enable filterFilter to filter deep object by string again. It
used to work like this before #9757, 1.3.6.
4ea9af0
@shuhei shuhei pushed a commit to shuhei/angular.js that referenced this pull request Dec 10, 2014
Shuhei Kagawa fix(filterFilter): filter deep object by string
Enable filterFilter with string expression to filter objects with deep
properties. It used to work like this before #9757 and v1.3.6.
0538dc0
@gkalpak gkalpak added a commit to gkalpak/angular.js that referenced this pull request Dec 11, 2014
@gkalpak gkalpak chore(CHANGELOG): add breaking change note for #9757 566e591
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment