.Net Select / Select2 淘汰 javascript - 如果初始值不在下拉列表中,则无法加载它们

Posted

技术标签:

【中文标题】.Net Select / Select2 淘汰 javascript - 如果初始值不在下拉列表中,则无法加载它们【英文标题】:.Net Select / Select2 knockout javascript - Cannot load initial values if they are not within the dropdown list 【发布时间】:2020-05-07 13:40:17 【问题描述】:

我想要一些关于“组合”框的 Select /Select2 功能的帮助,我试图在 .Net 中使用敲除/jquery 进行设置。我需要用一组值预加载这个“组合”框,然后允许用户添加额外的(从下拉列表中选择或输入其他内容)或删除条目。只要预加载到“组合”框的值存在于协调下拉列表(所有用户)中,下面的代码就可以正常工作。如果下拉列表中不存在预加载的值,它们会被简单地绕过。

还有其他人必须处理这个问题吗?你是怎么克服的?我将不胜感激任何反馈或想法!

<select data-bind="selectedOptions: newMessageTo, optionsCaption: 'Select a user...', 
    options: allUsers, optionsText: 'userName', optionsValue: 'userName', 
    select2:  placeholder: 'Select a user...', allowClear: true, multiple: true, 
    minimumInputLength: 3, tags: true, minimumResultsForSearch: 20 ">
</select>
self.myMessage = ko.observable();
self.myMessageText = ko.observable("");
self.messageId = ko.observable();
self.newMessageText = ko.observable("");
self.newMessageTo = ko.observableArray([]);
self.newMessageSubject = ko.observable("");
self.newAttachment = ko.observable();
self.newAttachmentList = ko.observableArray([]);
self.allUsers = ko.observable();
self.bearer = ko.observable();
self.newStyleAttachments = ko.observable(false);

self.replyAll = function () 
    self.replying() ? self.replying(false) : self.replying(true);
    self.newMessageTo.removeAll();
    for (var i = 0; i < self.myMessage().cc.length; i++) 
        if (self.myMessage().cc[i] !== self.user.email) 
            self.newMessageTo.push(self.myMessage().cc[i]);
        
    
    self.newMessageTo.push(self.myMessage().senderEmail);
    self.newMessageText("<br/><center>-------------------------------------------</center><br/> \
        <b>From:</b> " + self.myMessage().senderEmail + " <br/><b>To:</b> " + self.myMessage().cc + " \
        <br/><b>Subject:</b> " + self.myMessage().messageSubject + "<br/>" + self.myMessageText());
    self.newMessageSubject("RE: " + self.myMessage().messageSubject);
;
ko.bindingHandlers.select2 = 
    init: function (el, valueAccessor, allBindingsAccessor, viewModel) 
        ko.utils.domNodeDisposal.addDisposeCallback(el, function () 
            $(el).select2('destroy');
        );

        var allBindings = allBindingsAccessor(),
            select2 = ko.utils.unwrapObservable(allBindings.select2);

        $(el).select2(select2);
    ,
    update: function (el, valueAccessor, allBindingsAccessor, viewModel) 
        var allBindings = allBindingsAccessor();

        if ("value" in allBindings) 
            if ((allBindings.select2.multiple || el.multiple) && allBindings.value().constructor != Array) 
                $(el).val(allBindings.value().split(',')).change();
            
            else 
                $(el).val(allBindings.value()).change();
            
         else if ("selectedOptions" in allBindings) 
            var converted = [];
            var textAccessor = function (value)  return value; ;
            if ("optionsText" in allBindings) 
                textAccessor = function (value) 
                    var valueAccessor = function (item)  return item; 
                    if ("optionsValue" in allBindings) 
                        valueAccessor = function (item)  return item[allBindings.optionsValue]; 
                    
                    var items = $.grep(allBindings.options(), function (e)  return valueAccessor(e) == value );
                    if (items.length == 0 || items.length > 1) 
                        return "UNKNOWN";
                    
                    return items[0][allBindings.optionsText];
                
            
            $.each(allBindings.selectedOptions(), function (key, value) 
                converted.push( id: value, text: textAccessor(value) );
            );
            $(el).select2("data", converted);
        
        $(el).change();
    
;

【问题讨论】:

然后允许用户添加其他内容(从下拉列表中选择或输入其他内容)或删除条目 - 让我们关注粗体部分:据我了解,您有 2 个下拉菜单:一个您在此处提供的 html(使用 select2);另一个有一些onChange 处理程序,它采用其选定的值并将它们添加到第一个。您可以将该代码添加到您的问题中吗? 您好@HeyJude,感谢您的回复。我只使用了一个下拉菜单,但是当屏幕出现时,选择是预先填充的。用户可以通过从下拉列表中选择某些内容或键入不在下拉列表中的内容来删除预填充的选择和/或添加新值。发生的问题是,当从值数组填充“选择”框时,如果在下拉列表中不存在其中一个值,则在“选择”框中不会显示该值。我希望这是有道理的:-) 我不确定什么是“选择”,所以让我们更准确一点,只使用术语“选项”和“值”。所以,如果我又错了,请纠正我:你有一个下拉列表,预先填充了多个 options 和多个 values,并且用户或代码可以通过从现有的 options 中进行选择或在其中输入一些内容(在这种情况下,同时添加 option 和 value)来添加更多 values。现在,一些代码将 values 作为现有 options 添加到您的下拉列表中,这些 values 是不显示。我说对了吗? @HeyJude,是的,我想你明白了! 太好了,我编辑了我的答案以匹配您的用例。将代码与您的代码进行比较,看看哪里出了问题。 【参考方案1】:

我的猜测是,这与您的 select2 淘汰赛绑定(问题中不存在)有关。

以下是一个使用非常简单的绑定处理程序的工作示例,取自here。只需运行代码 sn-p,它会使用 2 个选项和 1 个值预先填充下拉列表,然后(5 秒后)向其中添加 2 个值 - 一个作为选项存在,一个不存在(因此是也作为新选项添加​​):

$(document).ready(function () 
  registerBinding();
  run();
);

var vm = function () 
  var self = this;
  self.available = ko.observableArray(['John', 'Joe']);
  self.selected = ko.observableArray(['John']);
  self.add = function (otherUsers) 
    otherUsers.forEach(function (otherUser) 
        var matchedAvailable = self.match(self.available(), otherUser);
        var matchedSelected = self.match(self.selected(), otherUser);
        if (!matchedAvailable) 
            self.available.push(otherUser);
        
        if (!matchedSelected) 
            self.selected.push(otherUser);
        
    );
  ;
  self.match = function (users, userToMatch) 
      var matched = ko.utils.arrayFirst(users, function (user) 
          return user == userToMatch;
      );
      return matched;
  ;
;

function run() 
  var vmInstance = new vm();
  ko.applyBindings(vmInstance);
  setTimeout(function () 
    vmInstance.add(['Jane', 'Joe']);
  , 5000);


function registerBinding() 
  ko.bindingHandlers.select2 = 
      after: ["options", "value"],
      init: function (el, valueAccessor, allBindingsAccessor, viewModel) 
          $(el).select2(ko.unwrap(valueAccessor()));
          ko.utils.domNodeDisposal.addDisposeCallback(el, function () 
              $(el).select2('destroy');
          );
      ,
      update: function (el, valueAccessor, allBindingsAccessor, viewModel) 
          var allBindings = allBindingsAccessor();
          var select2 = $(el).data("select2");
          if ("value" in allBindings) 
              var newValue = "" + ko.unwrap(allBindings.value);
              if ((allBindings.select2.multiple || el.multiple) && newValue.constructor !== Array) 
                  select2.val([newValue.split(",")]);
              
              else 
                  select2.val([newValue]);
              
          
      
  
;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.12/js/select2.full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.12/css/select2.min.css" />

<div class="col-xs-4">
    <label for="users">Users</label>
    <select id="users" class="form-control"
            multiple="multiple"
            data-bind="options: available,
                selectedOptions: selected,
                select2:  placeholder: 'Select an option...', allowClear: true ">
    </select>
</div>

【讨论】:

我仍然没有让 select2 工作!问题是选择框选项绑定到一个数组,该数组包含下拉列表中可用的所有 id 和值。 SelectedOptions 绑定到一个数组,该数组包含 SelectedOptions 中可能不存在的值列表。如果 selectedOption 不在 Options 数组中,则 SelectedOptions 中的值不会显示在选择框中 绑定到options 的数组是唯一一个其项目在下拉列表中显示为选项的数组。因此,如果您在绑定到selectedOptions 的数组中添加一个项目,而没有将此项目添加到绑定到options 的数组中first,它将不会显示。

以上是关于.Net Select / Select2 淘汰 javascript - 如果初始值不在下拉列表中,则无法加载它们的主要内容,如果未能解决你的问题,请参考以下文章

将 select2 与淘汰赛绑定

带有 ajax 的淘汰赛3+select2 (v4)

在 jQuery 对话框中淘汰 'with' 绑定和 select2

Select2 用字符串覆盖淘汰赛 observableArray

带有淘汰赛的Select2如何在选择中显示选定的项目?

Select2 在淘汰赛中选择标签作为对象而不是“id”