48

我正在将 an 转换<input type="hidden">为 select2 下拉列表并通过查询方法为其提供数据

$('#inputhidden').select2({
    query: function( query ) {
        query.callback( data ); // the data is in the format select2 expects and all works well..
    );
});

问题是我需要破解 select2 UI 并在搜索栏顶部放置两个按钮,单击该按钮将执行 ajax 调用,并且必须更新 select2 内容。

在此处输入图像描述

现在,我需要在不完全重建 select2 的情况下进行这些更新,而只是刷新下拉列表中的项目。我找不到将一组新数据传递给已创建的 select2 控件的方法,这可能吗?

4

9 回答 9

55

选择2 v3.x

如果您有带有选项的本地数组(通过 ajax 调用接收),我认为您应该使用data参数作为函数返回选择框的结果:

var pills = [{id:0, text: "red"}, {id:1, text: "blue"}]; 

$('#selectpill').select2({
    placeholder: "Select a pill",
    data: function() { return {results: pills}; }
});

$('#uppercase').click(function() {
    $.each(pills, function(idx, val) {
        pills[idx].text = val.text.toUpperCase();
    });
});
$('#newresults').click(function() {
    pills = [{id:0, text: "white"}, {id:1, text: "black"}];
});

小提琴:http : //jsfiddle.net/RVnfn/576/

如果您使用按钮自定义 select2 界面,只需在更新数据数组(例如药丸)后调用updateResults(此方法不允许从 select2 对象的外部调用,但您可以根据allowedMethods需要将其添加到 select2 中的数组)方法。


select2 v4:自定义数据适配器

updateOptions具有附加(不清楚为什么原始缺少此功能)方法的自定义数据适配器ArrayAdapter可用于动态更新选项列表(本示例中的所有选项):

$.fn.select2.amd.define('select2/data/customAdapter',
    ['select2/data/array', 'select2/utils'],
    function (ArrayAdapter, Utils) {
        function CustomDataAdapter ($element, options) {
            CustomDataAdapter.__super__.constructor.call(this, $element, options);
        }
        Utils.Extend(CustomDataAdapter, ArrayAdapter);
        CustomDataAdapter.prototype.updateOptions = function (data) {
            this.$element.find('option').remove(); // remove all options
            this.addOptions(this.convertToOptions(data));
        }        
        return CustomDataAdapter;
    }
);

var customAdapter = $.fn.select2.amd.require('select2/data/customAdapter');

var sel = $('select').select2({
    dataAdapter: customAdapter,
    data: pills
});

$('#uppercase').click(function() {
    $.each(pills, function(idx, val) {
        pills[idx].text = val.text.toUpperCase();
    });
    sel.data('select2').dataAdapter.updateOptions(pills);
});

小提琴 https ://jsfiddle.net/xu48n36c/1/


select2 v4:ajax传输功能

在 v4 中,您可以定义可以与本地数据数组一起使用的自定义传输方法(例如,谢谢 @Caleb_Kiage,我玩过它但没有成功)

文档:https ://select2.github.io/options.html#can-an-ajax-plugin-other-than-jqueryajax-be-used

Select2 使用 ajax.transport 中定义的传输方法向您的 API 发送请求。默认情况下,此传输方法是 jQuery.ajax,但可以更改。

$('select').select2({
    ajax: {
        transport: function(params, success, failure) {
            var items = pills;
            // fitering if params.data.q available
            if (params.data && params.data.q) {
                items = items.filter(function(item) {
                    return new RegExp(params.data.q).test(item.text);
                });
            }
            var promise = new Promise(function(resolve, reject) {
                resolve({results: items});
            });
            promise.then(success);
            promise.catch(failure);
        }
    }
});

但是使用这种方法,如果数组中的选项文本发生更改,您需要更改选项的 ID - 内部 select2 dom 选项元素列表未修改。如果数组中选项的 id 保持不变 - 将显示以前保存的选项,而不是从数组中更新!如果仅通过向其添加新项目来修改数组,这不是问题- 对于大多数常见情况来说都可以。

小提琴: https ://jsfiddle.net/xu48n36c/3/

于 2013-06-27T16:25:34.497 回答
19

我认为直接交出数据就足够了:

$("#inputhidden").select2("data", data, true);

请注意,第二个参数似乎表明需要刷新。

感谢@Bergi 对此的帮助


如果这不会自动更新,您可以尝试直接调用它的 updateResults 方法。

$("#inputhidden").select2("updateResults");

或者通过向“input.select2-input”发送触发器来间接触发它,如下所示:

var search = $("#inputhidden input.select2-input");
search.trigger("input");
于 2013-06-03T15:43:26.280 回答
15

将 Select2 4.0 与 Meteor 一起使用,您可以执行以下操作:

Template.TemplateName.rendered = ->

  $("#select2-el").select2({
    data  : Session.get("select2Data")
  })

  @autorun ->

    # Clear the existing list options. 
    $("#select2-el").select2().empty()

    # Re-create with new options.
    $("#select2-el").select2({
      data  : Session.get("select2Data")
    })

发生了什么:

  1. 当模板被渲染...
  2. 使用来自 Session 的数据初始化一个 select2 控件。
  3. 每次 Session.get("select2Data") 的值更改时,@autorun (this.autorun) 函数都会运行。
  4. 每当 Session 更改时,清除现有的 select2 选项并使用新数据重新创建。

这适用于任何响应式数据源——例如 Collection.find().fetch()——而不仅仅是 Session.get()。

注意:从 Select2 版本 4.0 开始,您必须在添加新选项之前删除现有选项。有关详细信息,请参阅此 GitHub 问题。在不清除现有选项的情况下,没有“更新选项”的方法。

以上是咖啡脚本。Javascript 非常相似。

于 2015-10-19T11:12:11.740 回答
14

试试这个:

var data = [{id: 1, text: 'First'}, {id: 2, text: 'Second'}, {...}];
$('select[name="my_select"]').empty().select2({
    data: data
});
于 2019-01-29T12:37:36.913 回答
6
var selBoxObj = $('#selectpill');
selBoxObj.trigger("change.select2");
于 2016-05-25T09:29:35.237 回答
4

我通过使用 ajax 选项并指定自定义传输函数解决了这个问题。

看这个小提琴Select2 动态选项演示

这是相关的js来让它工作。

var $items = [];

let options = {
ajax: {
    transport: function(params, success, failure) {
    let items = $items;

    if (params.data && params.data.q) {
        items = items.filter(function(item) {
        return new RegExp(params.data.q).test(item.text);
        });
    }

    let promise = new Promise(function(resolve, reject) {
        resolve({
        results: items
        });
    });

    promise.then(success);
    promise.catch(failure);
    }
},
placeholder: 'Select item'
};

$('select').select2(options);

let count = $items.length + 1;

$('button').on('click', function() {
$items.push({
    id: count,
    text: 'Item' + count
});
count++;
});
于 2017-04-30T15:41:43.287 回答
2

据我所知,如果不刷新整个列表或输入一些搜索文本并使用查询功能,就不可能更新 select2 选项。

这些按钮应该做什么?如果它们用于确定选择选项,为什么不将它们放在选择框之外,让它们以编程方式设置选择框数据然后打开呢?我不明白您为什么要将它们放在搜索框的顶部。如果用户不应该搜索,您可以使用 minimumResultsForSearch 选项隐藏搜索功能。

编辑:这个怎么样...

HTML

<input type="hidden" id="select2" class="select" />

Javascript

var data = [{id: 0, text: "Zero"}],
    select = $('#select2');

select.select2({
  query: function(query) {
    query.callback({results: data});
  },
  width: '150px'
});

console.log('Opening select2...');
select.select2('open');

setTimeout(function() {
  console.log('Updating data...');
  data = [{id: 1, text: 'One'}];
}, 1500);

setTimeout(function() {
  console.log('Fake keyup-change...');
  select.data().select2.search.trigger('keyup-change');
}, 3000);

示例Plunker

编辑2:这至少会更新列表,但是如果您在触发keyup-change事件之前输入了搜索文本,仍然会有一些奇怪之处。

于 2013-05-12T23:47:56.133 回答
1

对于 Select2 4.X

var instance = $('#select2Container').data('select2');
var searchVal = instance.dropdown.$search.val();
instance.trigger('query', {term:searchVal});
于 2016-08-25T12:28:13.287 回答
0

Diego对SpinyMan 给出的答案的评论很重要,因为该empty()方法将删除 select2 实例,因此将不再保留任何自定义选项。如果要保留现有的 select2 选项,则必须保存它们,销毁现有的 select2 实例,然后重新初始化。你可以这样做:

const options = JSON.parse(JSON.stringify(
  $('#inputhidden').data('select2').options.options
));
options.data = data;

$('#inputhidden').empty().select2('destroy').select2(options);

但是,我建议始终显式传递 select2 选项,因为上面只复制简单的选项,而不是任何自定义回调或适配器。另请注意,这需要select2的最新稳定版本(本文发布时为4.0.13)。

我编写了通用函数来处理这个问题,并提供了一些功能:

  • 可以处理返回多个实例的选择器
  • 使用现有 select2 的实例选项(默认)或传入一组新选项
  • 保留任何仍然有效的已选择值(默认值),或完全清除它们
function select2UpdateOptions(
  selector,
  data,
  newOptions = null,
  keepExistingSelected = true
) {
  // loop through all instances of the matching selector and update each instance
  $(selector).each(function() {
    select2InstanceUpdateOptions($(this), data, newOptions, keepExistingSelected);
  });
}

// update an existing select2 instance with new data options
function select2InstanceUpdateOptions(
  instance,
  data,
  newOptions = null,
  keepSelected = true
) {
  // make sure this instance has select2 initialized
  // @link https://select2.org/programmatic-control/methods#checking-if-the-plugin-is-initialized
  if (!instance.hasClass('select2-hidden-accessible')) {
    return;
  }

  // get the currently selected options
  const existingSelected = instance.val();

  // by default use the existing options of the select2 instance unless overridden
  // this will not copy over any callbacks or custom adapters however
  const options = (newOptions)
    ? newOptions
    : JSON.parse(JSON.stringify(instance.data('select2').options.options))
  ;

  // set the new data options that will be used
  options.data = data;
      
  // empty the select and destroy the existing select2 instance
  // then re-initialize the select2 instance with the given options and data
  instance.empty().select2('destroy').select2(options);
      
  // by default keep options that were already selected;
  // any that are now invalid will automatically be cleared
  if (keepSelected) {
    instance.val(existingSelected).trigger('change');
  }
}
于 2020-10-07T21:39:58.933 回答