Исходное значение Select2 4.0.0 с Ajax

У меня есть select2 v4.0.0, заполняемый из массива Ajax. Если я установил val select2, я могу увидеть, используя javascript-отладку, что он выбрал правильный элемент (# 3 в моем случае), однако это не показано в поле выбора, оно все еще показывает placeholder. 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, который определялся всякий раз, когда использовался пользовательский источник данных, позволяя определить исходный выбор для компонента. Это отлично работало для меня в версии 3.5.

Ответ 1

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

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

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


Предполагается, что у вас уже есть <option>, у которого value 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
});

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

Ответ 2

То, что я сделал, более чистое и требует создания двух массивов:

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

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

Примерная функция с параметрами a dict id: name.

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 promises для инициализации select2.

Ответ 3

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

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

Пример:

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

Ответ 4

Один сценарий, на который я не видел людей, на самом деле отвечающий, заключается в том, как сделать предварительный выбор, если параметры 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
}); 

Ответ 5

Меня устраивает...

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

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

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

Ответ 6

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

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

$("#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;
}

Ответ 7

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

 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>

Ответ 8

https://github.com/select2/select2/issues/4272 только это решило мою проблему. даже если вы устанавливаете значение по умолчанию с помощью параметра, вы должны отформатировать объект, который имеет атрибут text, и это то, что вы хотите показать в своем параметре. Итак, ваша функция форматирования должна использовать || выбрать атрибут, который не является пустым.

Ответ 9

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

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

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

а не

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

Ответ 10

Создайте простую комбинацию 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>  

library.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;
?>

Ответ 11

Для простого и семантического решения я предпочитаю определять начальное значение в 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, но я думаю, что она отлично совместима с другими версиями.

Ответ 12

Привет был почти уволен и вернулся, чтобы выбрать 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.