web-dev-qa-db-fra.com

Select2 4.0.0 valeur initiale avec Ajax

J'ai un select2 v4.0.0 en cours de remplissage d'un tableau Ajax. Si je règle le val du select2, je peux voir via le débogage javascript qu'il a sélectionné le bon élément (n ° 3 dans mon cas), mais cela ne s'affiche pas dans la zone de sélection, il affiche toujours le paramètre fictif. enter image description here

Alors que je devrais voir quelque chose comme ça: enter image description here

Dans mes champs de formulaire:

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

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

Comment puis-je faire en sorte que la zone de sélection affiche l'élément sélectionné plutôt que l'espace réservé? Devrais-je envoyer cela dans le cadre de la réponse JSON AJAX peut-être?

Auparavant, Select2 nécessitait une option appelée initSelection qui était définie chaque fois qu'une source de données personnalisée était utilisée, ce qui permettait de déterminer la sélection initiale du composant. Cela a bien fonctionné pour moi dans la v3.5.

93
Greg

Vous faites la plupart des choses correctement, il semble que le seul problème que vous rencontrez est de ne pas déclencher la méthode change après avoir défini la nouvelle valeur. Sans un événement change, Select2 ne peut pas savoir que la valeur sous-jacente a changé et affiche uniquement le paramètre fictif. Changer votre dernière partie en

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

Devrait résoudre votre problème, et vous devriez voir la mise à jour de l'interface utilisateur immédiatement.


Cela suppose que vous avez déjà un <option> qui a un value sur initial_creditor_id. Si vous ne sélectionnez pas Select2, le navigateur ne pourra pas réellement modifier la valeur car il n'y a pas d'option pour basculer sur et Select2 ne détectera pas la nouvelle valeur. J'ai remarqué que votre <select> ne contient qu'une seule option, celle de l'espace réservé, ce qui signifie que vous devrez créer le nouveau <option> manuellement.

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

Et ensuite, ajoutez-le au <select> sur lequel vous avez initialisé Select2. Vous devrez peut-être obtenir le texte d'une source externe, c'est-à-dire l'endroit où initSelection était utilisé, ce qui est toujours possible avec Select2 4.0.0. Comme pour une sélection standard, cela signifie que vous allez devoir faire la demande AJAX pour récupérer la valeur, puis définir le texte <option> à la volée pour l'ajuster.

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

Bien que cela puisse paraître beaucoup de code, il s'agit de exactement comme vous le feriez pour les zones de sélection autres que Select2 afin de garantir que toutes les modifications ont été apportées.

108
Kevin Brown

Ce que j'ai fait est plus propre et doit créer deux tableaux:

  • l'un contient une liste d'objets avec un identifiant et un texte (dans mon cas, son identifiant et son nom, en fonction de votre templateResult) (c'est ce que vous obtenez à partir d'une requête ajax)
  • le second n'est qu'un tableau d'identifiants (valeur de sélection)

J'initialise select2 en utilisant le premier tableau en tant que données et le second en tant que val.

Un exemple de fonction avec pour paramètres un dict of 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');
}

Vous pouvez alimenter la valeur initiale en utilisant des appels ajax et utiliser jquery pour effectuer l'initialisation de select2.

27
firebird631

Le fait d'être forcé à trigger('change') m'a rendu fou, car j'avais un code personnalisé dans le déclencheur change, qui ne devrait se déclencher que lorsque l'utilisateur modifie l'option dans le menu déroulant. IMO, le changement ne doit pas être déclenché lors de la définition d'une valeur d'initialisation au début.

J'ai creusé profondément et trouvé ce qui suit: https://github.com/select2/select2/issues/362

Exemple:

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

6
adamj

Ça marche pour moi ...

N'utilisez pas jQuery, uniquement HTML: créez la valeur d'option que vous afficherez comme sélectionné . Si ID est en , sélectionnez 2 données , il sera automatiquement sélectionné.

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

Select2.org - Valeurs présélectionnées par défaut

4
nat_jea

Un scénario auquel les gens n'ont pas vraiment répondu est la suivante: comment créer une présélection lorsque les options sont AJAX et que vous pouvez en sélectionner plusieurs. Puisqu'il s'agit de la page de destination de la présélection AJAX, je vais ajouter ma solution ici.

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

Si vous utilisez templateSelection et ajax, certaines de ces autres réponses risquent de ne pas fonctionner. Il semble que la création d'un nouvel élément option et la définition de value et text ne satisferont pas la méthode du modèle lorsque vos objets de données utilisent d'autres valeurs que id et text.

Voici ce qui a fonctionné pour moi:

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

Découvrez le jsFiddle ici: https://jsfiddle.net/shanabus/f8h1xnv4

Dans mon cas, je devais entrer processResults car mes données ne contenaient pas les champs id et text requis. Si vous avez besoin de le faire, vous devrez également exécuter votre sélection initiale via la même fonction. Ainsi:

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

après avoir passé quelques heures à chercher une solution, j'ai décidé de créer la mienne. Il c'est:

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

Et vous pouvez initialiser les sélections en utilisant cette fonction:

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

Et bien sûr, voici le code HTML:

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

https://github.com/select2/select2/issues/4272 seulement cela a résolu mon problème. Même si vous définissez la valeur par défaut par option, vous devez formater l'objet, qui a l'attribut text et c'est ce que vous souhaitez afficher dans votre option. alors, votre fonction de formatage doit utiliser || pour choisir l'attribut qui n'est pas vide.

0
王佳颉

Créer un combo ajax simple avec la valeur sélectionnée initialement pour 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>  

bibliothèque .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
        });
    }
}
};

et le côté serveur 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;
?>
0
Alejandro Aranda

Pour une solution simple et sémantique, je préfère définir la valeur initiale en HTML, par exemple:

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

Ainsi, lorsque j'appelle $('select').select2({ ajax: {...}});, la valeur initiale est initial-value et le texte de son option est Initial text.

Ma version actuelle de Select2 est 4.0. , mais je pense que sa compatibilité avec les autres versions est excellente.

0
Marcio Mazzucato

J'ajoute cette réponse principalement parce que je ne peux pas commenter ci-dessus! J'ai trouvé que c'était le commentaire de @ Nicki et son jsfiddle, https://jsfiddle.net/57co6c95/ , qui a finalement permis à ce travail de fonctionner pour moi.

Entre autres choses, il donnait des exemples du format du json nécessaire. Le seul changement que j’ai dû faire est que mes premiers résultats ont été renvoyés dans le même format que l’autre appel ajax.

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

plutôt que

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