Select2 4.0.0 valeur initiale avec Ajax


97

J'ai un select2 v4.0.0 rempli à partir d'un tableau Ajax. Si je règle la valeur de select2, je peux voir via le débogage javascript qu'il a sélectionné l'élément correct (# 3 dans mon cas), mais cela n'est pas affiché dans la zone de sélection, il affiche toujours l'espace réservé. entrez la description de l'image ici

Alors que je devrais voir quelque chose comme ça: entrez la description de l'image ici

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é? Dois-je envoyer ceci dans le cadre de la réponse AJAX JSON peut-être?

Dans le passé, 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.


Comment c'est possible? Quand j'essaye de lier selectavec ajaxelle augmente l'erreur, cette option ajax n'est pas autorisée avec select ...
Daggeto

Salut, veuillez jeter un oeil à stackoverflow.com/questions/42833778/…
Vivekraj KR

Réponses:


109

Vous faites la plupart des choses correctement, il semble que le seul problème que vous rencontrez est que vous ne déclenchez pas la changeméthode après avoir défini la nouvelle valeur. Sans changeévénement, Select2 ne peut pas savoir que la valeur sous-jacente a changé et n'affichera donc que l'espace réservé. Changer votre dernière partie en

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

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


Cela suppose que vous avez <option>déjà un fichier valuede initial_creditor_id. Si vous ne le faites pas, Select2 et le navigateur ne pourront pas modifier la valeur, car il n'y a pas d'option vers laquelle basculer 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 la nouvelle <option>manuellement.

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

Et puis ajoutez-le à celui sur <select>lequel vous avez initialisé Select2. Vous devrez peut-être obtenir le texte d'une source externe, qui est l'endroit où il était initSelectionutilisé pour entrer en jeu, ce qui est toujours possible avec Select2 4.0.0. Comme une sélection standard, cela signifie que vous allez devoir faire la requête AJAX pour récupérer la valeur, puis définir le <option>texte à 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 ressembler à beaucoup de code, c'est exactement comment vous le feriez pour les boîtes de sélection non Select2 pour vous assurer que toutes les modifications ont été apportées.


14
Une idée comment présélectionner plusieurs options pour les boîtes de sélection multiples?
user396404

6
@ user396404 les mêmes concepts doivent s'appliquer, il suffit de passer une liste d'identifiants au val()lieu d'un seul identifiant. Ou ajoutez simplement plusieurs <option selected>et cela devrait être géré automatiquement.
Kevin Brown

5
Je me rends compte que cette réponse date de plus d'un an, mais la documentation de Select2 pour la question FAQ: "Comment puis-je définir les options initialement sélectionnées lors de l'utilisation d'AJAX?" pointe toujours cela. J'ai joint un JSFiddle comme exemple de travail pour la v4.0.3 jsfiddle.net/57co6c95
Clint

2
Il ya un problème. Que faire si je souhaite demander plus qu'un simple identifiant et texte? J'ai essayé, mais l'option de données n'obtient que les données pour templateResult et l'ignore pour templateSelection. Une idée?
ClearBoth

2
Aussi, j'ai essayé cette solution, mais malheureusement après avoir appelé $select.trigger('change');l'option est toujours avec le texte Chargement ... , même si data.textj'avais exactement le texte que je voulais. Peut-être que cela n'est plus pris en charge dans la version 4.0.6 .
Alisson

28

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 de la requête ajax)
  • le second n'est qu'un tableau d'identifiants (valeur de sélection)

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

Un exemple de fonction avec comme paramètres un dict de 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 des initiales à l'aide d'appels ajax et utiliser les promesses de jquery pour effectuer l'initialisation de select2.


3
C'est certainement la meilleure façon de procéder. Manipuler le DOM en ajoutant <option>ne semble pas être la manière la plus logique de le faire. Voici comment je le fais en 4.0
jiaweizhang

2
@ firebird631, votre solution est géniale, elle fonctionne et très grand merci!
userlond

c'est la solution la plus propre que j'ai vue jusqu'à présent
Jimmy Ilenloa

Je noterai qu'en interne, l' dataoption consiste simplement à générer des <option>balises et à les ajouter à la sélection. Cette réponse ne couvre pas la façon dont vous gérez les cas où vous devez accéder à une API pour obtenir plus d'informations, mais je suppose que c'est un cas moins typique.
Kevin Brown

Bonjour avec ajax je ne suis pas capable de le faire. Lorsque j'envoie une liste avec deux objets, il n'y a aucun problème, il essaie d'insérer ces deux objets mais un seul est inséré. et déjà sélectionné automatiquement. Je n'ai jamais pu voir deux options, même si j'ai envoyé deux articles.
Sahin Yanlık

7

Cela fonctionne pour moi ...

N'utilisez pas jQuery, uniquement HTML: créez la valeur d'option que vous afficherez comme sélectionnée . Si l'ID est dans les données select2, il sera sélectionné automatiquement.

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

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


6

Le problème d'être forcé de trigger('change')me rendre fou, car j'avais un code personnalisé dans le changedéclencheur, qui ne devrait se déclencher que lorsque l'utilisateur modifie l'option dans la liste déroulante. OMI, 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 j'ai trouvé ce qui suit: https://github.com/select2/select2/issues/3620

Exemple:

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


4

Un scénario auquel je n'ai pas vu les gens vraiment répondre, est de savoir comment avoir une présélection lorsque les options proviennent d'AJAX et que vous pouvez en sélectionner plusieurs. Puisqu'il s'agit de la page de référence pour la présélection AJAX, j'ajouterai 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
}); 

3

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

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 le faire processResultscar mes données ne contenaient pas les champs obligatoires idet text. Si vous avez besoin de faire cela, 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;
}

ENFIN!!!!! Wow, cela n'aurait pas pu être plus frustrant !! J'avais utilisé "nom" au lieu de "texte" et cela me tuait. Je suis passé à la touche "texte" par défaut et cela fonctionne parfaitement maintenant. Je vous remercie!
HTMLGuy

1

après avoir passé quelques heures à chercher une solution, j'ai décidé de créer la mienne. Il 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 html:

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

Excellente idée pour une procédure d'initialisation générique.
Carlos Mora

1

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

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

Donc, quand j'appelle $('select').select2({ ajax: {...}});la valeur initiale est initial-valueet son texte d'option est Initial text.

Ma version actuelle de Select2 est 4.0.3 , mais je pense qu'elle a une grande compatibilité avec les autres versions.


Je suppose que vous enregistrez non seulement une valeur de sélection, mais également un texte dans votre base de données, afin que vous puissiez le récupérer comme ça ... sheesh!
ITDesigns.eu

@ ITDesigns.eu, je ne pense pas, la valeur envoyée à la base de données est initial-valueet le texte Initial textagit comme un espace réservé, il n'est pas envoyé à la base de données. Cela fonctionne dans mon application.
Marcio Mazzucato

pourquoi aurais-je besoin d'un espace réservé au lieu d'un vrai texte dans l'option réelle ?!
ITDesigns.eu

@ ITDesigns.eu, Select2 attrape cette information et se monte
Marcio Mazzucato

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 voulez afficher dans votre option. donc, votre fonction de formatage doit utiliser ||pour choisir l'attribut qui n'est pas vide.


0

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 de son jsfiddle, https://jsfiddle.net/57co6c95/ , qui a finalement fait fonctionner cela pour moi.

Entre autres choses, il a donné des exemples du format nécessaire pour le json. Le seul changement que j'ai dû faire était que mes résultats initiaux étaient renvoyés dans le même format que l'autre appel ajax, j'ai donc dû utiliser

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

plutôt que

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

0

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

-4

Salut était presque en train de quitter cela et revenir en arrière pour sélectionner 3.5.1. Mais finalement j'ai eu la réponse!

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

Assurez-vous simplement que la nouvelle option est l'une des options select2. Je reçois ça par un json.


Salut - qu'est-ce que «#status»? devrait-il être «#test»?
user2808054
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.