Permitir nuevos valores con select múltiples elegidos. JS Seleccionar
-
29-10-2019 - |
Pregunta
Estoy usando el complemento elegido.js http://harvesthq.github.com/chosen/ con jQuery para permitir que el usuario seleccione múltiples opciones de una selección. Sin embargo, ahora quiero poder dejarlos crear Valores que aún no están presentes: ¿alguna idea de cómo hacer esto?
EDITAR: Algo similar a la propia barra de selección de etiquetas/creación de SO estaría cerca de lo que estoy buscando
Preferiblemente sin cambiar o editar el complemento, pero lo hará si es necesario.
El código: HTML:
<p>Select something</p>
<select name="theSelect[]" multiple="multiple">
<option value="First Option">First Option</option>
<option value="Second Option">Second Option</option>
</select>
JavaScript:
$(function(){
$('select').chosen();
});
Entonces, si un usuario escribiera "tercera opción", me gustaría agregar eso a la lista y seleccionarla. El valor y el nombre de la pantalla son / serán los mismos, por lo que no es una preocupación
Solución
Según la documentación, puede intentar hacer algo como esto:
$('select').append('<option>test</option>');
$('select').trigger('liszt:updated');
Como Tony dijo en los comentarios a continuación:
"Comenzando con la versión 1.0 que el disparador ahora es" elegido: actualizado ". Ver harvesthq.github.io/chosen/#change-update-events"
Otros consejos
Me topé con esto buscando las mismas ideas. Parece que es una solicitud de funciones bastante popular, y un par de tenedores la han implementado. Parece que pronto se fusionará en la rama maestra.
+1 para este tirón en particular que funcionó un encanto:https://github.com/harvesthq/chosen/pull/166
Puedes ver el bifurcado de Koenpunt aquí: https://github.com/koenpunt/chosen
Aquí hay una forma simple en que lo hice:
$(".search-field").find("input").live( "keydown", function (evt) {
var stroke;
stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
if (stroke == 9) { // 9 = tab key
$('#tags').append('<option value="' + $(this).val() + '" selected="selected">' + $(this).val() + '</option>');
$('#tags').trigger('chosen:updated');
}
});
Solo estaba tratando de resolver el mismo problema. Terminé modificando un poco el código fuente. Aquí está la nueva función KeyUp_Checker. Eche un vistazo al caso 13:
AbstractChosen.prototype.keyup_checker = function(evt) {
var stroke, _ref;
stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
this.search_field_scale();
switch (stroke) {
case 8:
if (this.is_multiple && this.backstroke_length < 1 && this.choices > 0) {
return this.keydown_backstroke();
} else if (!this.pending_backstroke) {
this.result_clear_highlight();
return this.results_search();
}
break;
case 13:
evt.preventDefault();
if (this.results_showing) {
if (!this.is_multiple || this.result_highlight) {
return this.result_select(evt);
}
$(this.form_field).append('<option>' + $(evt.target).val() + '</option>');
$(this.form_field).trigger('liszt:updated');
this.result_highlight = this.search_results.find('li.active-result').last();
return this.result_select(evt);
}
break;
case 27:
if (this.results_showing) this.results_hide();
return true;
case 9:
case 38:
case 40:
case 16:
case 91:
case 17:
break;
default:
return this.results_search();
}
};
Sé que esta no es la respuesta, sino una solución alternativa.
Estaba buscando la parte adición de la marcha y descubrí que http://ivaynberg.github.com/select2/#tags Proporciona lo mismo que elegido + otras cosas como "etiquetado".
Puede adjuntar un evento al cuadro de texto de entrada para escuchar un código de caracteres en particular. Después de eso, agregue la opción y active la actualización en el menú desplegable.
var dropDown = $('select.chosen');
dropDown.parent().find('.chzn-container .chzn-search input[type=text]').keydown( function (evt) {
var stroke, _ref, target, list;
// get keycode
stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
target = $(evt.target);
// get the list of current options
list = target.parents('.chzn-container').find('.chzn-choices li.search-choice > span').map(function () { return $(this).text(); }).get();
if (stroke === 9 || stroke === 13) {
var value = $.trim(target.val());
// if the option does not exists
if ($.inArray(value,list) < 0) {
var option = $('<option>');
option.text(value).val(value).appendTo(dropDown);
option.attr('selected','selected');
// add the option and set as selected
}
// trigger the update event
dropDown.trigger("liszt:updated");
return true;
}
});
Una actualización de la respuesta de Leogdion que funciona con versiones posteriores de elegido:
var dropDown = $('#select_chosen');
// Make the chosen drop-down dynamic. If a given option is not in the list, the user can still add it
dropDown.parent().find('.chosen-container .search-field input[type=text]').keydown(
function (evt) {
var stroke, _ref, target, list;
// get keycode
stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
// If enter or tab key
if (stroke === 9 || stroke === 13) {
target = $(evt.target);
// get the list of current options
chosenList = target.parents('.chosen-container').find('.chosen-choices li.search-choice > span').map(function () { return $(this).text(); }).get();
// get the list of matches from the existing drop-down
matchList = target.parents('.chosen-container').find('.chosen-results li').map(function () { return $(this).text(); }).get();
// highlighted option
highlightedList = target.parents('.chosen-container').find('.chosen-results li.highlighted').map(function () { return $(this).text(); }).get();
// Get the value which the user has typed in
var newString = $.trim(target.val());
// if the option does not exists, and the text doesn't exactly match an existing option, and there is not an option highlighted in the list
if ($.inArray(newString,matchList) < 0 && $.inArray(newString,chosenList) < 0 && highlightedList.length == 0) {
// Create a new option and add it to the list (but don't make it selected)
var newOption = '<option value="' + newString + '">' + newString + '</option>';
$("#select").prepend(newOption);
// trigger the update event
$("#select").trigger("chosen:updated");
// tell chosen to close the list box
$("#select").trigger("chosen:close");
return true;
}
// otherwise, just let the event bubble up
return true;
}
}
)
He actualizado el código de 3nochroot una vez más. Ahora solo tengo un selector para encontrar la entrada multiselección.
$(document).ready(function() {
$(".js-choicelist").chosen({
//config comes here
}).parent().find('.chosen-container .search-field input[type=text]').keydown(
function (evt) {
var stroke, _ref, target, list;
// get keycode
stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
// If enter or tab key
if (stroke === 9 || stroke === 13) {
target = $(evt.target);
// get the list of current options
chosenList = target.parents('.chosen-container').find('.chosen-choices li.search-choice > span').map(function () { return $(this).text(); }).get();
// get the list of matches from the existing drop-down
matchList = target.parents('.chosen-container').find('.chosen-results li').map(function () { return $(this).text(); }).get();
// highlighted option
highlightedList = target.parents('.chosen-container').find('.chosen-results li.highlighted').map(function () { return $(this).text(); }).get();
// Get the value which the user has typed in
var newString = $.trim(target.val());
// if the option does not exists, and the text doesn't exactly match an existing option, and there is not an option highlighted in the list
if ($.inArray(newString,matchList) < 0 && $.inArray(newString,chosenList) < 0 && highlightedList.length == 0) {
// Create a new option and add it to the list (but don't make it selected)
var newOption = '<option value="' + newString + '">' + newString + '</option>';
var choiceSelect = target.parents('.select-multiple').find('select');
choiceSelect.prepend(newOption);
// trigger the update event
choiceSelect.trigger("chosen:updated");
// tell chosen to close the list box
choiceSelect.trigger("chosen:close");
return true;
}
// otherwise, just let the event bubble up
return true;
}
}
)
})
Actualización de la respuesta de Leogdion para múltiples select (esencia)
$(".chosen-select-with-add-new").chosen({
no_results_text: "Click Enter or Tab to add new option",
width: '100%'
}).parent().find('.chosen-container .search-field input[type=text]').keydown(function (evt) {
// get keycode
const stroke = evt.which != null ? evt.which : evt.keyCode;
// If enter or tab key
if (stroke === 9 || stroke === 13) {
const target = $(evt.target);
// get the list of current options
const chosenList = target.parents('.chosen-container').find('.chosen-choices li.search-choice > span').map(function () { return $(this).text(); }).get();
// get the list of matches from the existing drop-down
const matchList = target.parents('.chosen-container').find('.chosen-results li').map(function () { return $(this).text(); }).get();
// highlighted option
const highlightedList = target.parents('.chosen-container').find('.chosen-results li.highlighted').map(function () { return $(this).text(); }).get();
// Get the value which the user has typed in
const newString = $.trim(target.val());
// if the option does not exists, and the text doesn't exactly match an existing option, and there is not an option highlighted in the list
if ($.inArray(newString, matchList) < 0 && $.inArray(newString,chosenList) < 0 && highlightedList.length == 0) {
// Create a new option and add it to the list (but don't make it selected)
const newOption = '<option value="' + newString + '" selected="selected">' + newString + '</option>';
const choiceSelect = target.parents('.chosen-container').siblings('.chosen-select-with-add-new');
choiceSelect.append(newOption);
// trigger the update event
choiceSelect.trigger("chosen:updated");
// tell chosen to close the list box
choiceSelect.trigger("chosen:close");
return true;
}
// otherwise, just let the event bubble up
return true;
}
})
Ejemplo de uso en rieles (delgados)
.tag-list
label.control-label.h5 Tag list
= select_tag :tag_list, options_for_select(ActsAsTaggableOn::Tag.order('taggings_count desc').pluck(:name), @publication.tags.map(&:name)), multiple: true, data: { placeholder: 'north, east, south, west' }, class: 'chosen-select-with-add-new'
Probé varias soluciones que se dieron aquí y en otro lugar, sin embargo, ninguna funcionó en Eleged.js 1.8.5 (jQuery: 3.3.1) y así terminé con lo siguiente ya que no quería usar un tenedor que no siempre estuviera arriba -Selando a la rama maestra:
Por el caso de que no quiera .chosen-select
Para permitir nuevos valores, agregué una nueva clase .chosen-newValuesAllowed
. Establecí un controlador de eventos en esta clase donde CTRL + I agrega el nuevo valor si aún no está presente. El enfoque en el campo de entrada no se pierde después. En mi ejemplo, verifico el InnerHTML del Dado que @Value realmente contiene ID de base de datos y, por lo tanto, el nuevo valor, que es una cadena en mi ejemplo que el servidor procesaría más tarde, nunca podría encontrarse en @Value. Si desea verificar @Value, consulte el comentario dentro del fragmento. El código maneja seleccions simples y múltiples.
$(document).on("keydown", ".chosen-container.chosen-newValuesAllowed input", function(e) {
if (e.ctrlKey === true && e.keyCode === 73) { // CTRL + I
e.preventDefault();
var newValue = $(this).val();
if (newValue) {
try {
// only add if there is no option having the content/text of "input" yet!
// instead of filter() for the content of <option> you can check on its @value by: find("option[val='...']")
var $selectElement = $(e.target).closest("div.chosen-container").prev(); // the previous sibling should be the <select>. If not, grab it some other way, e.g. via @id
if (!$selectElement.find("option").filter(function () { return $(this).html() === newValue; }).length) {
if (!$selectElement.attr("multiple")) { // unselect for single-select
$selectElement.val('');
}
$selectElement.append('<option val="' + newValue + '" selected>' + newValue + '</option>');
$selectElement.trigger('chosen:updated');
}
} catch(error) {
// pass
}
e.target.focus();
}
return false;
}
});
Otra solución sería llamar a la función desencadenable Elegido: NO_RESULTS Si solo se deben agregar valores nuevos si explícitamente no es un resultado:
$(".chosen-select.chosen-newValuesAllowed").on("chosen:no_results", function(e, data){
var newValue = data.chosen.get_search_text();
...
});