admin管理员组

文章数量:1430513

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

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

autoComp.focus(function() { $(this).autoplete("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 autoplete is blurred. But as soon as the response returns, the options menu pops out, even though the autoplete has no focus. In order to make it go away the user has to click once inside, and again outside the autoplete, 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 autoplete?

this.autoplete = $('.tab#'+this.id+' #tags').autoplete({
    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).autoplete("search", "");
});
$('.tab#'+this.id+' #tags').blur(function() {
    console.log('blurring');
    var xhr = $(this).data('xhr'); // This es out undefined... :(
    if (xhr) {
        xhr.abort();
    };
    $(this).removeClass('ui-autoplete-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: {
                    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'm using jquery ui autoplete widget with ajax, and on noticed the following problem.

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

autoComp.focus(function() { $(this).autoplete("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 autoplete is blurred. But as soon as the response returns, the options menu pops out, even though the autoplete has no focus. In order to make it go away the user has to click once inside, and again outside the autoplete, 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 autoplete?

this.autoplete = $('.tab#'+this.id+' #tags').autoplete({
    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).autoplete("search", "");
});
$('.tab#'+this.id+' #tags').blur(function() {
    console.log('blurring');
    var xhr = $(this).data('xhr'); // This es out undefined... :(
    if (xhr) {
        xhr.abort();
    };
    $(this).removeClass('ui-autoplete-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: {
                    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'));
        }
Share Improve this question edited Sep 10, 2011 at 10:53 Uri asked Sep 9, 2011 at 2:15 UriUri 27.1k12 gold badges48 silver badges80 bronze badges 0
Add a ment  | 

2 Answers 2

Reset to default 4

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 autoplete 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 Autoplete 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").autoplete({
    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).autoplete("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").autoplete({
  open: function() {
    if ($(this).is(':not(:focus)')) {
      $(this).autoplete('close');
    }
  },
  source: function(request, response) {
    ...
  }
});

本文标签: