10

Let's say I have an input text field (more like the Google search field) which, when changed, will trigger a request and show some results.

For instance,

Let's type in Dog in the input:

typed D -> Calls ctrl.search('D') -> Makes a request -> Changes model when success
typed DO -> Calls ctrl.search('DO') -> Makes a request -> Changes model when success
typed DOG -> Calls ctrl.search('DOG') -> Makes a request -> Changes model when success.

Now, let's say that the DO request responds later than the DOG one. My model would end up with the DO results, even if I typed DOG.

For that, I need a way to cancel or abort current ongoing requests if I keep on typing characters. That way, my model is only changed by the final request.

My input looks like the following:

<input type="text" class="form-control" data-ng-model="query" data-ng-change="ctrl.search(query)" placeholder="Search" />

Here is my searchCtrl.js:

var search;
var language;
var _this;

var SearchCtrl = function (searchService, lang)
{
     search = searchService;
     langauge = lang;
     _this = this;
}

SearchCtrl.prototype.search = function (text)
{
    var promise = search.language(language)
                  .facet('characters')
                  .highlight('quotes')
                  .query(text);

    promise.then(function (response) {
         if(!response) return;
         _this.total = response.total;
         _this.count = response.found;
         _this.result = response.data;
    });
}
Matias Cicero
  • 25,439
  • 13
  • 82
  • 154
  • We can't cancel promise..either we need to `reject` or `resolve` it to complete it.. – Pankaj Parkar Nov 03 '15 at 18:50
  • 1
    1) Use debounce in your textbox you can use ng-model-options 2) You can provide a promise to the timeout property of http option which you can cancel it (by rejecting that deferred object), but the request will still be processed by the server it will just be rejected at the client level. – PSL Nov 03 '15 at 18:55
  • It would likely be better to solve this by not sending the request in the first place until a short pause in typing has occurred. Canceling the request won't stop the server from processing it if it has already received it. look into https://docs.angularjs.org/api/ng/directive/ngModelOptions specfically the debounce option. – Kevin B Nov 03 '15 at 18:55

3 Answers3

4

Usually for this case people use ng-model-options={debounce: 100}.

https://docs.angularjs.org/api/ng/directive/ngModelOptions

anyway you can reject promise.

Errorpro
  • 2,253
  • 2
  • 16
  • 17
  • This did the trick! Thank you very much! Is this like a delay before sending each request? – Matias Cicero Nov 03 '15 at 18:58
  • yes, it helps you ;) u're welcome. – Errorpro Nov 03 '15 at 19:01
  • @MatiasCicero it's basically a timeout that gets reset every time the value changes. so, if the value stops changing for 100ms, the timer ends and a request is sent. – Kevin B Nov 03 '15 at 19:06
  • This still doesn't solve your original problem... If a delayed "DO" returns later than an even further delayed "DOG", it will still use the "DO" results. All you are doing is saving the call to the server. – Patrick Nov 03 '15 at 19:11
1

I think you want to use a debounce technique in this case?

see:

house9
  • 20,359
  • 8
  • 55
  • 61
  • Thank you! What does `'blur': 0` do? – Matias Cicero Nov 03 '15 at 19:01
  • I copied that from the docs, might be not needed in your case, when leaving the field it would not have the debounce delay (because it is 0), you can fine tune the debounce based on each event type if desired – house9 Nov 03 '15 at 19:31
0

Like this: $q.reject(response);

Although technically I believe that the above commenter is correct, you're actually rejecting the promise and not really canceling it.

Andrew Cavanagh
  • 277
  • 2
  • 14