Select2 4.0.0 ค่าเริ่มต้นด้วย Ajax


98

ฉันมี select2 v4.0.0 ที่ถูกเติมจากอาร์เรย์ Ajax ถ้าฉันตั้งค่า val ของ select2 ฉันสามารถเห็นผ่านการดีบักจาวาสคริปต์ว่าได้เลือกรายการที่ถูกต้อง (# 3 ในกรณีของฉัน) อย่างไรก็ตามสิ่งนี้ไม่แสดงในกล่องเลือก แต่ก็ยังคงแสดงตัวยึด ป้อนคำอธิบายภาพที่นี่

ในขณะที่ฉันควรจะเห็นสิ่งนี้: ป้อนคำอธิบายภาพที่นี่

ในช่องแบบฟอร์มของฉัน:

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

จาวาสคริปต์ของฉัน:

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


เป็นไปได้อย่างไร? เมื่อฉันพยายามเชื่อมโยงselectกับajaxมันทำให้เกิดข้อผิดพลาดขึ้นตัวเลือกนั้นไม่ได้รับอนุญาตเมื่อเลือก ...
Daggeto

สวัสดีโปรดดูที่stackoverflow.com/questions/42833778/…
Vivekraj KR

คำตอบ:


109

คุณกำลังทำสิ่งต่างๆอย่างถูกต้องดูเหมือนว่าปัญหาเดียวที่คุณกำลังกดปุ่มคือคุณไม่ได้เรียกใช้changeเมธอดนี้หลังจากที่คุณตั้งค่าใหม่ หากไม่มีchangeเหตุการณ์ Select2 จะไม่สามารถทราบได้ว่าค่าพื้นฐานมีการเปลี่ยนแปลงดังนั้นจึงจะแสดงเฉพาะตัวยึดเท่านั้น เปลี่ยนส่วนสุดท้ายของคุณเป็น

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

ควรแก้ไขปัญหาของคุณและคุณจะเห็นการอัปเดต UI ทันที


นี่คือสมมติว่าคุณมีไฟล์ <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 บน คุณอาจต้องรับข้อความจากแหล่งภายนอกซึ่งเป็นที่ที่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 เพื่อให้แน่ใจว่ามีการเปลี่ยนแปลงทั้งหมด


14
มีความคิดอย่างไรในการเลือกหลายตัวเลือกล่วงหน้าสำหรับกล่องเลือกหลายรายการ
user396404

6
@ user396404 แนวคิดเดียวกันนี้ควรนำไปใช้เพียงแค่ส่งรายการรหัสเข้าไปval()แทน id เดียว หรือเพียงแค่ต่อท้ายหลาย ๆ ตัว<option selected>และควรจัดการโดยอัตโนมัติ
Kevin Brown

5
ฉันรู้ว่าคำตอบนี้มีอายุมากกว่าหนึ่งปีแล้ว แต่เอกสารสำหรับ Select2 สำหรับคำถาม FAQ: "ฉันจะตั้งค่าตัวเลือกที่เลือกไว้ในตอนแรกเมื่อใช้ AJAX ได้อย่างไร" ยังคงชี้ไปที่สิ่งนี้ ฉันได้แนบ JSFiddle เป็นตัวอย่างการทำงานสำหรับ v4.0.3 jsfiddle.net/57co6c95
Clint

2
มีปัญหา จะทำอย่างไรหากต้องการขอมากกว่าแค่ id และ text? ฉันได้ลองแล้ว แต่ตัวเลือกข้อมูลรับเฉพาะข้อมูลสำหรับ templateResult และไม่สนใจสำหรับ templateSelection ความคิดใด ๆ ?
เคลียร์ทั้ง

2
นอกจากนี้ฉันลองวิธีแก้ปัญหานี้แล้ว แต่น่าเสียดายที่หลังจากเรียก$select.trigger('change');ตัวเลือกนี้ยังคงมีข้อความกำลังโหลด ...แม้ว่าจะdata.textมีข้อความที่ฉันต้องการก็ตาม บางทีมันอาจจะไม่ได้รับการสนับสนุนใน4.0.6
Alisson

29

สิ่งที่ฉันทำมีความสะอาดมากขึ้นและจำเป็นต้องสร้างอาร์เรย์สองอาร์เรย์:

  • หนึ่งมีรายการวัตถุที่มี id และข้อความ (ในกรณีของฉันคือ id และชื่อขึ้นอยู่กับ templateResult ของคุณ) (เป็นสิ่งที่คุณได้รับจากแบบสอบถาม ajax)
  • ที่สองเป็นเพียงอาร์เรย์ของรหัส (ค่าที่เลือก)

ฉันเริ่มต้น select2 โดยใช้อาร์เรย์แรกเป็นข้อมูลและตัวที่สองเป็น val

ฟังก์ชั่นตัวอย่างที่มี as parameters เป็นคำสั่งของ 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 สัญญาเพื่อทำการเริ่มต้น select2


3
นี่เป็นวิธีที่ดีกว่าแน่นอน การจัดการ DOM โดยการเพิ่ม<option>ดูเหมือนจะไม่ใช่วิธีที่สมเหตุสมผลที่สุด นี่คือวิธีที่ฉันทำใน 4.0
jiaweizhang

2
@ firebird631 โซลูชันของคุณยอดเยี่ยมใช้งานได้ดีและขอบคุณมาก!
userlond

นี่เป็นวิธีแก้ปัญหาที่สะอาดที่สุดที่ฉันเคยเห็น
Jimmy Ilenloa

ฉันจะทราบว่าภายในdataตัวเลือกเป็นเพียงการสร้าง<option>แท็กและเพิ่มลงในการเลือก คำตอบนี้ไม่ได้ครอบคลุมถึงวิธีการจัดการกรณีที่คุณต้องออกไปที่ API เพื่อรับข้อมูลเพิ่มเติม แต่ฉันเดาว่าเป็นกรณีปกติน้อยกว่า
Kevin Brown

สวัสดีด้วย ajax ฉันไม่สามารถทำได้ เมื่อฉันส่งรายการที่มีวัตถุสองชิ้นไม่มีปัญหา แต่จะพยายามแทรกวัตถุทั้งสองนั้น แต่มีเพียงชิ้นเดียวที่แทรก และเลือกโดยอัตโนมัติแล้ว ฉันไม่สามารถมองเห็นสองตัวเลือกได้แม้ฉันจะส่งสองรายการ
Sahin Yanlık

7

มันใช้ได้สำหรับฉัน ...

อย่าใช้ jQuery เพียง HTML: สร้างค่าตัวเลือกที่คุณจะแสดงเป็นที่เลือก หาก ID อยู่ในข้อมูล select2 ระบบจะเลือกโดยอัตโนมัติ

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

Select2.org - ค่าเริ่มต้นที่เลือกไว้ล่วงหน้า


6

ปัญหาของการถูกบังคับให้trigger('change')ทำให้ฉันบ้าเพราะฉันมีโค้ดที่กำหนดเองในchangeทริกเกอร์ซึ่งจะทริกเกอร์เมื่อผู้ใช้เปลี่ยนตัวเลือกในเมนูแบบเลื่อนลงเท่านั้น IMO ไม่ควรทริกเกอร์การเปลี่ยนแปลงเมื่อตั้งค่าเริ่มต้นเมื่อเริ่มต้น

ฉันขุดลึกและพบสิ่งต่อไปนี้: https://github.com/select2/select2/issues/3620

ตัวอย่าง:

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


5

สถานการณ์หนึ่งที่ฉันไม่เคยเห็นคนตอบจริงๆคือการเลือกล่วงหน้าเมื่อตัวเลือกมาจาก 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
}); 

3

หากคุณใช้ 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;
}

ในที่สุด !!!!! ว้าวไม่น่าหงุดหงิดไปกว่านี้อีกแล้ว !! ฉันใช้ "ชื่อ" แทน "ข้อความ" และมันกำลังฆ่าฉัน ฉันเปลี่ยนไปใช้คีย์ "ข้อความ" เริ่มต้นและตอนนี้มันทำงานได้อย่างสมบูรณ์ ขอบคุณ!
HTMLGuy

1

หลังจากใช้เวลาสองสามชั่วโมงในการค้นหาวิธีแก้ปัญหาฉันก็ตัดสินใจสร้างของตัวเอง เขาคือ:

 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>

ความคิดที่ดีสำหรับขั้นตอนการเริ่มต้นทั่วไป
Carlos Mora

1

สำหรับโซลูชันที่เรียบง่ายและมีความหมายฉันต้องการกำหนดค่าเริ่มต้นใน HTML เช่น:

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

ดังนั้นเมื่อผมเรียก$('select').select2({ ajax: {...}});ค่าเริ่มต้นเป็นและข้อความที่เป็นตัวเลือกinitial-valueInitial text

Select2 เวอร์ชันปัจจุบันของฉันคือ4.0.3แต่ฉันคิดว่ามันเข้ากันได้ดีกับเวอร์ชันอื่น ๆ


ฉันเดาว่าคุณกำลังบันทึกไม่เพียง แต่ค่าที่เลือกเท่านั้น แต่ยังรวมถึงข้อความไปยังฐานข้อมูลของคุณด้วยดังนั้นคุณสามารถเรียกดูได้เช่นนั้น ... sheesh!
ITDesigns.eu

@ ITDesigns.eu ฉันไม่คิดอย่างนั้นค่าที่ส่งไปยังฐานข้อมูลคือinitial-valueและข้อความInitial textทำหน้าที่เป็นตัวยึดตำแหน่งจะไม่ถูกส่งไปยังฐานข้อมูล มันทำงานในแอปพลิเคชันของฉัน
Marcio Mazzucato

ทำไมต้องมีตัวยึดแทนข้อความจริงในตัวเลือกจริง !
ITDesigns.eu

@ ITDesigns.eu, Select2 จับข้อมูลนี้และติดตั้งเอง
Marcio Mazzucato

1

https://github.com/select2/select2/issues/4272 แค่นี้ก็แก้ปัญหาของฉันได้แล้ว แม้ว่าคุณจะตั้งค่าเริ่มต้นตามตัวเลือกคุณต้องจัดรูปแบบวัตถุซึ่งมีแอตทริบิวต์ข้อความและนี่คือสิ่งที่คุณต้องการแสดงในตัวเลือกของคุณ ดังนั้นฟังก์ชันรูปแบบของคุณจึงต้องใช้||เพื่อเลือกแอตทริบิวต์ที่ไม่ว่างเปล่า


0

ฉันเพิ่มคำตอบนี้เป็นหลักเพราะฉันไม่สามารถแสดงความคิดเห็นด้านบนได้! ฉันพบว่ามันเป็นความคิดเห็นของ @Nicki และ jsfiddle ของเธอhttps://jsfiddle.net/57co6c95/ซึ่งในที่สุดสิ่งนี้ก็ใช้ได้ผลกับฉัน

เหนือสิ่งอื่นใดมันให้ตัวอย่างของรูปแบบสำหรับ json ที่จำเป็น การเปลี่ยนแปลงเพียงอย่างเดียวที่ฉันต้องทำคือผลลัพธ์เริ่มต้นของฉันถูกส่งคืนในรูปแบบเดียวกับการโทร ajax อื่น ๆ ดังนั้นฉันจึงต้องใช้

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

ค่อนข้างมากกว่า

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

0

สร้างคำสั่งผสม 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;
?>

-4

สวัสดีเกือบจะออกจากสิ่งนี้แล้วและกลับไปเลือก 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


สวัสดี - '#status' คืออะไร? สิ่งที่ควรจะเป็น '# ทดสอบ'?
user2808054
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.