Search code examples
javascriptjquerybootstrap-4comboboxbootstrap-select

Bootstrap Select Editable Combobox Hack


How can I let my users add their own options to bootstrap-select?

Hello. After spending some time trying to find a simple solution that works with bootstrap 4 styling, including looking at the offered solutions and dead threads waiting on this open issue: https://github.com/snapappointments/bootstrap-select/issues/990, I decided to roll my own.

The following solution relies on the live-search option to be enabled on the bootstrap-select element. It uses the live search field to add the user-typed, custom value to the list of options. It is a hacky solution and not the prettiest thing, but maybe this concept could be directly integrated into bootstrap select to finally solve issue 990.


Solution

  • Let the user add their own values to a bootstrap-select live-search capable selector

    Just add this code to your page. Replace (yourselector) with your selector. For my project, I just wanted any selectpicker element that wasn't multiple capable, so I used .selectpicker:not([multiple]).

    var newOption;
    $(document).ready(function () {
        //Custom editable combobox
        $(document).on("loaded.bs.select", "(yourselector)", function (e, clickedIndex, isSelected, previousValue) {
            newOption = ""; //Reset newOption before doing a new search
            $(e.currentTarget).siblings(".dropdown-menu").on('keyup', '.bs-searchbox input', function (ie) {
                //if more than one and search is 0 characters, continue. If more than one and search is 1 character and character doesn't match first character of newValue, delete newValue.
                //If 1 and class is "no-results", delete old newValue and add newValue.
                console.log("running keyup script for " + e.currentTarget.id);
    
                var searchList = $(e.currentTarget).siblings("div.dropdown-menu ul.dropdown-menu li");
                var searchPhrase = $(ie.currentTarget).val();
    
                //Something was found
                if (searchList.length > 0 && !$(searchList[0]).hasClass("no-results")) {
                    //new search
                    if (searchPhrase.length == 0)
                        return;
                    else {
                        //they haven't started searching the same phrase again
                        if (newOption && newOption.toLowerCase().indexOf(searchPhrase.toLowerCase()) < 0) {
                            console.log("newOption: " + newOption + "\nsearchPhrase: " + searchPhrase + "\nSubstring?: " + newOption.toLowerCase().indexOf(searchPhrase.toLowerCase()));
                            //delete newOption from options list and reset
                            $("#" + e.currentTarget.id + " option[value='" + newOption + "']").remove();
                            newOption = "";
                            $(e.currentTarget).selectpicker("refresh");
                            $(ie.currentTarget).trigger('propertychange');
                        }
                    }
                }
                //Nothing was found
                else {
                    $("#" + e.currentTarget.id + " option[value='" + newOption + "']").remove();
                    newOption = searchPhrase;
                    $(e.currentTarget).append($('<option>').val(searchPhrase).text(searchPhrase));
                    $(e.currentTarget).selectpicker("refresh");
                    $(ie.currentTarget).trigger('propertychange');
                }
            })
        });
        $(".selectpicker").on("changed.bs.select", function (e, clickedIndex, newValue, oldValue) {
            newOption = ""; //Reset newOption before doing a new search
        });
    });