Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

[typeahead][bug] filters not being applied on promises #993

Closed
santyclaz opened this issue Sep 11, 2013 · 11 comments
Closed

[typeahead][bug] filters not being applied on promises #993

santyclaz opened this issue Sep 11, 2013 · 11 comments

Comments

@santyclaz
Copy link

I was originally going to comment on Stack Overflow, but I figured this is the more appropriate place to discuss this.

Reference to response I am commenting on:
http://stackoverflow.com/a/15930592/1217025

So I tried to add filters on the plunkr example @pkozlowski-opensource provided in his SO response, but the filters didn't seem to ever get applied.

e.g.
<input ... typeahead="suggestion for suggestion in cities($viewValue) | limitTo:4">

I tried digging into the ui-bootstrap typeahead core, and I feel like it comes down to the function var getMatchesAsync = function(inputValue) {...}.

In that function it calls:

$q.when(parserResult.source(scope, locals)).then(function(matches) {
   ...
}, ...);

It seems like parserResult.source(scope, locals) executes the part of the sourceArray expression that includes the sourceArray and everything to the right of it (really just filters). So in the example earlier, it executes cities($viewValue) | limitTo:4. Since cities($viewValue) returns a promise object, the limitTo filter does get run, but it simply returns the promise object unchanged since it doesn't know how to handle objects. Once the passed back promise object is resolved, the success callback in .then(function(matches) {...}, ...); fires, but all the filter information is essentially lost.

To sum up, it seems like the issue is that all filters get applied to the promise object, which typically yields no change, and does not get applied to the result of the promise.

@pkozlowski-opensource
Copy link
Member

@santyclaz your analysis is correct. The whole promise handling in AngularJS expressions (and in the $parse service) is a bit inconsistent and is changing in 1.2 (see #949 for example), inside AngularJS. I'm not sure how the final support is going to look like so things are going to change based on AngularJS support. For now you need to move filtering to the function itself to the cities method as shown in the http://plnkr.co/edit/eGG9Kj?p=preview plunker:

$scope.cities = function(cityName) {
    return $http.jsonp("http://gd.geobytes.com/AutoCompleteCity?callback=JSON_CALLBACK &filter=US&q="+cityName).then(function(response){
      return limitToFilter(response.data, 15);
    });
  };

@santyclaz
Copy link
Author

@pkozlowski-opensource oh alright, good to know. I'll be sure to keep an eye on this as it develops. Yeah I ended up just moving all my filtering into the function as I saw no other way around it without changing the core bootstrap code. Thanks!

@santyclaz
Copy link
Author

So I just saw the new stable release of 1.2.0, and noticed some changes relating to $parse and removing auto-unwrapping of promises. How will this affect this issue?

I'm guessing I will need to update my version of bootstrap in conjunction with my version of angular for this to work?

@pkozlowski-opensource
Copy link
Member

It was fixed in AngularJS, no need to update angular-ui/bootstrap.

@santyclaz
Copy link
Author

So I tried adding a limitTo filter again (http://plnkr.co/edit/SshGXx?p=preview)

e.g.
<input ... typeahead="suggestion for suggestion in cities($viewValue) | limitTo:5">

but the filter doesn't applied still. The angular version is 1.2.0 and bootstrap version is 0.6.0 in the plunkr.

@pkozlowski-opensource
Copy link
Member

@santyclaz due to the way things are implemented you have to move a filter to the cities function as commented previously, 1.2 changes nothing in this respect. Making it work with async results and the syntax you are trying to use would be very challenging.

@santyclaz
Copy link
Author

Alright thanks for clarifying!

@santyclaz
Copy link
Author

So I noticed on the docs an example that seems to use filters with promises, which seems inconsistent with our earlier discussion saying filters need to be moved to the function that returns the promise.

Code snippet in question (from bootstrap docs)
<input type="text" ng-model="asyncSelected" placeholder="Locations loaded via $http" typeahead="address for address in getLocation($viewValue) | filter:$viewValue" typeahead-loading="loadingLocations" class="form-control">

Specifically:
typeahead="address for address in getLocation($viewValue) | filter:$viewValue"

It seems like filter:$viewValue works perfectly fine with getLocations($viewValue) which returns a promise, when it seems like it shouldn't work in the first place. How come there is this inconsistency of the "filter" filter working, but other filters like "limitTo" not working?

@pkozlowski-opensource
Copy link
Member

@santyclaz no, actually things are consistent - there was simply a bug in docs that I haven't spotted earlier - it is corrected now via c5862b0. This filer on the docs was filtering a promise and really had no effect as the filter filter is ignoring anything that is not an array.

So nothing changed from our last discussion on the topic.

@santyclaz
Copy link
Author

Ooh that's silly of me, I should have realized the filtering was all server-side with each AJAX request, and not through the filter. Thanks for clarifying for me (again) haha

leg100 added a commit to leg100/sidelined-rails3 that referenced this issue Feb 27, 2014
@jdhiro
Copy link

jdhiro commented Mar 20, 2014

It looks like the broken example is still in the docs. I just spent a couple of hours hitting my head on my desk over this one.

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

No branches or pull requests

3 participants