允许使用 selected.js 多选的新值

Posted

技术标签:

【中文标题】允许使用 selected.js 多选的新值【英文标题】:allow new values with chosen.js multiple select 【发布时间】:2011-11-15 03:52:42 【问题描述】:

我正在使用 selected.js 插件 http://harvesthq.github.com/chosen/ 和 jQuery,以允许用户从一个选择中选择多个选项。但是,我现在希望能够让他们创建 尚不存在的值 - 知道如何去做吗?

编辑:类似于 SO 自己的标签选择/创建栏的东西将接近我所追求的

最好不要更改或编辑插件,但如果需要会这样做。

代码: html

<p>Select something</p>
<select name="theSelect[]" multiple="multiple">
    <option value="First Option">First Option</option>
    <option value="Second Option">Second Option</option>
</select>

javascript

$(function()
    $('select').chosen();
);

因此,如果用户要输入“第三选项”,我想将其添加到列表中并选择它。值和显示名称是 / 将是相同的,所以这不是问题

【问题讨论】:

【参考方案1】:

根据文档,您可以尝试执行以下操作:

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

正如托尼在下面的 cmets 中所说:

“从 1.0 版开始,触发器现在是“选择:更新”。见 harvesthq.github.io/chosen/#change-update-events”

【讨论】:

这是难题之一,但我还需要能够在用户键入列表中不存在的内容时触发它。我现在正在研究源代码:( 或者让他们输入他们想要的任何内容并在提交时检查它是一个更好的主意吗?我注意到这似乎是 SO 所做的 将此标记为已接受,因为我通过在文本框中输入新值来解决问题,并在提交时使用这些命令刷新相应选择 从 1.0 版开始,触发器现在是“选择:更新”。见harvesthq.github.io/chosen/#change-update-events 我知道这是古老的,但我很高兴选择作为标签选择器。为了限制可用标签,我有一个单独的弹出框来管理添加可用标签和编辑/删除旧标签。在弹出窗口中添加新标签时,我将更新已选择以将其显示为新标签选项以供选择。这是我所做的 popver 的 MIlestone 版本的图像i.imgur.com/HVQdyYI.png【参考方案2】:

我偶然发现了这个寻找相同的想法。 似乎它是一个非常受欢迎的功能请求,并且已经有几个分支实现了它。看起来它很快就会被合并到主分支中。

+1 为这个特别的拉动带来了魅力: https://github.com/harvesthq/chosen/pull/166

您可以在此处查看 Koenpunt 的分叉:https://github.com/koenpunt/chosen

【讨论】:

让我试着理解这一点...我下载了 fork 并用它替换了我当前选择的副本。然后我使用 sn-p 将选项添加到您发布的拉取链接中的元素? 或者直接克隆合并后的版本:github.com/koenpunt/chosen 我对此有点困惑。现在我在我网站的很多地方都使用了 selected 。如果我从最后一个链接获取源代码,然后替换我用于我的站点的源代码,它会工作吗?我的意思是,定期选择的更新是否反映在合并/分叉的更新中? 哈哈哈哈不要屏住呼吸任何拉取请求被接受,他们有大量的拉取请求积压,自 4 月下旬以来没有人提交。选择现在显然在他们的优先级列表中非常低。 选项添加不是 Harvest 想要的 Chosen 的一项功能,因为 Chosen 被设计为只是一个选择的视觉/UX 增强,而不是功能。但多年来,我试图让我的分叉与主仓库保持同步。【参考方案3】:

这是我做的一个简单的方法:

$(".search-field").find("input").live( "keydown", function (evt) 
    var stroke;
    stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
    if (stroke == 9)  // 9 = tab key
        $('#tags').append('<option value="' + $(this).val() + '" selected="selected">' + $(this).val() + '</option>');
        $('#tags').trigger('chosen:updated');
    
);

【讨论】:

你基本上只是重新包装了@leogdion的答案。 只有大约三分之一的代码量。这对我来说是一个相当大的进步。 _ref 来自哪里? live 已被 jquery 弃用。 +1 六年后。随着时间的推移,由于 jQuery 的变化而进行了一些调整,这是一个非常巧妙的解决方案。我还添加了if (stroke == 9 **|| stroke == 13**) 来捕获回车键【参考方案4】:

我只是想解决同样的问题。我最后稍微修改了源代码。这是新的 keyup_checker 函数。看一下案例13:

AbstractChosen.prototype.keyup_checker = function(evt) 
  var stroke, _ref;
  stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
  this.search_field_scale();
  switch (stroke) 
    case 8:
      if (this.is_multiple && this.backstroke_length < 1 && this.choices > 0) 
        return this.keydown_backstroke();
       else if (!this.pending_backstroke) 
        this.result_clear_highlight();
        return this.results_search();
      
      break;
    case 13:
      evt.preventDefault();
      if (this.results_showing) 
        if (!this.is_multiple || this.result_highlight) 
          return this.result_select(evt);
          

        $(this.form_field).append('<option>' + $(evt.target).val() + '</option>');
        $(this.form_field).trigger('liszt:updated');
        this.result_highlight = this.search_results.find('li.active-result').last();
        return this.result_select(evt);
       
      break;
    case 27:
      if (this.results_showing) this.results_hide();
      return true;
    case 9:
    case 38:
    case 40:
    case 16:
    case 91:
    case 17:
      break;
    default:
      return this.results_search();
  
;

【讨论】:

【参考方案5】:

我知道这不是答案,而是另一种解决方案。

我正在搜索即时添加部分,发现 http://ivaynberg.github.com/select2/#tags 提供与选择的内容相同的内容以及“标记”等其他内容。

【讨论】:

【参考方案6】:

您可以将一个事件附加到输入文本框以侦听特定的字符代码。之后添加选项并在下拉菜单上触发更新。

 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;
           
        );

【讨论】:

我得到了这个工作,但我必须对 jquery .find() 选择器进行一些调整。第一个必须是“.chzn-container .chzn-search input[type=text]”,第二个必须是“.chzn-drop .chzn-results li.active-result”。我猜可能选择了一些移动的东西,但在更新之后这对我有用。非常感谢。 我还必须更改最后一行以返回 true,以便列表关闭。否则,该项目将添加到列表中,但列表保持打开状态。 @Steve Hiner,我进行了相应的更改。谢谢 我还没有努力解决的一个缺点是代码原样依赖于选项卡或返回键将其添加到列表中。如果用户点击某个东西,那么该值就会丢失。如果他们填写并单击提交按钮并且他们的文本消失了,它会使用户感到困惑。我自己做过几次。我想我可以在文本框上的模糊事件中捕捉到这一点。 我发现虽然这段代码有效,但也不是没有问题。例如,您不能真正编辑现有条目,也不能键入类似条目,因为它会自动从列表中选择条目。我最终改用 Twitter 的 typeahead,它对我的​​目的非常有效。【参考方案7】:

对 leogdion 答案的更新,适用于选择的更高版本:

        var dropDown = $('#select_chosen');
        // Make the chosen drop-down dynamic. If a given option is not in the list, the user can still add it
        dropDown.parent().find('.chosen-container .search-field input[type=text]').keydown( 
            function (evt) 
               var stroke, _ref, target, list;
               // get keycode
               stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
               // If enter or tab key
               if (stroke === 9 || stroke === 13) 
                   target = $(evt.target);               
                   // get the list of current options
                   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
                   matchList = target.parents('.chosen-container').find('.chosen-results li').map(function ()  return $(this).text(); ).get();
                   // highlighted option
                   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
                   var 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)
                     var newOption = '<option value="' + newString + '">' + newString + '</option>';
                     $("#select").prepend(newOption);
                     // trigger the update event
                     $("#select").trigger("chosen:updated");
                     // tell chosen to close the list box
                     $("#select").trigger("chosen:close");
                     return true;
                   
                  // otherwise, just let the event bubble up
                  return true;
               
            
        )

【讨论】:

【参考方案8】:

我再次更新了 3nochroot 的代码。现在我只有一个选择器来查找多选输入。

$(document).ready(function() 
$(".js-choicelist").chosen(
    //config comes here
).parent().find('.chosen-container .search-field input[type=text]').keydown(
    function (evt) 
        var stroke, _ref, target, list;
        // get keycode
        stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
        // If enter or tab key
        if (stroke === 9 || stroke === 13) 
            target = $(evt.target);
            // get the list of current options
            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
            matchList = target.parents('.chosen-container').find('.chosen-results li').map(function ()  return $(this).text(); ).get();
            // highlighted option
            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
            var 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)
                var newOption = '<option value="' + newString + '">' + newString + '</option>';
                var choiceSelect = target.parents('.select-multiple').find('select');
                choiceSelect.prepend(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;
        
    
)

)

【讨论】:

【参考方案9】:

更新多选 (gist) 的 leogdion 答案

  $(".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;
    
  )

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'

【讨论】:

【参考方案10】:

我尝试了这里和其他地方给出的几种解决方案,但是没有一个在 selected.js 1.8.5 (jQuery: 3.3.1) 中有效,所以我最终得到了以下结果,因为我不想使用可能不会始终保持在 master 分支的最新状态:

对于我可能不希望任何.chosen-select 允许新值的情况,我添加了一个新类.chosen-newValuesAllowed。我在此类上设置了一个事件处理程序,其中 CTRL + I 添加新值(如果它尚不存在)。之后输入字段上的焦点不会丢失。在我的示例中,我检查了innerHTML,因为@value 实际上包含数据库ID,因此新值(在我的示例中是稍后将由服务器处理的字符串)永远无法在@value 中找到。如果你想检查@value,请看sn-p里面的注释。 该代码处理单选和多选。

$(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; 

);

另一个解决方案是调用可触发函数chosen:no_results,如果只有在明确没有结果的情况下才应该添加新值:

$(".chosen-select.chosen-newValuesAllowed").on("chosen:no_results", function(e, data)
       var newValue = data.chosen.get_search_text();
       ...
 );

【讨论】:

以上是关于允许使用 selected.js 多选的新值的主要内容,如果未能解决你的问题,请参考以下文章

vb multiselect啥意思

combogrid设置多选,并获取多选的值

带多选的 Select2 下拉菜单

带有多选的 UICollectionView 不会选择十几个项目

Vue实现多选、单选的样式切换

多选的快捷键是啥