Inserting an html button as the last element of a jquery ui autocomplete list
Asked Answered
S

1

6

I have been trying to insert an html button as the last element of an jquery ui autocomplete list. The button is supposed to open a popup window with the option of adding a new element to the autocomplete list. This is the code which inserts the button inside the autocomplete list:

data.push({label: '<input type="button" name="btn_name_field" id="btn_name_field" title="Create" class="button firstChild" value="Add new">'});
response(data);

This is the function that opens the popup:

$(document).on("click", "#btn_name_field", function () {
    open_popup("Street_Address", 400, 180, "", true, false,  {"call_back_function":"set_return","form_name":"EditView"}, "single", true );
});

In order to be able to insert the html inside as a "label", I had to use this function:

$[ "ui" ][ "autocomplete" ].prototype["_renderItem"] = function( ul, item) {
return $( "<li></li>" ) 
  .data( "item.autocomplete", item )
  .append( $( "<a></a>" ).html( item.label ) )
  .appendTo( ul );
};

What happens is: The button appears fine and does what it is supposed to (opens a popup window) However after opening the popup window all the code from the html input gets inserted into the textbox. This is the logical behaviour, since the code is inserted as a label, but would anybody know what would be the best way to insert an html button as the last element of the autocomplete?

Thanks in advance

Shikari answered 15/1, 2013 at 11:29 Comment(1)
Welcome to StackOverflow! Thanks for posting a well formed, useful question!Hildebrandt
H
4

If you're using jQueryUI >= 1.9, this seems like a good job for the response callback. This callback is called right after the source array is populated, but before the items are displayed to the user. You can leverage this event to push a new "button" object on your array of suggestions.

This "button" object has a label property that's the HTML of the button you're going to add, and it also has a button property that's set to true. You can use this property to cancel the default action of the select event:

$.ui.autocomplete.prototype._renderItem = function (ul, item) {
    return $("<li></li>")
        .data("item.autocomplete", item)
        .append($("<a></a>").html(item.label))
        .appendTo(ul);
};

$("#auto").autocomplete({
    source: /* source */
    response: function (event, ui) {
        // Add the "button" object to the list of suggestions:
        ui.content.push({
            label: "<input type='button' value='click me' class='mybutton' />",
            button: true
        });
    },
    select: function (event, ui) {
        // If this is the button, don't populate the <input>
        if (ui.item.button) {
            event.preventDefault();
        }
    }
});

Also, I would recommend using a delegated event handler instead of writing your event handling code inside of the markup you're generating for the button. One way to do this is to give your button a class (I've used .mybutton in the example), and write a delegated event handler using on:

$(document).on("click", ".mybutton", function () {
    alert('clicked!');
});

Here's a working example: http://jsfiddle.net/J5rVP/35/

Hildebrandt answered 15/1, 2013 at 14:56 Comment(14)
Thank you very much for your response. The idea is beautiful, but I am probably doing something wrong because the button does not get displayed. This is my implementation of the response callback: response(data, function (event, ui) { ui.content.push({ label: "<input type='button' value='click me' class='mybutton' />", button: true }); });Shikari
What version of jQueryUI are you using?Hildebrandt
I tried your suggestion here but being a complete noob in Javascript I fail to see why is it not working. Could anybody please helpShikari
@Sitalk: What's not working exactly? Do you see any errors in the console?Hildebrandt
I added the response callback like this: response(data, function (event, ui) { ui.content.push({ label: "<input type='button' value='click me' class='mybutton' />", button: true }); }); But now the button does not show at all. But now the button does not show at all.Shikari
Look closely at the answer code--there's a difference between the response callback passed to the source option and the response event that's called when the autocomplete widget loads results.Hildebrandt
Thanks for your tip. This is where the example of my implementation is. Somehow the button simply does not show up. The error console does not show anything. Since your example worked on jsfiddle.net, there must be a problem with something else inside my code.Shikari
All the data is showing properly, only the button is missing.Shikari
Looks like in the pastebin you aren't using the same version of _renderItem that I am.Hildebrandt
Thank you for the wonderful tip... Sorry about my negligence, I should have noticed that earlier. Here are some other changes I have made to the code. Ufortunately the button is still not showing. Maybe the reason is because I am "pushing" the button html code straight inside the "data" array, while you are "pushing" it inside the "content". Not sure if this is the problem, but the result is that the "button" does not appear inside the autocomplete data array. ThanksShikari
I think it looks okay now. Are you absolutely sure you're using version 1.9.2 of jQueryUI? This won't work with a version earlier than 1.9.Hildebrandt
Thanks for your reply Andrew... I am glad you asked me that because it made me look deeper into the source code generated by SugarCRM (the CRM platform I am trying to customize). Apparently the html showed that jQueryUI 1.8.16 was included first and then jQueryUI 1.9.2 (which I included by hand). Should have noticed that long time ago... Since upgrading the jQueryUI for SugarCRM might not be upgrade-safe, so I am stuck with the option of using jQueryUI 1.8.16 and your elegant solution would not work for this version... Sorry about wasting your time.Shikari
Since the response callback is missing from jQueryUI 1.8.16, what would be the best alternative?Shikari
@Sitalk: In that case you can use the source option and pass a callback. I'll create an example.Hildebrandt

© 2022 - 2024 — McMap. All rights reserved.