Is there a way to dynamically ajax add elements through jquery chosen plugin?

Shreeni picture Shreeni · Mar 13, 2012 · Viewed 20k times · Source

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.)

Answer

Shreeni picture Shreeni · Mar 14, 2012

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.