Select2 4.0.0 Anfangswert mit Ajax


97

Ich habe eine select2 v4.0.0, die aus einem Ajax-Array gefüllt wird. Wenn ich den Wert von select2 einstelle, kann ich durch Javascript-Debugging sehen, dass das richtige Element ausgewählt wurde (in meinem Fall # 3). Dies wird jedoch nicht im Auswahlfeld angezeigt, es wird weiterhin der Platzhalter angezeigt. Geben Sie hier die Bildbeschreibung ein

Während ich so etwas sehen sollte: Geben Sie hier die Bildbeschreibung ein

In meinen Formularfeldern:

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

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

Wie kann ich festlegen, dass im Auswahlfeld das ausgewählte Element und nicht der Platzhalter angezeigt wird? Sollte ich dies möglicherweise als Teil der AJAX JSON-Antwort senden?

In der Vergangenheit erforderte Select2 eine Option namens initSelection, die definiert wurde, wenn eine benutzerdefinierte Datenquelle verwendet wurde, sodass die anfängliche Auswahl für die Komponente bestimmt werden konnte. Das hat in Version 3.5 gut funktioniert.


Wie ist es möglich? Wenn ich versuche, selectmit ajaxihm zu binden , steigt der Fehler, diese Option ist bei Auswahl nicht zulässig ...
Daggeto

Hallo, bitte werfen Sie einen Blick auf stackoverflow.com/questions/42833778/…
Vivekraj KR

Antworten:


109

Sie machen die meisten Dinge richtig. Es sieht so aus, als ob das einzige Problem, auf das Sie stoßen, darin besteht, dass Sie die changeMethode nicht auslösen , nachdem Sie den neuen Wert festgelegt haben. Ohne ein changeEreignis kann Select2 nicht wissen, dass sich der zugrunde liegende Wert geändert hat, sodass nur der Platzhalter angezeigt wird. Ändern Sie Ihren letzten Teil in

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

Sollte Ihr Problem beheben und Sie sollten das UI-Update sofort sehen.


Dies setzt voraus, dass Sie ein <option>bereits haben, das ein valuevon hat initial_creditor_id. Wenn Sie Select2 nicht verwenden, kann der Browser den Wert nicht ändern, da keine Option zum Wechseln vorhanden ist und Select2 den neuen Wert nicht erkennt. Ich habe festgestellt, dass Ihre <select>Option nur eine einzige enthält, die für den Platzhalter, was bedeutet, dass Sie die neue <option>manuell erstellen müssen.

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

<select>Fügen Sie es dann an das hinzu , auf dem Sie Select2 initialisiert haben. Möglicherweise müssen Sie den Text von einer externen Quelle initSelectionbeziehen, aus der das Spiel stammt, was mit Select2 4.0.0 weiterhin möglich ist. Wie bei einer Standardauswahl bedeutet dies, dass Sie die AJAX-Anforderung stellen müssen, um den Wert abzurufen, und dann den <option>Text im laufenden Betrieb einstellen müssen, um ihn anzupassen.

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

Dies sieht zwar nach viel Code aus, aber genau so würden Sie es für Nicht-Select2-Auswahlfelder tun, um sicherzustellen, dass alle Änderungen vorgenommen wurden.


14
Haben Sie eine Idee, wie Sie mehrere Optionen für Mehrfachauswahlfelder vorwählen können?
user396404

6
@ user396404 Es sollten dieselben Konzepte gelten. Übergeben Sie einfach eine Liste von IDs val()anstelle einer einzelnen ID. Oder einfach mehrere anhängen <option selected>und das sollte automatisch erledigt werden.
Kevin Brown

5
Mir ist klar, dass diese Antwort über ein Jahr alt ist, aber die Dokumentation zu Select2 für die FAQ-Frage: "Wie kann ich die ursprünglich ausgewählten Optionen bei Verwendung von AJAX festlegen?" weist noch darauf hin. Ich habe eine JSFiddle als Arbeitsbeispiel für v4.0.3 angehängt. Jsfiddle.net/57co6c95
Clint

2
Es gibt ein Problem. Was ist, wenn ich mehr als nur ID und Text anfordern möchte? Ich habe versucht, aber die Datenoption ruft nur die Daten für templateResult ab und ignoriert sie für templateSelection. Irgendeine Idee?
ClearBoth

2
Auch ich habe diese Lösung ausprobiert, aber leider ist $select.trigger('change');die Option nach dem Aufruf immer noch mit dem Text Loading ... verbunden , obwohl data.textgenau der Text vorhanden war, den ich wollte. Möglicherweise wird dies in 4.0.6 nicht mehr unterstützt .
Alisson

28

Was ich getan habe, ist sauberer und muss zwei Arrays erstellen:

  • Eine enthält eine Liste von Objekten mit ID und einem Text (in meinem Fall ID und Name, abhängig von Ihrem templateResult) (was Sie von einer Ajax-Abfrage erhalten).
  • Die zweite ist nur ein Array von IDs (Auswahlwert).

Ich initialisiere select2 mit dem ersten Array als Daten und dem zweiten als Wert.

Eine Beispielfunktion mit einem Diktat von id: name als Parametern.

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

Sie können den Initialenwert mit Ajax-Aufrufen eingeben und JQuery-Versprechen verwenden, um die Select2-Initialisierung durchzuführen.


3
Dies ist definitiv der bessere Weg, dies zu tun. Das Manipulieren des DOM durch Hinzufügen <option>scheint nicht der logischste Weg zu sein. So mache ich es in 4.0
Jiaweizhang

2
@ firebird631, deine Lösung ist brillant, sie funktioniert und vielen Dank!
Userlond

Dies ist die sauberste Lösung, die ich bisher gesehen habe
Jimmy Ilenloa

Ich werde bemerken, dass die dataOption intern nur <option>Tags generiert und sie zur Auswahl hinzufügt. Diese Antwort behandelt nicht, wie Sie mit Fällen umgehen, in denen Sie zu einer API gehen müssen, um weitere Informationen zu erhalten, aber ich denke, das ist ein weniger typischer Fall.
Kevin Brown

Hallo mit Ajax, ich kann es nicht. Wenn ich eine Liste mit zwei Objekten sende, gibt es kein Problem, es wird versucht, diese beiden Objekte einzufügen, aber nur eines eingefügt. und bereits automatisch ausgewählt. Ich kann nie zwei Optionen sehen, auch wenn ich zwei Artikel gesendet habe.
Sahin Yanlık

7

Es funktioniert für mich ...

Verwenden Sie nicht jQuery, sondern nur HTML: Erstellen Sie den Optionswert, den Sie als ausgewählt anzeigen . Wenn die ID in den Daten von select2 enthalten ist , wird sie automatisch ausgewählt.

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

Select2.org - Vorgewählte Standardwerte


6

Das Problem, gezwungen zu sein, trigger('change')mich verrückt zu machen, da ich benutzerdefinierten Code im changeTrigger hatte, der nur ausgelöst werden sollte, wenn der Benutzer die Option in der Dropdown-Liste ändert. IMO, Änderung sollte nicht ausgelöst werden, wenn zu Beginn ein Init-Wert eingestellt wird.

Ich habe tief gegraben und Folgendes gefunden: https://github.com/select2/select2/issues/3620

Beispiel:

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


4

Ein Szenario, auf das die Leute nicht wirklich geantwortet haben, ist die Vorauswahl, wenn die Optionen aus AJAX stammen und Sie mehrere auswählen können. Da dies die Startseite für die AJAX-Vorauswahl ist, füge ich hier meine Lösung hinzu.

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

Wenn Sie templateSelection und ajax verwenden, funktionieren einige dieser anderen Antworten möglicherweise nicht. Es scheint, dass das Erstellen eines neuen optionElements und das Festlegen von valueund textdie Vorlagenmethode nicht erfüllen, wenn Ihre Datenobjekte andere Werte als ID und Text verwenden.

Folgendes hat bei mir funktioniert:

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

Schauen Sie sich die jsFiddle hier an: https://jsfiddle.net/shanabus/f8h1xnv4

In meinem Fall musste ich processResultsin da meine Daten die erforderlichen nicht enthielten idund textFelder. Wenn Sie dies tun müssen, müssen Sie auch Ihre anfängliche Auswahl über dieselbe Funktion ausführen. Wie so:

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

ENDLICH!!!!! Wow, das hätte nicht frustrierender sein können !! Ich hatte "Name" anstelle von "Text" verwendet und es brachte mich um. Ich habe auf die Standardtaste "Text" umgestellt und sie funktioniert jetzt einwandfrei. Danke dir!
HTMLGuy

1

Nachdem ich einige Stunden nach einer Lösung gesucht hatte, beschloss ich, meine eigene zu erstellen. Er ist es:

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

Mit dieser Funktion können Sie die Auswahl initialisieren:

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

Und hier ist natürlich das HTML:

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

Tolle Idee für ein generisches Initialisierungsverfahren.
Carlos Mora

1

Für eine einfache und semantische Lösung bevorzuge ich es, den Anfangswert in HTML zu definieren, Beispiel:

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

Also, wenn ich $('select').select2({ ajax: {...}});den Anfangswert aufrufe initial-valueund sein Optionstext ist Initial text.

Meine aktuelle Select2-Version ist 4.0.3 , aber ich denke, sie ist sehr gut mit anderen Versionen kompatibel.


Ich denke, Sie speichern nicht nur einen ausgewählten Wert, sondern auch einen Text in Ihrer Datenbank, damit Sie ihn so abrufen können ... meine Güte!
ITDesigns.eu

@ ITDesigns.eu, ich glaube nicht, der Wert, der an die Datenbank gesendet wird, ist initial-valueund der Text Initial textfungiert als Platzhalter, er wird nicht an die Datenbank gesendet. Es funktioniert in meiner Anwendung.
Marcio Mazzucato

Warum sollte ich in der eigentlichen Option einen Platzhalter anstelle eines echten Textes benötigen ?!
ITDesigns.eu

@ ITDesigns.eu, Select2 fängt diese Informationen und montiert sich
Marcio Mazzucato

1

https://github.com/select2/select2/issues/4272 nur dies löste mein Problem. Selbst wenn Sie den Standardwert nach Option festlegen, müssen Sie das Objekt mit dem Textattribut formatieren. Dies möchten Sie in Ihrer Option anzeigen. Daher muss Ihre Formatierungsfunktion ||das Attribut auswählen, das nicht leer ist.


0

Ich füge diese Antwort hauptsächlich hinzu, weil ich oben keinen Kommentar abgeben kann! Ich fand, dass es der Kommentar von @Nicki und ihrer jsfiddle, https://jsfiddle.net/57co6c95/ , war, der dies schließlich für mich zum Laufen brachte .

Es gab unter anderem Beispiele für das Format des benötigten JSON. Die einzige Änderung, die ich vornehmen musste, war, dass meine ersten Ergebnisse im gleichen Format wie der andere Ajax-Aufruf zurückgegeben wurden, sodass ich sie verwenden musste

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

eher, als

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

0

Erstellen Sie eine einfache Ajax-Kombination mit dem anfänglichen ausgewählten Wert für 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>  

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

und die PHP-Serverseite

<?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 hat das fast beendet und gehe zurück, um 3.5.1 auszuwählen. Aber endlich habe ich die Antwort bekommen!

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

Stellen Sie nur sicher, dass die neue Option eine der select2-Optionen ist. Ich bekomme das von einem Json.


Hallo - was ist '#status'? sollte das '#test' sein?
user2808054
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.