web-dev-qa-db-fra.com

Sélectionnez 2 liste déroulante mais autorisez les nouvelles valeurs par utilisateur?

Je veux avoir un menu déroulant avec un ensemble de valeurs mais aussi permettre à l'utilisateur de "sélectionner" une nouvelle valeur qui n'y figure pas. 

Je vois que select2 supporte ceci si vous l’utilisez en mode tokens, mais existe-t-il un moyen de le faire sans jetons?

106
johnjohn

Pour la version 4+, vérifier cette réponse ci-dessous par Kevin Brown

Dans Select2 3.5.2 et ci-dessous, vous pouvez utiliser quelque chose comme:

$(selector).select2({
  minimumInputLength:1,
  "ajax": {
    data:function (term, page) {
      return { term:term, page:page };
    },
    dataType:"json",
    quietMillis:100,
    results: function (data, page) {
      return {results: data.results};
    },
    "url": url
  },
  id: function(object) {
    return object.text;
  },
  //Allow manually entered text in drop down.
  createSearchChoice:function(term, data) {
    if ( $(data).filter( function() {
      return this.text.localeCompare(term)===0;
    }).length===0) {
      return {id:term, text:term};
    }
  },
});

(extrait d'une réponse de la liste de diffusion select2, mais ne trouve pas le lien maintenant)

91
fmpwizard

La excellente réponse fournie par @fmpwizard fonctionne pour Select2 3.5.2 et inférieur, mais elle ne fonctionnera pas dans 4.0.0.

Depuis très tôt (mais peut-être pas aussi tôt que cette question), Select2 prend en charge le "marquage": les utilisateurs peuvent ajouter leur propre valeur si vous le leur permettez. Ceci peut être activé avec l'option tags et vous pouvez jouer avec un exemple dans la documentation .

$("select").select2({
  tags: true
});

Par défaut, cela créera une option ayant le même texte que le terme de recherche saisi. Vous pouvez modifier l'objet utilisé si vous souhaitez le marquer d'une manière spéciale ou créer l'objet à distance une fois qu'il est sélectionné.

$("select").select2({
  tags: true,
  createTag: function (params) {
    return {
      id: params.term,
      text: params.term,
      newOption: true
    }
  }
});

En plus de servir d'indicateur facile à repérer sur l'objet transmis via l'événement select2:select, la propriété extra vous permet également de rendre l'option légèrement différemment dans le résultat. Donc, si vous voulez signaler visuellement le fait qu’il s’agit d’une nouvelle option en mettant "(nouveau)} _" à côté, vous pouvez procéder de la sorte.

$("select").select2({
  tags: true,
  createTag: function (params) {
    return {
      id: params.term,
      text: params.term,
      newOption: true
    }
  },
  templateResult: function (data) {
    var $result = $("<span></span>");

    $result.text(data.text);

    if (data.newOption) {
      $result.append(" <em>(new)</em>");
    }

    return $result;
  }
});
147
Kevin Brown

Juste pour garder le code en vie, je poste le code de @rrauenza Fiddle from son commentaire .

HTML

<input type='hidden' id='tags' style='width:300px'/>

jQuery

$("#tags").select2({
    createSearchChoice:function(term, data) { 
        if ($(data).filter(function() { 
            return this.text.localeCompare(term)===0; 
        }).length===0) 
        {return {id:term, text:term};} 
    },
    multiple: false,
    data: [{id: 0, text: 'story'},{id: 1, text: 'bug'},{id: 2, text: 'task'}]
});
14
Michel Ayres

Étant donné que beaucoup de ces réponses ne fonctionnent pas dans la version 4.0+, si vous utilisez ajax, le serveur pourrait ajouter la nouvelle valeur en option. Donc, cela fonctionnerait comme ceci:

  1. L'utilisateur recherche une valeur (qui fait une requête ajax au serveur)
  2. Si la valeur est excellente, renvoyez l'option. Sinon, demandez simplement au serveur d’ajouter cette option comme ceci: [{"text":" my NEW option)","id":"0"}]
  3. Lorsque le formulaire est soumis, vérifiez simplement si cette option est dans la base de données et, le cas échéant, créez-la avant de l'enregistrer.
11
Eric

Amélioration de la réponse de @fmpwizard:

//Allow manually entered text in drop down.
createSearchChoice:function(term, data) {
  if ( $(data).filter( function() {
    return term.localeCompare(this.text)===0; //even if the this.text is undefined it works
  }).length===0) {
    return {id:term, text:term};
  }
},

//solution to this error: Uncaught TypeError: Cannot read property 'localeCompare' of undefined
4
Vikash Singh

Je suis tombé sur Kevin Brown. https://stackoverflow.com/a/30019966/112680

Tout ce que vous avez à faire pour v4.0.6 est d’utiliser le paramètre tags: true.

1
dbinott

Il y a une meilleure solution je pense maintenant

définir simplement le marquage sur true sur les options de sélection?

tags: true

de https://select2.org/tagging

1
Steven Moffat
var text = 'New York Mills';
var term = 'new york mills';
return text.localeCompare(term)===0;

Dans la plupart des cas, nous devons comparer les valeurs avec un registre insensible. Et ce code renverra false, ce qui entraînera la création d'enregistrements en double dans la base de données. De plus, String.prototype.localeCompare () n'est pas pris en charge par le navigateur Safary et ce code ne fonctionnera pas dans ce navigateur.

return this.text.localeCompare(term)===0;

sera mieux remplacer à

return this.text.toLowerCase() === term.toLowerCase();
1
Paul

Merci pour l'aide les gars, j'ai utilisé le code ci-dessous dans Codeigniter I J'utilise la version: 3.5.2 de select2.

var results = [];
var location_url = <?php echo json_encode(site_url('job/location')); ?>;
$('.location_select').select2({
    ajax: {
        url: location_url,
        dataType: 'json',
        quietMillis: 100,
        data: function (term) {
            return {
                term: term
            };
        },
        results: function (data) {
            results = [];
            $.each(data, function(index, item){
                results.Push({
                    id: item.location_id,
                    text: item.location_name
                });
            });
            return {
                results: results
            };
        }
    },
    //Allow manually entered text in drop down.
    createSearchChoice:function(term, results) {
        if ($(results).filter( function() {
            return term.localeCompare(this.text)===0; 
        }).length===0) {
            return {id:term, text:term + ' [New]'};
        }
    },
});
0
Sam