Select2 4.0.0 valore iniziale con Ajax


97

Ho un select2 v4.0.0 che viene popolato da un array Ajax. Se imposto la val di select2 posso vedere tramite il debug javascript che ha selezionato l'elemento corretto (# 3 nel mio caso), tuttavia questo non viene mostrato nella casella di selezione, mostra ancora il segnaposto. inserisci qui la descrizione dell'immagine

Mentre dovrei vedere qualcosa del genere: inserisci qui la descrizione dell'immagine

Nei miei campi del modulo:

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

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

Come posso fare in modo che la casella di selezione mostri l'elemento selezionato anziché il segnaposto? Forse dovrei inviarlo come parte della risposta JSON AJAX?

In passato, Select2 richiedeva un'opzione chiamata initSelection che veniva definita ogni volta che veniva utilizzata un'origine dati personalizzata, consentendo di determinare la selezione iniziale per il componente. Questo ha funzionato bene per me nella v3.5.


Com'è possibile? Quando provo a collegarmi selectcon ajaxsi verifica un errore, l'opzione ajax non è consentita con selezionare ...
Daggeto

Ciao, si prega di dare un'occhiata a stackoverflow.com/questions/42833778/...
Vivekraj KR

Risposte:


109

Stai facendo la maggior parte delle cose correttamente, sembra che l'unico problema che stai riscontrando è che non stai attivando il changemetodo dopo aver impostato il nuovo valore. Senza un changeevento, Select2 non può sapere che il valore sottostante è cambiato, quindi visualizzerà solo il segnaposto. Modificare la tua ultima parte in

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

Dovresti risolvere il tuo problema e dovresti vedere subito l'aggiornamento dell'interfaccia utente.


Questo presuppone che tu abbia <option>già un che ha un valuedi initial_creditor_id. Se non si seleziona Select2 e il browser non sarà effettivamente in grado di modificare il valore, poiché non è disponibile alcuna opzione a cui passare e Select2 non rileverà il nuovo valore. Ho notato che la tua <select>contiene un'unica opzione, quella per il segnaposto, il che significa che dovrai creare la nuova <option>manualmente.

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

E poi aggiungilo al file su <select>cui hai inizializzato Select2. Potrebbe essere necessario ottenere il testo da una fonte esterna, che è dove prima initSelectionentrava in gioco, il che è ancora possibile con Select2 4.0.0. Come una selezione standard, questo significa che dovrai effettuare la richiesta AJAX per recuperare il valore e quindi impostare il <option>testo al volo per regolare.

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

Sebbene possa sembrare un sacco di codice, è esattamente come lo faresti per le caselle di selezione non Select2 per assicurarti che tutte le modifiche siano state apportate.


14
Qualche idea su come preselezionare più opzioni per le caselle di selezione multipla?
user396404

6
@ user396404 dovrebbero essere applicati gli stessi concetti, basta passare un elenco di ID a val()invece di un singolo ID. O semplicemente aggiungi più <option selected>e questo dovrebbe essere gestito automaticamente.
Kevin Brown

5
Mi rendo conto che questa risposta risale a più di un anno fa, ma la documentazione di Select2 per la domanda delle FAQ: "Come posso impostare le opzioni selezionate inizialmente quando uso AJAX?" indica ancora questo. Ho allegato un JSFiddle come esempio funzionante per v4.0.3 jsfiddle.net/57co6c95
Clint

2
C'è un problema. E se volessi richiedere più di un semplice ID e testo? Ho provato ma l'opzione data ottiene solo i dati per templateResult e la ignora per templateSelection. Qualche idea?
ClearBoth

2
Inoltre, ho provato questa soluzione, ma sfortunatamente dopo aver chiamato $select.trigger('change');l'opzione è ancora con il testo Caricamento in corso ... , anche se data.textaveva esattamente il testo che volevo. Forse questo non è più supportato nella 4.0.6 .
Alisson

28

Quello che ho fatto è più pulito e ha bisogno di creare due array:

  • uno contiene un elenco di oggetti con id e un testo (nel mio caso il suo id e nome, a seconda del tuo templateResult) (è quello che ottieni dalla query ajax)
  • il secondo è solo un array di ID (valore di selezione)

Inizializzo select2 usando il primo array come dati e il secondo come val.

Una funzione di esempio con come parametri un dict di 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');
}

Puoi alimentare il valore delle iniziali usando le chiamate ajax e usare le promesse di jquery per eseguire l'inizializzazione select2.


3
Questo è sicuramente il modo migliore per farlo. Manipolare il DOM aggiungendo <option>non sembra essere il modo più logico per farlo. Questo è come lo faccio in 4.0
jiaweizhang

2
@ firebird631, la tua soluzione è geniale, funziona e grazie mille!
userlond

questa è la soluzione più pulita che ho visto finora
Jimmy Ilenloa

Noterò che internamente l' dataopzione sta solo generando <option>tag e aggiungendoli alla selezione. Questa risposta non copre il modo in cui gestisci i casi in cui devi passare a un'API per ottenere maggiori informazioni, ma immagino che sia un caso meno tipico.
Kevin Brown

Ciao con ajax non sono in grado di farlo. Quando invio una lista con due oggetti non ci sono problemi prova ad inserire quei due oggetti ma solo uno inserito. e già selezionato automaticamente. Non sono mai riuscito a vedere due opzioni, anche se ho inviato due elementi.
Sahin Yanlık

7

Per me funziona ...

Non utilizzare jQuery, solo HTML: crea il valore dell'opzione che verrà visualizzato come selezionato . Se l'ID è nei dati select2 , verrà selezionato automaticamente.

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

Select2.org: valori predefiniti preselezionati


6

Il problema di essere costretto a trigger('change')farmi impazzire, poiché avevo un codice personalizzato nel changetrigger, che dovrebbe attivarsi solo quando l'utente modifica l'opzione nel menu a discesa. IMO, la modifica non dovrebbe essere attivata quando si imposta un valore di inizializzazione all'inizio.

Ho scavato in profondità e ho trovato quanto segue: https://github.com/select2/select2/issues/3620

Esempio:

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


4

Uno scenario a cui non ho visto davvero rispondere le persone è come avere una preselezione quando le opzioni sono di origine AJAX e puoi selezionare più opzioni. Poiché questa è la pagina di riferimento per la preselezione AJAX, aggiungerò qui la mia soluzione.

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

Se stai usando un templateSelection e ajax, alcune di queste altre risposte potrebbero non funzionare. Sembra che la creazione di un nuovo optionelemento e l'impostazione di valuee textnon soddisfi il metodo del modello quando i tuoi oggetti dati utilizzano valori diversi da id e text.

Ecco cosa ha funzionato per me:

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

Dai un'occhiata a jsFiddle qui: https://jsfiddle.net/shanabus/f8h1xnv4

Nel mio caso, ho dovuto farlo processResultspoiché i miei dati non contenevano i campi obbligatori ide text. Se è necessario eseguire questa operazione, sarà inoltre necessario eseguire la selezione iniziale tramite la stessa funzione. Così:

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

FINALMENTE!!!!! Wow, non avrebbe potuto essere più frustrante !! Stavo usando "nome" invece di "testo" e mi stava uccidendo. Sono passato al tasto "testo" predefinito e ora funziona perfettamente. Grazie!
HTMLGuy

1

dopo aver passato alcune ore a cercare una soluzione, ho deciso di crearne una mia. Lui è:

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

E puoi inizializzare le selezioni usando questa funzione:

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

E, naturalmente, ecco l'html:

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

Ottima idea per una procedura di inizializzazione generica.
Carlos Mora

1

Per una soluzione semplice e semantica preferisco definire il valore iniziale in HTML, esempio:

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

Quindi quando chiamo $('select').select2({ ajax: {...}});il valore iniziale è initial-valuee il testo dell'opzione è Initial text.

La mia attuale versione di Select2 è 4.0.3 , ma penso che abbia una grande compatibilità con altre versioni.


Immagino che tu stia salvando non solo un valore selezionato, ma anche un testo nel tuo database, in modo da poterlo recuperare in questo modo ... sheesh!
ITDesigns.eu

@ ITDesigns.eu, non credo, il valore inviato al database è initial-valuee il testo Initial textfunge da segnaposto, non viene inviato al database. Funziona nella mia applicazione.
Marcio Mazzucato

perché dovrei aver bisogno di un segnaposto invece di un testo reale nell'opzione effettiva ?!
ITDesigns.eu

@ ITDesigns.eu, Select2 cattura queste informazioni e si monta da solo
Marcio Mazzucato

1

https://github.com/select2/select2/issues/4272 solo questo ha risolto il mio problema. anche se imposti il ​​valore predefinito per opzione, devi formattare l'oggetto, che ha l'attributo text e questo è ciò che vuoi mostrare nella tua opzione. quindi, la funzione di formattazione deve utilizzare ||per scegliere l'attributo che non è vuoto.


0

Aggiungo questa risposta principalmente perché non posso commentare sopra! Ho scoperto che è stato il commento di @Nicki e del suo jsfiddle, https://jsfiddle.net/57co6c95/ , che alla fine ha funzionato per me.

Tra le altre cose, ha fornito esempi del formato necessario per il json. L'unico cambiamento che ho dovuto fare è stato che i miei risultati iniziali venivano restituiti nello stesso formato dell'altra chiamata ajax, quindi ho dovuto usare

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

piuttosto che

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

0

Crea una semplice combinazione ajax con il valore iniziale selezionato per 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>  

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

e il lato server 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

Ciao, stavo quasi uscendo da questo e torna a selezionare 3.5.1. Ma finalmente ho avuto la risposta!

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

Assicurati solo che la nuova opzione sia una delle opzioni select2. Ho ricevuto questo da un json.


Ciao, cos'è "#status"? dovrebbe essere "#test"?
user2808054
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.