使用 jquery select2 插件时,如果已列出 ajax 调用中的有效值,如何防止选择新标签?

Posted

技术标签:

【中文标题】使用 jquery select2 插件时,如果已列出 ajax 调用中的有效值,如何防止选择新标签?【英文标题】:When using jquery select2 plugin, how can I prevent new tags from being chosen if there is a valid value from the ajax call already listed? 【发布时间】:2015-12-30 19:06:24 【问题描述】:

我正在使用带有多项选择的select2 version 4,我支持用户添加新标签,但如果我的后端已经存在该标签,我想阻止人们选择新标签。

现在如果用户输入一个已经存在的标签并且我有 tags:true 那么它会在下拉列表中显示两个项目(现有的和新的)。这是一个例子:

如您所见,“testTag2”是来自我的后端的有效标签,因此它显示在选择中,但由于 templateResult 功能和 tags:true 它还显示为第二项(让用户认为他们可以选择它作为新标签)。

如果下拉列表中没有作为另一个选项列出该文本,是否只在下拉列表中显示“NEW”标签选项

这是我的 javascript 代码:

function SetupAppTags() 
$("#Tags").select2(
    theme: "classic",
    width: "98%",
    tags: true,
    ajax: 
        url: "/Tag/Search",
        dataType: 'json',
        delay: 300,
        data: function(params) 
            return  q: params.term ;
        ,
        processResults: function(data, params) 
            return  results: data ;
        ,
        cache: false
    ,
    escapeMarkup: function(markup)  return markup; ,
    minimumInputLength: 3,
    templateResult: tagFormatResult,
    templateSelection: tagSelectionResult
);


 function tagFormatResult(tag) 

if (tag.loading) 
    return "Loading . . . <img src='/Content/Images/ajax-loader.gif' />";
 else 

    if (tag.name) 
        var existsAlready = $("#Tags option[value='" + tag.id + "']").length > 0;
        if (existsAlready) 
            return null;
        
        return tag.name;
    

    var length = $('#tagsContainer .select2-selection__choice').filter(function () 
        return $(this).attr("title").toUpperCase() === person.text.toUpperCase();
    ).length;

    if (length == 1) 
        return null;
    
    return tag.text + " [NEW]";

【问题讨论】:

你可以为此创建一个小提琴吗?如果无法使用 Ajax,那么即使是简单的数据数组也足够了。 【参考方案1】:

根据Select2 Options

更改搜索时选项的匹配方式当用户向下过滤时 通过在搜索框中输入搜索词得到结果,Select2 使用 一个内部“匹配器”,用于将搜索词与结果匹配。当一个遥控器 使用数据集,Select2 期望返回的结果有 已被过滤。

Key matcher Value 获取搜索参数和数据对象的函数。 Select2 将传递已传递的单个数据对象 从数据适配器返回到匹配器分别确定 如果它们应该显示。只有第一级对象将 传入,所以如果你正在处理嵌套数据,你需要匹配 那些单独的。

matcher: function (params, data) 
  // If there are no search terms, return all of the data
  if ($.trim(params.term) === '') 
    return data;
  

  // `params.term` should be the term that is used for searching
  // `data.text` is the text that is displayed for the data object
  if (data.text.indexOf(params.term) > -1) 
    var modifiedData = $.extend(, data, true);
    modifiedData.text += ' (matched)';

    // You can return modified objects from here
    // This includes matching the `children` how you want in nested data sets
    return modifiedData;
  

  // Return `null` if the term should not be displayed
  return null;

我认为这是您的典型案例,除了您应该将 ("matched") 替换为 ("") ,并添加 else 以在您的案例中添加“[NEW]”。

ajax 调用返回的数据应该是匹配器的输入。

因此您的代码应如下所示:

  matcher: function (params, data) 
  // If there are no search terms, return all of the data
  if ($.trim(params.term) === '') 
    return data;
  

  // `params.term` should be the term that is used for searching
  // `data.text` is the text that is displayed for the data object
  if (data.text.indexOf(params.term) > -1) 
    var modifiedData = $.extend(, data, true);
   //match was found then just show it.
   // modifiedData.text += ' (matched)';

    // You can return modified objects from here
    // This includes matching the `children` how you want in nested data sets
    return modifiedData;
  
   else
  
   //there is not match found , suggest adding NEW Tag.
    modifiedData.text += '[NEW]';
    return modifiedData;
  

  // Return `null` if the term should not be displayed
  return null;

【讨论】:

【参考方案2】:

如果我误解了您的问题,请纠正我。但据我了解,我想出了以下解决方案。

出于演示目的,我在&lt;select&gt; 框中预加载了几个&lt;option&gt; 元素,而不是ajax 数据馈送到select2 我使用的是普通的JavaScript array 对象模仿ajax 响应。

更新的小提琴链接:https://jsfiddle.net/vijayP/akyzt9Ld/11/

html如下:

<div id="tagsContainer">
    <select id="Tags" multiple="" name="Tags">
       <option value="white">white</option>
       <option value="green">green</option>
    </select>
</div> 

在这里我们可以看到,下拉列表中的最后一个&lt;option&gt; 包含文本green

模仿 ajax 响应的 JSON data 对象如下所示:

var data = [ id: 0, name:'yellow', text: 'yellow' , 
                 id: 1, name:'green', text: 'green' , 
                 id: 2, name:'cyan', text: 'cyan' , 
                 id: 3, name:'violet', text: 'violet' , 
                 id: 4, name:'gray', text: 'gray' 
                ];

green 再次位于第 2 位。

select2 初始化和支持 JavaScript 代码如下:

    var uniqueTexts = null; //array for holding unique text
    $("#Tags").select2(
        tags: true,
        data: data,
        templateResult: tagFormatResult,
        escapeMarkup: function (markup)  
            uniqueTexts = null; 
            return markup; 
        , 
        matcher: function (params, data) 
            if(!uniqueTexts)
                uniqueTexts = []; 
            
            var modifiedData = null;

            if ($.trim(params.term) === '' || data.text.indexOf(params.term) > -1) 
                if(uniqueTexts.indexOf(data.text) == -1)
                
                    modifiedData = data;
                    uniqueTexts.push(modifiedData.text);
                
            

            if(modifiedData)
            
                return modifiedData;
            

            return null;
        
    );

    function tagFormatResult(tag) 
        if (tag.loading) 
            return "Loading . . . <img src='/Content/Images/ajax-loader.gif' />";
         
        else 
        
            var length = $('#tagsContainer .select2-selection__choice').filter(function () 
                return $(this).attr("title").toUpperCase() === tag.text.toUpperCase();
            ).length;

            if (length == 1) 
                return tag.text;
            

            if (tag.text) 

                if(getOptionCount(tag.text) >1)
                    return tag.text;
                else
                    return tag.text + " [NEW]";
            
            return tag.text + " [NEW]";
        
    

    function getOptionCount(tagText)
    
        var count = 0;
        var selectBoxOptions = $("#Tags option");
        $(selectBoxOptions).each(function()
            if(tagText == $(this).text())
                count++;//increment the counter if option text is matching with tag text
        );
        return count;
    

var uniqueTexts 是一个数组,用于保存要显示给最终用户的唯一文本。在启动时,我们将其设置为null。所以这个想法是每当用户关注选择框或输入搜索关键字时;为每个选项调用matcher: 回调。我们检查每个选项,看看它是否已经存在于uniqueTexts[] 中。如果它是第一次出现,那么我们允许它显示;否则我们返回null 以避免它第二次显示。

我还添加了一个escapeMarkup: 回调处理程序,只要向最终用户显示选项,就会调用它。这时我们可以再次将uniqueTexts 设置为null。这是完整的一轮循环。用户可以再次聚焦或输入选择框。

function tagFormatResult(tag) 的工作原理如下:

1) 首先检查当前标签是否已经被选中。如果它已被选中,则不要将 "[NEW]" 文本添加到 tag.text

2) 其次,它检查当前tag.text 是否多次以select option 文本出现。如果它出现在多个地方,那么也不要将 "[NEW]" 添加到tag.text

3) 在所有其他情况下,将 "[NEW]" 添加到 tag.text

我希望这会对你有所帮助。 更新链接:https://jsfiddle.net/vijayP/akyzt9Ld/11/

【讨论】:

如果我输入标签“绿色”,然后再次输入绿色,我会在下拉列表中看到两个选项都显示“绿色”。这似乎没有回答这个问题。我的目标是只显示一个项目并且在下拉列表中没有重复项 @leora,我会在下周检查它。 @leora。更新了答案。请看一下。

以上是关于使用 jquery select2 插件时,如果已列出 ajax 调用中的有效值,如何防止选择新标签?的主要内容,如果未能解决你的问题,请参考以下文章

删除 Select2 Jquery 插件中的默认选择

select2 jquery插件重置具有预选项目的选择元素

select2 插件和 jquery ui 模式对话框

Select2 jquery插件在结果中显示所选项目的数量而不是标签

select2插件的使用

当不在 jquery 模态对话框中时,select2 插件可以正常工作