allow new values with chosen.js multiple select

后端 未结 10 1964
囚心锁ツ
囚心锁ツ 2020-12-12 19:30

I\'m using the chosen.js plugin http://harvesthq.github.com/chosen/ with jQuery to allow the user to select multiple options from a select. However, I now want to be able to

相关标签:
10条回答
  • 2020-12-12 19:45

    Update of leogdion answer for multiple select (gist)

      $(".chosen-select-with-add-new").chosen({
        no_results_text: "Click Enter or Tab to add new option",
        width: '100%'
      }).parent().find('.chosen-container .search-field input[type=text]').keydown(function (evt) {
        // get keycode
        const stroke = evt.which != null ? evt.which : evt.keyCode;
        // If enter or tab key
        if (stroke === 9 || stroke === 13) {
          const target = $(evt.target);
          // get the list of current options
          const chosenList = target.parents('.chosen-container').find('.chosen-choices li.search-choice > span').map(function () { return $(this).text(); }).get();
          // get the list of matches from the existing drop-down
          const matchList = target.parents('.chosen-container').find('.chosen-results li').map(function () { return $(this).text(); }).get();
          // highlighted option
          const highlightedList = target.parents('.chosen-container').find('.chosen-results li.highlighted').map(function () { return $(this).text(); }).get();
          // Get the value which the user has typed in
          const newString = $.trim(target.val());
          // if the option does not exists, and the text doesn't exactly match an existing option, and there is not an option highlighted in the list
    
          if ($.inArray(newString, matchList) < 0 && $.inArray(newString,chosenList) < 0 && highlightedList.length == 0) {
            // Create a new option and add it to the list (but don't make it selected)
            const newOption = '<option value="' + newString + '" selected="selected">' + newString + '</option>';
            const choiceSelect = target.parents('.chosen-container').siblings('.chosen-select-with-add-new');
            choiceSelect.append(newOption);
            // trigger the update event
            choiceSelect.trigger("chosen:updated");
            // tell chosen to close the list box
            choiceSelect.trigger("chosen:close");
            return true;
          }
          // otherwise, just let the event bubble up
          return true;
        }
      })
    

    Example usage on rails (slim)

      .tag-list
        label.control-label.h5 Tag list
        = select_tag :tag_list, options_for_select(ActsAsTaggableOn::Tag.order('taggings_count desc').pluck(:name), @publication.tags.map(&:name)), multiple: true, data: { placeholder: 'north, east, south, west' }, class: 'chosen-select-with-add-new'
    
    0 讨论(0)
  • 2020-12-12 19:49

    According to the documentation you can try doing something like this:

    $('select').append('<option>test</option>');
    $('select').trigger('liszt:updated');
    

    As Tony stated in the comments below:

    "Starting with version 1.0 which the trigger is now "chosen:updated". See harvesthq.github.io/chosen/#change-update-events"

    0 讨论(0)
  • 2020-12-12 19:54

    I tried several solutions given here and elsewhere, however none worked in chosen.js 1.8.5 (jQuery: 3.3.1) and so I ended up with the following since I didn't want to use a fork that might not always be up-to-date to the master branch:

    For the case that I might not want any .chosen-select to allow new values, I added a new class .chosen-newValuesAllowed. I set an event handler on this class where CTRL + I adds the new value if it is not yet present. The focus on the input field does not get lost afterwards. In my example, I check the innerHTML of the since @value actually contains database ids and therefore the new value, which is a string in my example that would be processed by the server later, could never be found in @value. If you want to check @value, please see the comment inside the snippet. The code handles single and multiple selects.

    $(document).on("keydown", ".chosen-container.chosen-newValuesAllowed input", function(e) { 
    if (e.ctrlKey === true && e.keyCode === 73) { // CTRL + I
        e.preventDefault();
        var newValue = $(this).val();
        if (newValue) {            
            try {
                // only add if there is no option having the content/text of "input" yet!
                // instead of filter() for the content of <option> you can check on its @value by: find("option[val='...']") 
                var $selectElement = $(e.target).closest("div.chosen-container").prev(); // the previous sibling should be the <select>. If not, grab it some other way, e.g. via @id
                if (!$selectElement.find("option").filter(function () { return $(this).html() === newValue; }).length) {
                    if (!$selectElement.attr("multiple")) { // unselect for single-select 
                        $selectElement.val('');
                    }
                    $selectElement.append('<option val="' + newValue + '" selected>' + newValue + '</option>');
                    $selectElement.trigger('chosen:updated');    
                }
            } catch(error) {
                // pass
            }
            e.target.focus();
        }        
        return false; 
    }
    });
    

    Another solution would be to call the triggerable function chosen:no_results if new values should only be added if there explicitly is no result:

    $(".chosen-select.chosen-newValuesAllowed").on("chosen:no_results", function(e, data){
           var newValue = data.chosen.get_search_text();
           ...
     });
    
    0 讨论(0)
  • 2020-12-12 19:55

    You could just attach an event to the input text box to listen for a particular character code. After that add the option and trigger the update on the dropdown.

     var dropDown = $('select.chosen');
     dropDown.parent().find('.chzn-container .chzn-search input[type=text]').keydown( function (evt) {
               var stroke, _ref, target, list;
               // get keycode
               stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
               target = $(evt.target);               
               // get the list of current options
               list = target.parents('.chzn-container').find('.chzn-choices li.search-choice > span').map(function () { return $(this).text(); }).get();
               if (stroke === 9 || stroke === 13) {
                  var value = $.trim(target.val());
                  // if the option does not exists
                  if ($.inArray(value,list) < 0) {
                     var option = $('<option>');
                     option.text(value).val(value).appendTo(dropDown);
                     option.attr('selected','selected');
                     // add the option and set as selected
                  }
                  // trigger the update event
                  dropDown.trigger("liszt:updated");
                  return true;
               }
            });
    
    0 讨论(0)
提交回复
热议问题