Giá trị ban đầu Select2 4.0.0 với Ajax


97

Tôi có select2 v4.0.0 được điền từ một mảng Ajax. Nếu tôi đặt giá trị của select2, tôi có thể thấy thông qua gỡ lỗi javascript rằng nó đã chọn đúng mục (# 3 trong trường hợp của tôi), tuy nhiên điều này không được hiển thị trong hộp chọn, nó vẫn đang hiển thị trình giữ chỗ. nhập mô tả hình ảnh ở đây

Trong khi tôi sẽ thấy một cái gì đó như thế này: nhập mô tả hình ảnh ở đây

Trong các trường biểu mẫu của tôi:

<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 của tôi:

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);

Làm cách nào tôi có thể làm cho hộp chọn hiển thị mục đã chọn thay vì trình giữ chỗ? Có lẽ tôi nên gửi cái này như một phần của phản hồi AJAX JSON?

Trước đây, Select2 yêu cầu một tùy chọn gọi là initSelection được xác định bất cứ khi nào nguồn dữ liệu tùy chỉnh được sử dụng, cho phép lựa chọn ban đầu cho thành phần được xác định. Điều này làm việc tốt cho tôi trong v3.5.


Làm thế nào nó có thể? Khi tôi đang cố gắng ràng buộc selectvới ajaxnó mọc lỗi, tùy chọn đó ajax của nó không được phép có chọn ...
Daggeto

Câu trả lời:


109

Bạn đang làm hầu hết mọi thứ một cách chính xác, có vẻ như vấn đề duy nhất bạn đang gặp phải là bạn không kích hoạt changephương pháp sau khi bạn đang đặt giá trị mới. Nếu không có changesự kiện, Select2 không thể biết rằng giá trị cơ bản đã thay đổi nên nó sẽ chỉ hiển thị trình giữ chỗ. Thay đổi phần cuối cùng của bạn thành

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

Sẽ khắc phục sự cố của bạn và bạn sẽ thấy bản cập nhật giao diện người dùng ngay lập tức.


Đây là giả sử rằng bạn có một <option>đã có một valuesố initial_creditor_id. Nếu bạn không Select2 và trình duyệt sẽ không thực sự thay đổi được giá trị, vì không có tùy chọn nào để chuyển sang và Select2 sẽ không phát hiện ra giá trị mới. Tôi nhận thấy rằng bạn <select>chỉ chứa một tùy chọn duy nhất, tùy chọn dành cho trình giữ chỗ, có nghĩa là bạn sẽ cần tạo tùy chọn mới <option>theo cách thủ công.

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

Và sau đó nối nó vào cái <select>mà bạn đã khởi tạo Select2. Bạn có thể cần lấy văn bản từ một nguồn bên ngoài, nơi initSelectionđược sử dụng để phát, điều này vẫn có thể thực hiện được với Select2 4.0.0. Giống như một lựa chọn tiêu chuẩn, điều này có nghĩa là bạn sẽ phải thực hiện yêu cầu AJAX để truy xuất giá trị và sau đó đặt <option>văn bản nhanh chóng để điều chỉnh.

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
});

Mặc dù điều này có thể trông giống như rất nhiều mã, nhưng đây chính xáccách bạn thực hiện đối với các hộp chọn không thuộc Select2 để đảm bảo rằng tất cả các thay đổi đã được thực hiện.


14
Bất kỳ ý tưởng nào về cách chọn trước nhiều tùy chọn cho nhiều hộp chọn không?
user396404

6
@ user396404 áp dụng các khái niệm tương tự, chỉ cần chuyển một danh sách id vào val()thay vì một id duy nhất. Hoặc chỉ thêm nhiều <option selected>và điều đó sẽ được xử lý tự động.
Kevin Brown

5
Tôi nhận thấy câu trả lời này đã hơn một năm, nhưng tài liệu dành cho Select2 cho câu hỏi FAQ: "Làm cách nào để đặt các tùy chọn đã chọn ban đầu khi sử dụng AJAX?" vẫn chỉ ra điều này. Tôi đã gắn một JSFiddle như một ví dụ làm việc cho v4.0.3 jsfiddle.net/57co6c95
Clint

2
Có một vấn đề. Điều gì xảy ra nếu tôi muốn yêu cầu nhiều hơn chỉ id và văn bản? Tôi đã thử nhưng tùy chọn dữ liệu chỉ nhận dữ liệu cho templateResult và bỏ qua nó cho templateSelection. Bất kỳ ý tưởng?
ClearBoth,

2
Ngoài ra, tôi đã thử giải pháp này, nhưng rất tiếc sau khi gọi $select.trigger('change');tùy chọn vẫn có văn bản Đang tải ... mặc dù data.textcó chính xác văn bản tôi muốn. Có thể điều này không còn được hỗ trợ trong 4.0.6 .
Alisson

28

Những gì tôi đã làm rõ ràng hơn và cần tạo ra hai mảng:

  • một chứa danh sách các Đối tượng có id và văn bản (trong trường hợp của tôi là id và tên của nó, tùy thuộc vào templateResult của bạn) (nó là những gì bạn nhận được từ truy vấn ajax)
  • thứ hai chỉ là một mảng id (giá trị lựa chọn)

Tôi khởi tạo select2 bằng cách sử dụng mảng đầu tiên làm dữ liệu và mảng thứ hai làm giá trị.

Một hàm ví dụ với các tham số là một chính tả của 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');
}

Bạn có thể cung cấp giá trị viết tắt bằng cách sử dụng các lệnh gọi ajax và sử dụng các lời hứa jquery để thực hiện khởi tạo select2.


3
Đây chắc chắn là cách tốt hơn để làm điều đó. Thao tác DOM bằng cách thêm <option>có vẻ không phải là cách hợp lý nhất để làm điều đó. Đây là cách tôi làm điều đó trong 4,0
jiaweizhang

2
@ firebird631, giải pháp của bạn thật tuyệt vời, nó hoạt động và rất cảm ơn!
userlond

đây là giải pháp sạch tôi đã thấy cho đến nay
Jimmy Ilenloa

Tôi sẽ lưu ý rằng bên trong datatùy chọn chỉ là tạo <option>thẻ và thêm chúng vào lựa chọn. Câu trả lời này không đề cập đến cách bạn xử lý các trường hợp cần truy cập API để lấy thêm thông tin, nhưng tôi đoán đó là trường hợp ít điển hình hơn.
Kevin Brown,

Xin chào với ajax Tôi không thể làm điều đó. Khi tôi gửi một danh sách có hai đối tượng, không có vấn đề gì khi nó cố gắng chèn hai đối tượng đó nhưng chỉ một đối tượng được chèn. và đã được chọn tự động. Tôi không bao giờ có thể thấy hai tùy chọn, ngay cả khi tôi đã gửi hai mục.
Sahin Yanlık

7

Nó phù hợp với tôi ...

Không sử dụng jQuery, chỉ sử dụng HTML: Tạo giá trị tùy chọn mà bạn sẽ hiển thị khi đã chọn . Nếu ID nằm trong dữ liệu select2, nó sẽ tự động được chọn.

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

Select2.org - Các giá trị được chọn trước mặc định


6

Vấn đề bị buộc phải trigger('change')khiến tôi phát điên vì tôi có mã tùy chỉnh trong trình changekích hoạt, mã này sẽ chỉ kích hoạt khi người dùng thay đổi tùy chọn trong trình đơn thả xuống. IMO, không nên kích hoạt thay đổi khi đặt giá trị init lúc bắt đầu.

Tôi đã đào sâu và tìm thấy thông tin sau: https://github.com/select2/select2/issues/3620

Thí dụ:

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


4

Một tình huống mà tôi chưa thấy mọi người thực sự trả lời, đó là làm thế nào để có một lựa chọn trước khi các tùy chọn có nguồn gốc AJAX và bạn có thể chọn nhiều. Vì đây là trang truy cập để chọn trước AJAX, tôi sẽ thêm giải pháp của mình ở đây.

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

3

Nếu bạn đang sử dụng templateSelection và ajax, một số câu trả lời khác có thể không hoạt động. Có vẻ như việc tạo một optionphần tử mới và đặt valuetextsẽ không đáp ứng phương pháp mẫu khi các đối tượng dữ liệu của bạn sử dụng các giá trị khác ngoài id và văn bản.

Đây là những gì đã làm việc cho tôi:

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

Kiểm tra jsFiddle tại đây: https://jsfiddle.net/shanabus/f8h1xnv4

Trong trường hợp của tôi, tôi phải tham processResultsgia vì dữ liệu của tôi không chứa các trường bắt buộc idtext. Nếu bạn cần làm điều này, bạn cũng sẽ cần chạy lựa chọn ban đầu của mình thông qua cùng một chức năng. Như vậy:

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

CUỐI CÙNG !!!!! Wow, điều đó không thể khó chịu hơn !! Tôi đã sử dụng "tên" thay vì "văn bản" và nó đang giết chết tôi. Tôi đã chuyển sang phím "văn bản" mặc định và nó đang hoạt động hoàn hảo. Cảm ơn bạn!
HTMLGuy

1

sau vài giờ tìm kiếm giải pháp, tôi quyết định tạo ra giải pháp của riêng mình. Anh ấy là:

 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');
                    }
                });
            }
        }

Và bạn có thể khởi tạo các lựa chọn bằng cách sử dụng chức năng này:

$('.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();
            }
        });

Và tất nhiên, đây là html:

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

Ý tưởng tuyệt vời cho một thủ tục khởi tạo chung.
Carlos Mora

1

Đối với một giải pháp đơn giản và ngữ nghĩa, tôi muốn xác định giá trị ban đầu trong HTML, ví dụ:

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

Vì vậy, khi tôi gọi $('select').select2({ ajax: {...}});giá trị ban đầu là initial-valuevà văn bản tùy chọn của nó là Initial text.

Phiên bản Select2 hiện tại của tôi là 4.0.3 , nhưng tôi nghĩ nó có khả năng tương thích tốt với các phiên bản khác.


Tôi đoán bạn đang lưu không chỉ một giá trị được chọn, mà còn cả một văn bản vào cơ sở dữ liệu của bạn, vì vậy bạn có thể truy xuất nó như thế ... sheesh!
ITDesigns.eu

@ ITDesigns.eu, tôi không nghĩ vậy, giá trị sento cho cơ sở dữ liệu là initial-valuevà văn bản Initial texthoạt động như một trình giữ chỗ, nó không được gửi đến cơ sở dữ liệu. Nó đang hoạt động trong ứng dụng của tôi.
Marcio Mazzucato

tại sao tôi cần một trình giữ chỗ thay vì một văn bản thực trong tùy chọn thực tế ?!
ITDesigns.eu

@ ITDesigns.eu, Select2 bắt thông tin này và tự gắn kết
Marcio Mazzucato

1

https://github.com/select2/select2/issues/4272 chỉ điều này giải quyết được vấn đề của tôi. ngay cả khi bạn đặt giá trị mặc định theo tùy chọn, bạn phải định dạng đối tượng, đối tượng này có thuộc tính văn bản và đây là những gì bạn muốn hiển thị trong tùy chọn của mình. vì vậy, hàm định dạng của bạn phải sử dụng ||để chọn thuộc tính không trống.


0

Tôi đang thêm câu trả lời này chủ yếu vì tôi không thể bình luận ở trên! Tôi thấy đó là nhận xét của @Nicki và jsfiddle của cô ấy, https://jsfiddle.net/57co6c95/ , cuối cùng điều này đã hoạt động với tôi.

Trong số những thứ khác, nó đưa ra các ví dụ về định dạng cho json cần thiết. Thay đổi duy nhất mà tôi phải thực hiện là kết quả ban đầu của tôi được trả về ở định dạng giống như lệnh gọi ajax khác, vì vậy tôi phải sử dụng

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

hơn là

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

0

Tạo tổ hợp ajax đơn giản với giá trị đã chọn ban đầu cho 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>  

thư viện .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
        });
    }
}
};

và phía máy chủ 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;
?>

-4

Hi gần như thoát khỏi điều này và quay lại chọn 3.5.1. Nhưng cuối cùng tôi đã có câu trả lời!

$('#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');

Chỉ cần đảm bảo rằng tùy chọn mới là một trong các tùy chọn select2. Tôi nhận được điều này bởi một json.


Xin chào - '#status' là gì? có nên là '#test' không?
user2808054
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.