Select2 4.0.0 начальное значение с Ajax

у меня есть select2 v4.0.0 заполняется из массива Ajax. Если я установил val select2, я вижу через отладку javascript, что он выбрал правильный элемент (#3 в моем случае), однако это не показано в поле выбора, он все еще показывает заполнитель. enter image description here

в то время как я должен видеть что-то вроде этого: enter image description here

в моих полях формы:

<input name="creditor_id" type="hidden" value="3">
<div class="form-group minimal form-gap-after">
    <span class="col-xs-3 control-label minimal">
        <label for="Creditor:">Creditor:</label>
    </span>
    <div class="col-xs-9">
        <div class="input-group col-xs-8 pull-left select2-bootstrap-prepend">
            <select class="creditor_select2 input-xlarge form-control minimal select2 col-xs-8">
                <option></option>
            </select>
        </div>
    </div>
</div>

мой javascript:

var initial_creditor_id = "3";
$(".creditor_select2").select2({
    ajax: {
       url: "/admin/api/transactions/creditorlist",
       dataType: 'json',
       delay: 250,
       data: function (params) {
           return {
                q: params.term,
                c_id: initial_creditor_id,
                page: params.page
           };
       },
       processResults: function (data, page) {
            return {
                results: data
            };
       },
       cache: true
   },
   placeholder: "Search for a Creditor",
   width: "element",
   theme: "bootstrap",
   allowClear: true
   }).on("select2:select", function (e) {
      var selected = e.params.data;
      if (typeof selected !== "undefined") {
           $("[name='creditor_id']").val(selected.creditor_id);
           $("#allocationsDiv").hide();
           $("[name='amount_cash']").val("");
           $("[name='amount_cheque']").val("");
           $("[name='amount_direct']").val("");
           $("[name='amount_creditcard']").val("");
        }
    }).on("select2:unselecting", function (e) {
        $("form").each(function () {
            this.reset()
        });
        ("#allocationsDiv").hide();
        $("[name='creditor_id']").val("");
    }).val(initial_creditor_id);

Как я могу сделать окно выбора показать выбранный элемент, а не прототип? Возможно, я должен отправить это как часть ответа AJAX JSON?

в прошлом для Select2 требовалась опция initSelection, которая определялась всякий раз, когда использовался пользовательский источник данных, что позволяло определить начальный выбор компонента. Это отлично сработало для меня в v3.5.

11 ответов


вы делаете большинство вещей правильно, похоже, единственная проблема, которую вы нажмете, заключается в том, что вы не запускаете change метод после установки нового значения. Без change event, Select2 не может знать, что базовое значение изменилось, поэтому оно будет отображать только заполнитель. Изменение последней части на

.val(initial_creditor_id).trigger('change');

должен исправить вашу проблему, и вы должны сразу увидеть обновление пользовательского интерфейса.


это предполагает, что у вас есть <option> уже есть value of initial_creditor_id. Если вы не Select2, а браузер, фактически не сможет изменить значение, так как нет возможности переключиться на, и Select2 не обнаружит новое значение. Я заметил, что ваш <select> содержит только один параметр, один для заполнителя, что означает, что вам нужно будет создать новый <option> вручную.

var $option = $("<option selected></option>").val(initial_creditor_id).text("Whatever Select2 should display");

а затем добавьте его к <select> что вы инициализировали Select2 on. Вы можете получить текст из внешнего источника, где initSelection используется для вступления в игру, что по-прежнему возможно с Select2 4.0.0. Как и стандартный выбор, это означает, что вам придется сделать запрос AJAX для получения значения, а затем установить <option> текст на лету корректировать.

var $select = $('.creditor_select2');

$select.select2(/* ... */); // initialize Select2 and any events

var $option = $('<option selected>Loading...</option>').val(initial_creditor_id);

$select.append($option).trigger('change'); // append the option and update Select2

$.ajax({ // make the request for the selected data object
  type: 'GET',
  url: '/api/for/single/creditor/' + initial_creditor_id,
  dataType: 'json'
}).then(function (data) {
  // Here we should have the data object
  $option.text(data.text).val(data.id); // update the text that is displayed (and maybe even the value)
  $option.removeData(); // remove any caching data that might be associated
  $select.trigger('change'); // notify JavaScript components of possible changes
});

хотя это может выглядеть как много кода, это точно, как вы это сделаете для non-Select2 выберите поля, чтобы убедиться, что все изменения были сделаны.


то, что я сделал, более чисто и должно сделать два массива:

  • один содержит список объектов с идентификатором и текстом (в моем случае его идентификатор и имя, в зависимости от вашего templateResult) (его то, что вы получаете от ajax-запроса)
  • второй-это только массив идентификаторов (стоимость выбора)

Я инициализирую select2, используя первый массив в качестве данных, а второй-как val.

пример функции с параметрами a dict of идентификационное имя.

function initMyList(values) {
    var selected = [];
    var initials = [];

    for (var s in values) {
        initials.push({id: s, name: values[s].name});
        selected.push(s);
    }

    $('#myselect2').select2({
        data: initials,
        ajax: {
            url: "/path/to/value/",
            dataType: 'json',
            delay: 250,
            data: function (params) {
                return {
                    term: params.term,
                    page: params.page || 1,
                };
            },
            processResults: function (data, params) {
                params.page = params.page || 1;

                return {
                    results: data.items,
                    pagination: {
                        more: (params.page * 30) < data.total_count
                    }
                };
            },
            cache: true
        },
        minimumInputLength: 1,
        tokenSeparators: [",", " "],
        placeholder: "Select none, one or many values",
        templateResult: function (item) { return item.name; },
        templateSelection: function (item) { return item.name; },
        matcher: function(term, text) { return text.name.toUpperCase().indexOf(term.toUpperCase()) != -1; },
    });

    $('#myselect2').val(selected).trigger('change');
}

вы можете передать значение инициалов с помощью вызовов ajax и использовать jQuery обещает выполнить инициализацию select2.


вопрос о принуждении к trigger('change') сводили меня с ума, так как у меня был пользовательский код change trigger, который должен запускаться только при изменении пользователем опции в раскрывающемся списке. IMO, изменение не должно запускаться при установке значения инициализации в начале.

я копнул глубоко и нашел следующее:https://github.com/select2/select2/issues/3620

пример:

$dropDown.val(1).trigger('change.select2');


один сценарий, который я не видел, чтобы люди действительно отвечали, - Это как иметь предварительный выбор, когда параметры получены AJAX, и вы можете выбрать несколько. Поскольку это страница перехода для предварительного выбора AJAX, я добавлю свое решение здесь.

$('#mySelect').select2({
    ajax: {
        url: endpoint,
        dataType: 'json',
        data: [
            { // Each of these gets processed by fnRenderResults.
                id: usersId,
                text: usersFullName,
                full_name: usersFullName,
                email: usersEmail,
                image_url: usersImageUrl,
                selected: true // Causes the selection to actually get selected.
            }
        ],
        processResults: function(data) {

            return {
                results: data.users,
                pagination: {
                    more: data.next !== null
                }
            };

        }
    },
    templateResult: fnRenderResults,
    templateSelection: fnRenderSelection, // Renders the result with my own style
    selectOnClose: true
}); 

если вы используете templateSelection и ajax, некоторые из этих других ответов могут не работать. Кажется, что создание нового option элемент и задание value и text не будет удовлетворять методу шаблона, когда ваши объекты данных используют другие значения, кроме id и text.

вот что сработало для меня:

$("#selectElem").select2({
  ajax: { ... },
  data: [YOUR_DEFAULT_OBJECT],
  templateSelection: yourCustomTemplate
} 

Проверьте jsFiddle здесь:https://jsfiddle.net/shanabus/f8h1xnv4

в моем случае, мне пришлось processResults В С моей данные не содержали требуемого id и text поля. Если вам нужно это сделать, вам также нужно будет запустить свой первоначальный выбор через ту же функцию. Вот так:

$(".js-select2").select2({
  ajax: {
    url: SOME_URL,
    processResults: processData
  },
  data: processData([YOUR_INIT_OBJECT]).results,
  minimumInputLength: 1,
  templateSelection: myCustomTemplate
});

function processData(data) {
  var mapdata = $.map(data, function (obj) {      
    obj.id = obj.Id;
    obj.text = '[' + obj.Code + '] ' + obj.Description;
    return obj;
  });
  return { results: mapdata }; 
}

function myCustomTemplate(item) {
     return '<strong>' + item.Code + '</strong> - ' + item.Description;
}

это работает для меня ...

Не используйте jQuery, только HTML: создайте Параметр Значение будет отображаться как избранные. Если ID это select2 data он будет выбран автоматически.

<select id="select2" name="mySelect2">
  <option value="mySelectedValue">
        Hello, I'm here!
  </option>
</select>

Select2.org -по умолчанию предварительно выбранные значения


потратив несколько часов на поиск решения, я решил создать свой собственный. Он:

 function CustomInitSelect2(element, options) {
            if (options.url) {
                $.ajax({
                    type: 'GET',
                    url: options.url,
                    dataType: 'json'
                }).then(function (data) {
                    element.select2({
                        data: data
                    });
                    if (options.initialValue) {
                        element.val(options.initialValue).trigger('change');
                    }
                });
            }
        }

и вы можете инициализировать выбор, используя эту функцию:

$('.select2').each(function (index, element) {
            var item = $(element);
            if (item.data('url')) {
                CustomInitSelect2(item, {
                    url: item.data('url'),
                    initialValue: item.data('value')
                });
            }
            else {
                item.select2();
            }
        });

и, конечно же, вот html:

<select class="form-control select2" id="test1" data-url="mysite/load" data-value="123"></select>

Я добавляю этот ответ в основном потому, что я не могу прокомментировать выше! Я обнаружил, что это был комментарий @Nicki и ее jsfiddle,https://jsfiddle.net/57co6c95/, это в конечном итоге заставило это работать на меня.

среди прочего, он дал примеры формата для необходимого json. Единственное изменение, которое я должен был сделать, было то, что мои первоначальные результаты были возвращены в том же формате, что и другой вызов ajax, поэтому мне пришлось использовать

$option.text(data[0].text).val(data[0].id);

, а не

$option.text(data.text).val(data.id);

создать простой ajax комбо с де начальное значение seleted для select2 4.0.3

<select name="mycombo" id="mycombo""></select>                   
<script>
document.addEventListener("DOMContentLoaded", function (event) {
    selectMaker.create('table', 'idname', '1', $("#mycombo"), 2, 'type');                                
});
</script>  

библиотека .js

var selectMaker = {
create: function (table, fieldname, initialSelected, input, minimumInputLength = 3, type ='',placeholder = 'Select a element') {
    if (input.data('select2')) {
        input.select2("destroy");
    }
    input.select2({
        placeholder: placeholder,
        width: '100%',
        minimumInputLength: minimumInputLength,
        containerCssClass: type,
        dropdownCssClass: type,
        ajax: {
            url: 'ajaxValues.php?getQuery=true&table=' + table + '&fieldname=' + fieldname + '&type=' + type,
            type: 'post',
            dataType: 'json',
            contentType: "application/json",
            delay: 250,
            data: function (params) {
                return {
                    term: params.term, // search term
                    page: params.page
                };
            },
            processResults: function (data) {
                return {
                    results: $.map(data.items, function (item) {
                        return {
                            text: item.name,
                            id: item.id
                        }
                    })
                };
            }
        }
    });
    if (initialSelected>0) {
        var $option = $('<option selected>Cargando...</option>').val(0);
        input.append($option).trigger('change'); // append the option and update Select2
        $.ajax({// make the request for the selected data object
            type: 'GET',
            url: 'ajaxValues.php?getQuery=true&table=' + table + '&fieldname=' + fieldname + '&type=' + type + '&initialSelected=' + initialSelected,
            dataType: 'json'
        }).then(function (data) {
            // Here we should have the data object
            $option.text(data.items[0].name).val(data.items[0].id); // update the text that is displayed (and maybe even the value)
            $option.removeData(); // remove any caching data that might be associated
            input.trigger('change'); // notify JavaScript components of possible changes
        });
    }
}
};

и сторона сервера php

<?php
if (isset($_GET['getQuery']) && isset($_GET['table']) && isset($_GET['fieldname'])) {
//parametros carga de petición
parse_str(file_get_contents("php://input"), $data);
$data = (object) $data;
if (isset($data->term)) {
    $term = pSQL($data->term);
}else{
    $term = '';
}
if (isset($_GET['initialSelected'])){
    $id =pSQL($_GET['initialSelected']);
}else{
    $id = '';
}
if ($_GET['table'] == 'mytable' && $_GET['fieldname'] == 'mycolname' && $_GET['type'] == 'mytype') {

    if (empty($id)){
        $where = "and name like '%" . $term . "%'";
    }else{
         $where = "and id= ".$id;
    }

    $rows = yourarrayfunctionfromsql("SELECT id, name 
                    FROM yourtable
                    WHERE 1 " . $where . "
                    ORDER BY name ");
}

$items = array("items" => $rows);
$var = json_encode($items);
echo $var;
?>

для простого и семантического решения я предпочитаю определять начальное значение в HTML, например:

<select name="myfield" data-placeholder="Select an option">
    <option value="initial-value" selected>Initial text</option>
</select>

поэтому, когда я называю $('select').select2({ ajax: {...}}); начальное значение initial-value и его текст опции Initial text.

мой Select2 версия 4.0.3, но я думаю, она имеет большую совместимость с другими версиями.


Привет почти бросил это и вернулся к выбору 3.5.1. Но в конце концов я получил ответ!

$('#test').select2({
    placeholder: "Select a Country",
    minimumResultsForSearch: 2,
    ajax: {
        url: '...',
        dataType: 'json',
        cache: false,
        data: function (params) {
                var queryParameters = {
                    q: params.term
                }
                return queryParameters;
        },
        processResults: function (data) {
            return {
                results: data.items
            };
        }
    }
});

var option1 = new Option("new",true, true);

$('#status').append(option1);

$('#status').trigger('change');

просто убедитесь, что новый параметр является одним из параметров select2. Я получаю это от json.