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

Option to have typeahead update the $viewValue after blur #2255

Closed
scottohara opened this issue May 25, 2014 · 2 comments
Closed

Option to have typeahead update the $viewValue after blur #2255

scottohara opened this issue May 25, 2014 · 2 comments

Comments

@scottohara
Copy link

Not sure if this would conflict with other existing behaviour of the typeahead, but my use case is as follows:

  1. Data source for typeahead is a promise ($http)
  2. Typeahead expression is:
object as object.name for object in functionThatReturnsAPromise($viewValue, 10)
  1. Given the above expression, the value stored in the ng-model after selecting an item from the popup is an object (eg. {id: 123, name: 'foo'})
  2. typeahead-editable is true (allows the user to enter values not returned in the promise results)
  3. If the user enters a value not in the promise results, the ng-model stores a string value (eg. "bar")
  4. On save, my application checks the type of the value stored in the ng-model, eg.
if (typeof $scope.myModel === 'string') {
  // user-entered value...add new item to database
} else {
  // existing value selected, do nothing
}

The problem I'm having is where the user types a value and tabs out of the field (blurs) before the $http promise has resolved; and the value the user typed would have been in the search results.

For example, if "foo" is an existing value returned in the promise, and the user types "foo" but hits tab before the promise resolves; the ng-model has a value of "foo" (a string).
If, on the other hand, the user waits for the promise to resolve before hitting tab (or is a slow typist), the ng-model will have a value of {id: 123, name: 'foo'} (an object).

From what I understand, the typeahead ignores/cancels any in-flight requests when the field blurs. Is this correct, and if so, is there a way to override this, so that when a $http call triggered by the typeahead resolves, it will update the typeahead value even if the input field no longer has focus?

(i.e. in the above example, the string value "foo" would be replaced by the foo object)

Alternatively, I could modify my save code to recheck that a string value is truly new, eg.

if (typeof $scope.myModel === 'string' && !existsInPromise($scope.myModel)) {
  // user-entered value...add new item to database
} else {
  // existing value selected, do nothing
}

..but I would need to do this for every typeahead that has this same issue; so it would be ideal if I could configure the typeahead itself to update even when blurred.

@pkozlowski-opensource
Copy link
Member

@scottohara your analysis of the current behaviour is correct - we ignore async results if a field is blurred. This was explicitly requested by our users, see #964

As for the solution, this:

so that when a $http call triggered by the typeahead resolves, it will update the typeahead value even if the input field no longer has focus

won't work since promise resolution will return some results and will make the autocomplete pop-up to appear - there won't be automatic selection of any match. And indeed - you don't have any guarantee that there would be only one matching item.

I would like to offer an alternative solution but I'm not sure I got your use-case. If users can input a new name, who is going to fill-in the id? And can't you check if the model holds an object or a string?

Once again, I will need more info to suggest something else / better...

@scottohara
Copy link
Author

Thanks for the response. I agree that my use case is somewhat of an edge-case; and I was concerned that it might conflict with existing behaviour, which as you pointed out was explicitly requested to work the way it does.

Your point about there being no guarantee of only one matching item is valid. Although in my case, values returned by the promise do happen to be unique, so there should only ever be one exact match. But I appreciate that this may not always be the case.

I will close this issue, and implement a solution by checking if a string value stored in the model matches an existing value before adding the new value.

(alternatively, another option would be to resolve the promise and pass it into the controller as a dependency, ie. via a resolve on the ui-router state that transitions to the controller).

Thanks for your input.

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

2 participants