views:

32

answers:

1

I have stolen/found/used/written and edited the following widget of jQuery for a auto-completing dropdown.

(function($) {
    $.widget("ui.comboboxGemeenten", {
        _create: function() {
            var focushelper = false;
            var lastTerm;
            var self = this;
            var select = this.element.hide();
            var input = $("<input>")
                    .insertAfter(select)
                    .width(300)
                    .autocomplete({
                        source: function(request, response) {

                            var jsonbox = { gem_query: request.term };
                            lastTerm = request.term;

                            $.post("/" + $.trim(window.location.pathname.substr(1, 9)) + "/Gemeenten/FilterInstGem/", jsonbox, function donedit(data) {
                                //alert("iets");
                                if (data.succes == true && data.lastTerm == lastTerm) {
                                //alert(textlength);
                                    //alert(data.lesplaatsen);
                                    response($.map(data.gemeenten, function(item) {

                                        return {
                                            id: item,
                                            //   label: (item.Lpl_Gemeente == null ? "" : item.Lpl_Gemeente) + " - " + item.Lpl_Instelling,
                                            value: item
                                        }
                                    }));
                                } else {
                                    // alert("slecht");
                                }
                            }, "json");
                        },
                        delay: 0,
                        change: function(event, ui) {
                            if (!ui.item) {
                                // remove invalid value, as it didn't match anything
                                $(this).val("");
                                return false;
                            }
                            //alert(ui.item.id);
                            select.val(ui.item.id);
                            self._trigger("selected", event, {
                                item: select.find("[value='" + ui.item.id + "']")
                            });
                        },
                        focus: function() {
                            focushelper = true;
                        },
                        minLength: 2
                    })
                    .addClass("ui-widget ui-widget-content ui-corner-left")
                    .focus(function() {             //if it is default value, remove it.
                        if (select.val() == "" && !focushelper) {
                            //alert(select.val());
                            $(input).val("");
                        }
                    })
                    .val(select.find("option:selected").text()); //return selected value for editing

        }
    });

})(jQuery);

The problem was that I return a long list of items, and when I write inside the input field to filter, like

"gen" it would do a post for "g" for "ge" and for "gen" because it posts on every change. The problem was that the last return of the list was not always for "gen" but sometimes for "ge" so, my result was not correct.

using a delay did not change anything.

using minlength does not matter, once it's more than the minlength the problem occurs again.

so what did I do? I used var lastTerm to check on receiving my list, if this result is for the last term written, and not for one in the middle.

this does fix my problem, but it's not the nicest thing.

Is there a way to just halt the post, so I don't waste a load of server resources since the results for not the last term, are discarded anyway.

the MVC part:

    [HttpPost]
    public ActionResult FilterInstGem(string gem_query) {
        List<string> lpls = _db.InstellingAdressens.Where(l => l.GEMEENTE.Contains(gem_query)).Select(q => q.GEMEENTE).Distinct().OrderBy(q => q).ToList();
        return Json(new { succes = true, lastTerm = gem_query, gemeenten = lpls });
    }

the total thing looks like: http://jqueryui.com/demos/autocomplete/#combobox

+1  A: 

Since $.post() returns the XmlHttpRequest you can save a reference to it and abort it, like this:

if(this.xhr) this.xhr.abort();
this.xhr = $.post("/" + $.trim(window.location.pathname.substr(1, 9)) + "/Gemeenten/FilterInstGem/", jsonbox, function donedit(data) {
  this.xhr = null;
  //rest of your current post success code....
});

By placing these where you currently have just

$.post("/" + $.trim(window.location.pathname.substr(1, 9)) + "/Gemeenten/FilterInstGem/", jsonbox, function donedit(data) {

You're storing the reference to the request...if a request comes in successfully (before another's fired) it'll abort the last request, if it's not interrupted and completes, it'll execute the success callback you already have, setting this.xhr = null; so we know there's nothing to abort next time.

Nick Craver
as always the perfect solution. well explained. thanks!
Stefanvds