Selecione o menu suspenso 2, mas permite novos valores por usuário?

125

Quero ter uma lista suspensa com um conjunto de valores, mas também permitir que o usuário "selecione" um novo valor não listado lá.

Vejo que o select2 suporta isso se você o estiver usando no tagsmodo, mas existe uma maneira de fazê-lo sem usar tags?

johnjohn
fonte
1
O Select2 nunca funcionou para mim, pelo menos, o createSearchChoice nunca funcionou para mim no 4.0.3, e eu não queria que meus usuários esperassem que o ajax fosse concluído para retornar a mesma palavra-chave; portanto, tive que lançar minha própria biblioteca. compartilhá-lo, porque eu acho que poderia ajudar outras pessoas que ainda estão confusos quanto eu, por favor, não para baixo votação, se você não concordar com a minha resposta: github.com/razzbee/tagcomplete
razzbee

Respostas:

100

Para a versão 4+, verifique esta resposta abaixo por Kevin Brown

No Select2 3.5.2 e abaixo, você pode usar algo como:

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

(extraído de uma resposta na lista de distribuição select2, mas não consegue encontrar o link agora)

fmpwizard
fonte
4
Desculpe pela resposta tardia, mas muito obrigado pela sua solução! O outro pôster postou um link para sua essência, o que o torna duplamente incrível! :) #
311313 johnjohn
rrauenza incrível, exatamente o que eu estava procurando
Matthias S
4
Para adicionar o selectOnBlur: truetrabalho, consulte: stackoverflow.com/questions/25616520/…
Alireza Fattahi 2/14
1
Apenas um aviso para futuros leitores, você provavelmente deseja usar tags: []junto createSearchChoice.
Kevin Brown
5
O violino ligado acima parece quebrado.
Wolfr 19/04
175

A excelente resposta fornecida pelo @fmpwizard funciona para o Select2 3.5.2 e inferior, mas não funciona no 4.0.0 .

Desde muito cedo (mas talvez não tão cedo quanto essa pergunta), o Select2 oferece suporte à "marcação": onde os usuários podem adicionar seu próprio valor, se você permitir. Isso pode ser ativado através da tagsopção, e você pode brincar com um exemplo na documentação .

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

Por padrão, isso criará uma opção que possui o mesmo texto que o termo de pesquisa que eles inseriram. Você pode modificar o objeto usado se estiver procurando marcá-lo de uma maneira especial ou criar o objeto remotamente depois que ele for selecionado.

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

Além de servir como um sinalizador fácil de detectar no objeto transmitido pelo select2:selectevento, a propriedade extra também permite que você renderize a opção de maneira um pouco diferente no resultado. Portanto, se você deseja sinalizar visualmente o fato de que é uma nova opção colocando " (novo) " ao lado, você pode fazer algo assim.

$("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;
  }
});
Kevin Brown
fonte
Isso foi muito útil @
Markus1980Wien #
Acho que usei esse trecho várias vezes.
Sahu V Kumar
Se não estiver funcionando, verifique se você adicionou essa opção em select2 não adicionar nas opções do ajax. para select2 ajax
Zohaib
2
Seu workign na versão select2 (4.0.6) desta maneira: $ ("select"). Select2 ({tags: true, createTag: function (params) {return {id: params.term, texto: params.term, newOption : true}}, templateResult: function (data) {var resultado = data.text; if (data.newOption) {resultado = resultado + '(novo)';} retornar resultado;}}); Obrigado @Kevin Brown
M. Salah
Essa deve ser a resposta principal. Estou pesquisando há algum tempo e essa opção responde a todas as perguntas que tenho visto sobre o tópico.
Justin
14

Apenas para manter o código ativo, estou postando o código de @rrauenza Fiddle a partir do seu comentário .

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'}]
});
Michel Ayres
fonte
2
Fui ao violino, mas não parece estar funcionando para mim no Chrome. Você pode confirmar?
IcedDante
@IcedDante o código está funcionando. o ponto no violino é apenas para mostrar como isso deve ser feito (a seleção é escondido no violino)
Michel Ayres
4
Quando vou para o violino, não vejo um menu suspenso select2 em nenhum lugar. Não seria bom ter um exemplo que realmente ... faz alguma coisa?
IcedDante
Como posso definir os dados de uma fonte externa? Quero dizer, e se eu quiser carregar cidades de um país selecionado e o próprio país selecionado for uma dropodown?
Ali Baig
12

Como muitas dessas respostas não funcionam na versão 4.0 ou superior, se você estiver usando o ajax, o servidor poderá adicionar o novo valor como uma opção. Portanto, funcionaria assim:

  1. O usuário procura por valor (o que faz ajax solicitar ao servidor)
  2. Se o valor for ótimo, retorne a opção Se não, basta que o servidor acrescente essa opção da seguinte forma:[{"text":" my NEW option)","id":"0"}]
  3. Quando o formulário é enviado, verifique se essa opção está no banco de dados e, se não estiver, crie-a antes de salvar.
Eric
fonte
6

Existe uma solução melhor, eu acho agora

basta definir a marcação como true nas opções selecionadas?

tags: true

de https://select2.org/tagging

Steven Moffat
fonte
4

Melhor na resposta @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
Vikash Singh
fonte
Eu usei isso com uma ligeira modificação. Vou colocar minha resposta em um segundo, mas obrigado.
Sam
1
var text = 'New York Mills';
var term = 'new york mills';
return text.localeCompare(term)===0;

Na maioria dos casos, precisamos comparar valores com registro insensível. E esse código retornará false, o que levará à criação de registros duplicados no banco de dados. Além disso, String.prototype.localeCompare () não é suportado pelo navegador Safary e este código não funcionará neste navegador;

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

substituirá melhor a

return this.text.toLowerCase() === term.toLowerCase();
ultrapassado
fonte
1

Obrigado pela ajuda pessoal, usei o código abaixo no Codeigniter II estou usando a versão: 3.5.2 of 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]'};
        }
    },
});
Sam
fonte