How to cancel a request made with angucomplete-alt remote-api-handler?

by Tristan Hamel   Last Updated August 14, 2019 06:26 AM

This question is about Angucomplete-alt directive

Note: I am using Angular 1.4

I am using remote-api-handler parameter to populate the options of angucomplete-alt directive. I would like to be able to cancel queries made by angucomplete-alt if the response is received after new queries were made or if the text field lost focus. To do so, I inspect the response's config property and set a flag upon losing focus. So far, I have managed only to handle the case by sending an empty data array to angucomplete-alt but this has the undesirable side effect of showing the no-results placeholder and showing the dropdown after the text field lost focus.

Ideally I want to achieve the following:

  • cancel a request if a new one was done before its result arrive and display the text-searching placeholder rather than the text-no-results one.

  • cancel a request if lost focus and prevent angucomplete-alt to open its dropdown.

My intuition is that I should use remote-api-handler second argument (timeoutPromise) but I have not had success so far. Would someone have an idea how to nicely tackle this use case? Maybe you would adopt a different strategy than the one I am trying?

Here is the part of the html template defining the angucomplete-alt directive:

  <angucomplete-alt id="suggestions"
                    placeholder="Search something"
                    pause="100"
                    selected-object="vm.selected"
                    remote-api-handler="vm.apiHandler"
                    title-field="key"
                    minlength="1"
                    maxlength="70"
                    text-searching="search in progress"
                    text-no-results="nothing found"
                    focus-in="vm.focusIn()"
                    focus-out="vm.focusOut()">
  </angucomplete-alt>

And here is the controller handling the requests from angucomplete-alt:

angular
    .module('my-module')
    .controller('FieldController', FieldController);

  function FieldController(apiService) {
    var self = this;
    var previousSelectedTitle = '';

    self.infocus = false;
    self.currentString = '';

    self.apiHandler = apiHandler;
    self.focusIn = focusIn;
    self.focusOut = focusOut;
    self.selected = selected;

    function apiHandler(string, timeoutPromise) {
      self.currentString = string;
      return apiService.get(string)
      .then(function(result){
        //prevents late responses to display - should use timeoutPromise?
        if(!self.infocus || result.config.params.string !== self.currentString){
          return {data: []};
        }
        else{
          return result;
        }
      }
    }

    function focusIn() {
      self.infocus = true;
    }

    function focusOut() {
      self.infocus = false;
    }

    function selected(selectedObj) {
      if (angular.isUndefined(selectedObj) ||!self.infocus) {
        return;
      }
      //Do something great with the selected object
    }
  }


Answers 2


The second argument to your custom handler is not exactly a timeout promise but really a cancel promise. The promise only gets resolved if a search is already underway but the user continued typing, and now the input has changed.

I have been using Promise.race which seems to make the plugin function as intended:

function apiHandler(string, nevermind) {
  return Promise.race([apiService.get(string), nevermind]);
}
Tom McClure
Tom McClure
July 25, 2019 20:30 PM

Tom McClure answer is almost correct, for the correct implementation of Promise.race, see the code below,

in controller file add below code

function apiHandler(string) {
  return Promise.race([apiService.get(string)]);
}

In above code promise.race will consider the api which will take longer time and ignore others.

you can also cancel the previous api call by adding timeout,so that you will get the response for the latest api call

var handler = $q.defer()
$http.get('url', {
timeout: handler.promise
})

to cancel the previous api call just call handler.resolve() which will cancel the api call

handler.resolve() //which will cancel the previous api call

this might help you.

ajaykumar mp
ajaykumar mp
August 14, 2019 06:26 AM

Related Questions


Updated April 20, 2015 04:11 AM

Updated August 04, 2016 08:12 AM

Updated May 20, 2015 20:11 PM

Updated June 02, 2015 00:11 AM

Updated July 24, 2017 08:26 AM