0

I am trying to use jQuery AutoComplete for a client / customer selection input field - on a simple test HTML page (that I plan to enhance, once the AJAX part is working).

I have copied (verbatim) the JQuery sample JavaScript from https://jqueryui.com/autocomplete/#remote-jsonp and the only change I have made to this is the "#..." ID name, and the URL value in the "source" definition.

The back-end server (which is running Django) receives requests from the JavaScript fine, and seems to generate the JSON callback string correctly. Here is its output:

curl http://localhost:52974/AjaxClientAutocomplete/?term=Adm

[ {label: "ADMAC", value: "109"}, {label: "Administration Software L", value: "110"}, {label: "Adminsoft - Office Rental", value: "111"}, {label: "Adminsoft - Reimburse Int", value: "112"}, {label: "Adminsoft - Royalties", value: "113"}, {label: "adminsoftware.biz", value: "114"}, {label: "Admiral Word Publishing B", value: "115"} ]

Using the developer tools on my browser, I have copied the HTML that the DOM sees into a test HTML file on my hard drive. I have cut this back to the bare essentials, and made several variants to test what works and what doesn't.

Using a local variable as the AutoComplete "source:" works fine - including with it being an array of objects as per the full string shown above (copy-and-pasted into the JavaScript).

So in summary:

  • The JavaScript (shown below) seems to be sending requests to the server OK.
  • The server is receiving these and responding - seemingly with a correct JSONP response.
  • The JavaScript just doesn't seem to process this and update its source label / value list, so it can use this (like it does successfully, when the "source:" is a variable with the same object list).
  • Or is it a problem with the JSONP response? (Notes: I have tried adding quotes around the "label" and "value" keys, without success. This exact text works perfectly when pasted into the JavaScipt as the value for a variable, which was used as the AutoComplete "source:" instead of the AJAX function.)

I am fairly new to this technical area, and can't think of anything else to try. Can anyone see what I am missing? Here is the JavaScript:

// AjaxClientAutocomplete.js        Created by GE on 16 May 2020
// Expects Django to handle the AJAX request being made using an HTTP GET to an URL of "/AjaxClientAutocomplete/"
//      The search string will be passed in a parameter named "term"
// The Django HTML template must give the input field an ID of "idClientName":  e.g. <input type="text" name="ClientName" id="idClientName">
// It also should have a an HTML element with id="log" which will accept the output from the "log()" function - which will be disabled once working.

$(function () {
    function log(message) {
        $("<div>").text(message).prependTo("#log");
        $("#log").scrollTop(0);
    }

    $("#idClientName").autocomplete({
        source: function (request, response) {
            $.ajax({
                url: "/AjaxClientAutocomplete/",
                dataType: "jsonp",
                data: {
                    term: request.term
                },
                success: function (data) {
                    response(data);
                }
            });
        },
        minLength: 2,
        select: function (event, ui) {
            log("Selected: " + ui.item.value + " aka " + ui.item.id);
        }
    });
});

And here is the relevant portion of the HTML template:

<form action="" method="get">
    {% csrf_token %}
    <div class="ui-widget">
        <label for="ClientName">Client Name Search: </label>
        <input type="text" name="ClientName" id="idClientName">
    </div>
    <input type="submit" value="Go">
</form>

<div class="ui-widget" style="margin-top:2em; font-family:Arial">
    Result:
    <div id="log" style="height: 200px; width: 300px; overflow: auto;" class="ui-widget-content"></div>
</div>
Graeme
  • 43
  • 1
  • 8
  • Hope this helps you https://stackoverflow.com/questions/9656523/jquery-autocomplete-with-callback-ajax-json – prathameshk73 May 16 '20 at 10:45
  • Thanks for this link. It gave some interesting wider background reading. However, unfortunately it didn't actually solve the problem I was getting. – Graeme May 20 '20 at 01:43

1 Answers1

0

I have finally cracked this - with the help of a friend (Paul Hutcheon) who has significant experience with front-end development.

We tried a number of things, but were completely unable to get it to work using the ".ajax()" and "jsonp" methodology, as per the sample source code at https://jqueryui.com/autocomplete/#remote-jsonp.

However, it works perfectly using the jQuery ".getJSON()" shorthand method (which is a bit simpler, anyway).

Here is the new ".getJSON()" JavaScript in the hope that it is useful to others:

// AjaxClientAutocomplete.js        Created by GE on 16 May 2020
// 20 May 20:  Modified (with help from Paul Hutcheon) to use JQuery's ".getJSON()" function, which is a wrapper for ".ajax()"
// Expects Django to handle the AJAX request being made using an HTTP GET to an URL of "/AjaxClientAutocomplete/"
//      The search string will be passed in a parameter named "term", which has the search string
// The Django HTML template must give the input field an ID of "idClientName":  e.g. <input type="text" name="ClientName" id="idClientName">
// It also should have a an HTML element with id="log", which will accept the output from the "log()" function - This will be disabled once working.

$(function () {
    $("#idClientName").autocomplete({
        source: function (request, response) {
            $.getJSON("/AjaxClientAutocomplete/", {
                NameStartsWith: request.term
            }, response);
        },
        minLength: 2,
        select: function (event, ui) {
            event.preventDefault();
            $(this).val(ui.item.label);
            log(ui.item ?
                "Selected: " + ui.item.label :
                "Nothing selected, input was " + this.value);
        },
        focus: function (event, ui) {
            event.preventDefault();
            $(this).val(ui.item.label);
        }
    });
});

You may observe that we have replaced the original "term:" with "NameStartsWith:". Hopefully, this helps people understand the ".getJSON()" shorthand better. But it also gives a more meaningful key name in the request that is sent to the server. This lets us add other search options (e.g. "Name contains", "Address contains", and "Phone contains") to the search form, and handle them all in a single JavaScript and server request.

The extra code in the "select:" and "focus:" events are not necessary if the server response is merely a list of values. However, it is needed in our case, because the response from the server is a list of label/value pairs, giving the matching clients' name and primary key value (integer). The extra code ensures that the name is always displayed for the current / selected input item (rather than the primary key - which is still returned correctly as the value for this field, when the form is eventually submitted).

We also made a change at the server end, so that it returns a true JSON response (with quotes around the object names too), rather than the "jsonp" format (in my original question, which worked in another example I followed, where the "source:" was a variable). The server's JSON response, for a search string of "adm", is now: [ {"label": "ADMAC", "value": "109"}, {"label": "Administration Software L", "value": "110"}, {"label": "Adminsoft - Office Rental", "value": "111"}, {"label": "Adminsoft - Reimburse Int", "value": "112"}, {"label": "Adminsoft - Royalties", "value": "113"}, {"label": "adminsoftware.biz", "value": "114"}, {"label": "Admiral Word Publishing B", "value": "115"} ]

Anyway, I hope this is helpful to someone.

Graeme
  • 43
  • 1
  • 8