开发者

jquery ui autocomplete does't close options menu if there is no focus when ajax returns

开发者 https://www.devze.com 2023-04-03 21:04 出处:网络
I\'m using jquery ui autocomplete widget with ajax, and on noticed the following problem. Background: In order for the user to be able to focus on the autocomplete and get the options without typing

I'm using jquery ui autocomplete widget with ajax, and on noticed the following problem.

Background: In order for the user to be able to focus on the autocomplete and get the options without typing anything, I use the focus event:

autoComp.focus(function() { $(this).autocomplete("search", "");}

However this produces the following effect: when the user clicks, an ajax request is being sent. While waiting for the response, the user then clicks elsewhere and the autocomplete is blurred. But as soon as the response returns, the options menu pops out, even though the autocomplete has no focus. In order to make it go away the user has to click once inside, and again outside the autocomplete, which is a bit annoying.

any ideas how I prevent this?

EDIT: I solved this in a very ugly way by building another mediator function that knows the element's ID, and this function calls the ajax function with the ID, which on success check the focus of the element, and returns null if it's not focused. It's pretty ugly and I'm still looking for alternatives.

EDIT#2: Tried to do as Wlliam suggested, still doesn't work.. the xhr is undefined when blurring. Some kind of a problem with the this keyword, maybe it has different meanings if I write the getTags function outside of the autocomplete?

this.autocomplete = $('.tab#'+this.id+' #tags').autocomplete({
    minLength: 0,
    autoFocus: true,
    source: getTags,
    select: function(e, obj) {
        tab_id = $(this).parents('.tab').attr('id');
        tabs[tab_id].addTag(obj.item.label, obj.item.id, false);
        $(this).blur(); // This is done so that the options menu won't pop up again.
        return false;  // This is done so that the value will not stay in the input box after selection.
    },
    open: function() {},
    close: function() {}
});
$('.tab#'+this.id+' #tags').focus(function() {
    $(this).autocomplete("search", "");
});
$('.tab#'+this.id+' #tags').blur(function() {
    console.log('blurring');
    var xhr = $(this).data('xhr'); // This comes out undefined... :(
    if (xhr) {
        xhr.abort();
    };
    $(this).removeClass('ui-autocomplete-loading');
});

and this is the getTags function copied to the source keyword:

        function getTags(request, response)
        {
            console.log('Getting tags.');
            $(this).data('xhr', $.ajax({
                url: '/rpc',
                dataType: 'json',
                data: {
               开发者_JAVA技巧     action: 'GetLabels',
                    arg0: JSON.stringify(request.term)
                },
                success: function(data) {
                    console.log('Tags arrived:');
                    tags = [];
                    for (i in data) {
                        a = {}
                        a.id = data[i]['key'];
                        a.label = data[i]['name'];
                        tags.push(a);
                    }
                    response(tags);
                }
            }));
            console.log($(this).data('xhr'));
        }


I think you need to use the callback option for the source, in order to abort the AJAX request. Quoting from the overview of the autocomplete widget:

The callback gets two arguments:

  • A request object, with a single property called "term", which refers to the value currently in the text input. For example, when the user entered "new yo" in a city field, the Autocomplete term will equal "new yo".
  • A response callback, which expects a single argument to contain the data to suggest to the user. This data should be filtered based on the provided term, and can be in any of the formats described above for simple local data (String-Array or Object-Array with label/value/both properties). It's important when providing a custom source callback to handle errors during the request. You must always call the response callback even if you encounter an error. This ensures that the widget always has the correct state.

In your case, it'll probably look something like the following:

$("#autoComp").autocomplete({
    source: function(request, response) {
        var searchString = request.term;

        // ajax call to remote server, perhaps filtered with searchString
        $(this).data('xhr', $.ajax({
            ...
            success: function(data) {
                ...
                // pass back the data filtered by searchString
                response(filteredList);
            }
        }));
    },
    minLength: 0,
    focus: function() {
        $(this).autocomplete("search");
    }
})
// cancel the request when user click away from the input box
.blur(function() {
    var xhr = $(this).data('xhr');
    if (xhr) xhr.abort();
});


I got around this issue by using the Open event. If the input doesn't have focus when the drop-down opens, I simply close it.

$("#autoComp").autocomplete({
  open: function() {
    if ($(this).is(':not(:focus)')) {
      $(this).autocomplete('close');
    }
  },
  source: function(request, response) {
    ...
  }
});
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号