Seleccionar2 desplegable pero permitir nuevos valores por usuario?

125

Quiero tener un menú desplegable con un conjunto de valores, pero también permitir que el usuario "seleccione" un nuevo valor que no aparece allí.

Veo que select2 admite esto si lo está usando en tagsmodo, pero ¿hay alguna manera de hacerlo sin usar etiquetas?

johnjohn
fuente
1
Select2 nunca funcionó para mí, al menos createSearchChoice nunca funcionó para mí en 4.0.3, y no quería que mis usuarios esperaran que ajax se completara para devolver la misma palabra clave, así que tuve que implementar mi propia biblioteca, solo estoy compartirlo porque creo que podría ayudar a otros que todavía están confundidos como yo, por favor no rechace el
razzbee

Respuestas:

100

Para la versión 4+, verifique esta respuesta a continuación por Kevin Brown

En Select2 3.5.2 y versiones posteriores, puede 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};
    }
  },
});

(tomado de una respuesta en la lista de correo select2, pero no puedo encontrar el enlace ahora)

fmpwizard
fuente
44
Perdón por la respuesta tardía, pero muchas gracias por su solución. El otro póster, ¡publicó un enlace a tu esencia por cierto que te hace doblemente increíble! :)
johnjohn
rrauenza increíble, exactamente lo que estaba buscando
Matthias S
44
Agregar la selectOnBlur: truevoluntad hará el trabajo, consulte: stackoverflow.com/questions/25616520/…
Alireza Fattahi
1
Solo un aviso para futuros lectores, probablemente quieras usar tags: []junto con createSearchChoice.
Kevin Brown
55
El violín vinculado anteriormente parece roto.
Wolfr
175

La excelente respuesta proporcionada por @fmpwizard funciona para Select2 3.5.2 y posteriores, pero no funcionará en 4.0.0 .

Desde muy temprano (pero tal vez no tan temprano como esta pregunta), Select2 ha admitido "etiquetado": donde los usuarios pueden agregar su propio valor si se lo permite. Esto se puede habilitar a través de la tagsopción, y puede jugar con un ejemplo en la documentación .

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

Por defecto, esto creará una opción que tiene el mismo texto que el término de búsqueda que han ingresado. Puede modificar el objeto que se utiliza si desea marcarlo de una manera especial, o crear el objeto de forma remota una vez que se selecciona.

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

Además de servir como un indicador fácil de detectar en el objeto pasado a través del select2:selectevento, la propiedad adicional también le permite representar la opción de manera ligeramente diferente en el resultado. Entonces, si desea señalar visualmente el hecho de que es una nueva opción al poner " (nuevo) " al lado, puede hacer algo como esto.

$("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
fuente
Eso fue muy útil @ Markus1980Wien
abiieez
Creo que he usado este fragmento varias veces.
Sahu V Kumar
Si no funciona, verifique dos veces que haya agregado esta opción en select2, no agregue las opciones ajax. para select2 ajax
Zohaib
2
Su workign en la versión select2 (4.0.6) de esta manera: $ ("select"). Select2 ({tags: true, createTag: function (params) {return {id: params.term, text: params.term, newOption : true}}, templateResult: function (data) {var result = data.text; if (data.newOption) {result = result + '(new)';} return result;}}); gracias @Kevin Brown
M. Salah
Esta debería ser la mejor respuesta. He estado buscando durante un tiempo para esto, y esta opción responde a todas las preguntas que he visto sobre el tema.
Justin
14

Solo por mantener vivo el código, estoy publicando el código de @rrauenza Fiddle de su comentario .

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
fuente
2
Fui al violín, pero no parece estar funcionando para mí en Chrome. ¿Puedes confirmar?
IcedDante
@IcedDante el código está funcionando. el punto en el violín es solo mostrar cómo se debe hacer (la selección está oculta en el violín)
Michel Ayres
44
Cuando voy al violín, no veo un menú desplegable select2 en ninguna parte. ¿No sería bueno tener un ejemplo que en realidad ... haga algo?
IcedDante
¿Cómo puedo configurar los datos de una fuente externa? Quiero decir, ¿qué pasa si quiero cargar ciudades de un país seleccionado y el país seleccionado en sí mismo es un dropodown?
Ali Baig
12

Dado que muchas de estas respuestas no funcionan en 4.0+, si está utilizando ajax, puede hacer que el servidor agregue el nuevo valor como una opción. Entonces funcionaría así:

  1. El usuario busca valor (lo que hace una solicitud ajax al servidor)
  2. Si el valor se encuentra excelente, devuelva la opción. Si no, simplemente haga que el servidor agregue esa opción así:[{"text":" my NEW option)","id":"0"}]
  3. Cuando se envía el formulario, simplemente verifique si esa opción está en el DB y, si no, créelo antes de guardarlo.
Eric
fuente
6

Hay una mejor solución, creo que ahora

¿simplemente establece el etiquetado como verdadero en las opciones seleccionadas?

tags: true

de https://select2.org/tagging

Steven Moffat
fuente
4

Mejora en la respuesta 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
Vikash Singh
fuente
Utilicé esto con una ligera modificación. Pondré mi respuesta en un segundo pero gracias.
Sam
1
var text = 'New York Mills';
var term = 'new york mills';
return text.localeCompare(term)===0;

En la mayoría de los casos, necesitamos comparar valores con un registro insensible. Y este código devolverá falso, lo que conducirá a la creación de registros duplicados en la base de datos. Además, String.prototype.localeCompare () no es compatible con el navegador Safary y este código no funcionará en este navegador;

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

reemplazará mejor a

return this.text.toLowerCase() === term.toLowerCase();
muerto
fuente
1

Gracias por la ayuda chicos, usé el siguiente código dentro de Codeigniter II estoy usando la versión: 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]'};
        }
    },
});
Sam
fuente