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?


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)


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

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

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.


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

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

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]'};
        }
    },
});
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.