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

in 1.3.16 ng-repeat filter changed from not filtering the absent fields to filtering them #12060

Closed
ali-bugdayci opened this issue Jun 9, 2015 · 13 comments

Comments

@ali-bugdayci
Copy link

in 1.3.15 we have working code like this:

<div data-ng-controller="UserController as vm"
        <div ng-include="'modules/users/views/usersTable.template.client.view.html'">

where the ng-view included can see and use the vm object.

Update to 1.3.16 breaks this and ng-view creates a new scope object. Hence the vm used inside the included code is not same object.

@Narretz
Copy link
Contributor

Narretz commented Jun 9, 2015

There is nothing in 1.3.16 that should affect ng-include. Can you please provide a demo of the problem?

@ali-bugdayci
Copy link
Author

Hi,

Thanks for the fast response. As you have mentioned the problem was from the change in the "filter filter" implementation.

In 1.3.15, if the filter object values are absent in the data, the data passes through ng-repeat.

In 1.3.16, if the filter object values are absent in the data, the data is not passed from ng-repeat

Check the plunker: http://plnkr.co/edit/5WSyJIlnxRmwkY8wk590?p=preview

@ali-bugdayci ali-bugdayci changed the title in 1.3.16 ng-view changed to create a new Scope rather than inheriting in 1.3.16 ng-repeat filter changed from not filtering the absent fields to filtering them Jun 9, 2015
@ali-bugdayci
Copy link
Author

Must have been appeared when fixing these issues:

filterFilter: fix matching against null/undefined (9dd0fe3, #11573, #11617)

@lgalfaso
Copy link
Contributor

If you need to put a value on a filter so it gets ignored, then it should be set to undefined. Eg ng-repeat="datum in vm.data | filter:{absent: undefined}".
Sorry that this is causing you trouble, but the behavior at 1.3.16 is the correct behavior.

@ali-bugdayci
Copy link
Author

No no. Have you checked the plunker I send? To make it more discrete I am outlining a usage scenario:

  • Go to :
    http://plnkr.co/edit/E5WhPwmocYNukQhJzmzX?p=preview
  • At first the search field is null. And 1.3.16 is displaying them all.
  • Write something to the search field like 'a'
  • Then delete the search field input
  • This time the search is blank string
  • 1.3.16 is just displaying one of them
  1. User wise this is not acceptable. You have a list of options. When you filter then it works. When you clear the filter it is not back to how it was.
  2. Now a days lots of folks are using NoSql databases. Hence you can not make sure that each field exists in the data returned, since they are mostly schemaless.

@gkalpak
Copy link
Member

gkalpak commented Jun 10, 2015

@ali-bugdayci, this is unfortunately how filterFilter works (which is indeed kind of unexpected in some cases). Note that the change between 1.3.15 and 1.3.16 was intentional in order to fix an old regression introduced during a refactoring in 1.3.6 (so basically, 1.3.16 restores the original behaviour of 1.3.5).

In cases where you want to avoid an emty search field resulting in case-insensitive substring comparison against '', you can change your filter expression like this: | filter:{xyz: search||undefined}
(Updated plnkr)

@ali-bugdayci
Copy link
Author

@gkalpak
The problem with search field is that, in big projects it is most of the times an object not a string. Like we have different input fields where we aggregate the search object.

If you are aware that it works like this and ok with it, than I have nothing to say. But from my users point of view I believe the scenario I described is not acceptable. Seems like I will be sticking with 1.3.15 for a long time.

@gkalpak
Copy link
Member

gkalpak commented Jun 10, 2015

This is has come up a few times and we (I) are aware of this. I don't say I am against changing it, but it will be a breaking change. I am definitely open to discussion, though.

Luckily, Angular is too flexible for you to have to stick to 1.3.15 for a long time, as it provides several ways of making things work the way you like. Off the top of my head:

  1. A special ngModel parser that converts empty string to undefined (either on all input fields or on all input[type="search"] fields or with a special directive.
  2. A custom filter that wraps filterFilter (and igores empty strings).
  3. Decorating filterFilter itself (to ignore empty strings).
  4. Using a custom predicate function as expression.
  5. ...

(Especially for a large project, the overhead should be minimal 😃)

@ali-bugdayci
Copy link
Author

@gkalpak Yeah you are right. May be the best way would be to configure the filterFilter with a filterprovider and choose how you want it to behave.

@gkalpak
Copy link
Member

gkalpak commented Jun 10, 2015

@ali-bugdayci, what would that filterProvider allow you to do which isn't already possible ? Do you mean something like offering a config flag to enable ignoring empty strings ?

BTW, there is no such thing as "provider" for filters, but we might be able to attach some properties on the filter itself.

@ali-bugdayci
Copy link
Author

@gkalpak yeah I know that we dont have filter provider, but you got what I meant.

Instead of every one trying to solve this problem, configuring it through a flag option would be awesome.

But I wouldn't expect something fast. Since you guys are aware of this problem, and made your choice, this would not be a high priority issue.

@petebacondarwin
Copy link
Contributor

There is no configuration phase (unlike standard services) for filters and for this use case it would be an unrealistic change to the core. Also changing how a filter behaves across the board and behind the scenes is a recipe for disaster. If you are using a third party component that expects filterFilter to behave as specified by Angular this may break things. Also future maintainers may not realise that the filter behaviour has been changed just from looking at the template, without searching through the code for potential configuration changes.

As @gkalpak points out there are a number of extension points in Angular to allow you to achieve the effect you wish. Here are a couple of examples:

The second option is perhaps the recommended approach as it doesn't mess with the model value. By attaching the comparator to the $rootScope it is available throughout your application, it doesn't add much to the complexity of the template, It also has the added advantage that it does not change the behaviour of filterFilter for third party components, which you might be using and makes it explicitly clear to the person reading the template that this filter is not going to behave in the default manner.

@gkalpak
Copy link
Member

gkalpak commented Jun 17, 2015

@petebacondarwin said it all.

I just wanted to add that (especially for a large project using the same behaviour in many places), another viable option is to define a custom filter that wraps filterFilter and ensures empty strings in predicate are converted to undefined (or incorporate whatever custom business logic you need to).
(Quick and dirty example)

Or (depending on how you construct filtering predicates, creating a directive that converts empty strings to undefined might also work for you.
(Demo)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants