I am trying to use "Chosen" plugin by harvest (http://harvesthq.github.com/chosen/) and it works for the static set of options I am passing. However, what I want is that whenever anybody types something that is not in the pre-filled options, then it should send that to the server as a new option and on successful response, I want to not only add that to the valid list of options, but also make it select it.
Reloading the options is fairly simple:
// In ajax response
var newOption = new Option("Text", __value__);
$("#tagSelection").append(newOption);
$("#tagSelection").trigger("liszt:updated");
However, I don't know how to make "Chosen" plugin pick this as the value. I would love to do something like
$("#tagSelection").trigger("liszt:select:__value__");
or something similar.
Any suggestions?
(ps: I am trying to build a "tagging" plugin based on chosen. So, if the tag being typed doesn't exist, it will add it to the server and then select it straight away.)
I've just been doing this. I didn't like Shreeni's line for setting selected (no offence) so i went with
$('#tagSelection').append(
$('<option></option>')
.val(data.Item.Id)
.html(data.Item.Value)
.attr("selected", "selected"));
$("#tagSelection").trigger("liszt:updated");
which i personally think is a bit cleaner (tested with multiselect box and it works fine)
These are the complete set of changes I did to the chosen plugin (jquery version) to solve this problem
Chosen.prototype.choice_build = function(item) {
this.new_term_to_be_added = null;
// ....
};
Chosen.prototype.no_results = function(terms) {
// ....
no_results_html.find("span").first().html(terms);
this.new_term_to_be_added = terms;
return this.search_results.append(no_results_html);
};
Chosen.prototype.keydown_checker = function(evt) {
// ...
case 13:
if(this.new_term_to_be_added != null && this.options.addNewElementCallback != null) {
var newElement = this.options.addNewElementCallback(this.new_term_to_be_added);
if(newElement!=null && newElement.length == 1) {
// KEY TO SOLVING THIS PROBLEM
this.result_highlight = newElement;
// This will automatically trigger the change/select events also.
// Nothing more required.
this.result_select(evt);
}
this.new_term_to_be_added = null;
}
evt.preventDefault();
break;
// ...
};
The this.new_term_to_be_added maintains the currently typed string which is not among the pre-defined options.
The options.addNewElementCallback is the callback to the calling function to allow them to process it (send it to server etc.) and it has to be synchronous. Below is the skeleton:
var addTagCallback = function(tagText) {
var newElement = null;
$.ajax({url : that.actionUrl,
async : false,
dataType: "json",
data : { // ....},
success : function(response) {
if(response) {
$('#tagSelection').append(
$('<option></option>')
.val(data.Item.Id)
.html(data.Item.Value)
.attr("selected", "selected"));
$("#tagSelection").trigger("liszt:updated");
// Get the element - will necessarily be the last element - so the following selector will work
newElement = $("#tagSelection_chzn li#tagSelection_chzn_o_" + ($("#tagSelection option").length - 1));
} else {
// Handle Error
}
}});
return newElement;
};
The newElement is a jquery element - the latest added li object to list of options.
By doing this.result_highlight = newElement; and this.result_select(evt); I tell the Chosen plugin to select this. This works whether it is a single select or a multi-select. Rifky's solution will work only for single select.
A fork containing the feature you want has been created here. This fork is referred to as the koenpunt fork.
You can follow through the discussion for this feature on the harvesthq github site
My summary of what happened:
Since version 1.0 some of the suggestions above are not relevant any longer. Here is all that is needed:
--- /home/lauri/Downloads/chosen_v1.0.0 (original)/chosen.jquery.js
+++ /home/lauri/Downloads/chosen_v1.0.0 (modified)/chosen.jquery.js
@@ -408,8 +408,18 @@
break;
case 13:
evt.preventDefault();
- if (this.results_showing) {
+ if (this.results_showing && this.result_highlight) {
return this.result_select(evt);
+ }
+ var new_term_to_be_added = this.search_field.val();
+ if(new_term_to_be_added && this.options.add_term_callback != null) {
+ var newTermID = this.options.add_term_callback(new_term_to_be_added);
+ if(newTermID) {
+ this.form_field_jq.append(
+ $('<option></option>').val(newTermID).html(new_term_to_be_added).attr("selected", "selected")
+ );
+ this.form_field_jq.trigger("chosen:updated");
+ }
}
break;
case 27:
The options are as follows:
{add_term_callback: addTagCallback, no_results_text:'Press Enter to add:'}
This means that if "Orange" is not in the list of fruits, it would simply prompt:
Press Enter to add: "Orange"
The callback should register the new term by whatever means necessary and return the ID (or value in the context of the underlying select element) for the new option.
var addTagCallback = function(tagText) {
// do some synchronous AJAX
return tagID;
};
I do it simply this way and it works perfectly:
// this variable can be filled by an AJAX call or so
var optionsArray = [
{"id": 1, "name": "foo"},
{"id": 2, "name": "bar"}
];
var myOptions = "<option value></option>";
for(var i=0; i<optionsArray.length; i++){
myOptions += '<option value="'+optionsArray[i].id+'">'+optionsArray[i].name+'</option>';
}
// uses new "chosen" names instead of "liszt"
$(".chosen-select").html(myOptions).chosen().trigger("chosen:updated");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With