Chosen automatically sets the default field text ("Choose a country...") by reading the select element's data-placeholder value. If no data-placeholder value is present, it will default to "Select an Option" or "Select Some Options" depending on whether the select is single or multiple. You can change these elements in the plugin js file as you see fit.
- <select data-placeholder="Choose a country..." style="width:350px;" multiple class="chosen-select">
+
<select data-placeholder="Choose a country..." multiple class="chosen-select">
Note: on single selects, the first element is assumed to be selected by the browser. To take advantage of the default text support, you will need to include a blank option as the first element of your select list.
When a single select box isn't a required field, you can set allow_single_deselect: true and Chosen will add a UI element for option deselection. This will only work if the first option has blank text.
+
When a single select box isn't a required field, you can set allow_single_deselect: true and Chosen will add a UI element for option deselection. This will only work if the first option has blank text.
When working with form fields, you often want to perform some behavior after a value has been selected or deselected. Whenever a user selects a field in Chosen, it triggers a "change" event* on the original form field. That let's you do something like this:
-
$("#form_field").chosen().change( … );
+
Observing Form Field Changes
+
When working with form fields, you often want to perform some behavior after a value has been selected or deselected. Whenever a user selects a field in Chosen, it triggers a "change" event on the original form field. That lets you do something like this:
+
$("#form_field").chosen().change( … );
Note: Prototype doesn't offer support for triggering standard browser events. Event.simulate is required to trigger the change event when using the Prototype version.
Updating Chosen Dynamically
If you need to update the options in your select field and want Chosen to pick up the changes, you'll need to trigger the "chosen:updated" event on the field. Chosen will re-build itself based on the updated content.
-
-
Event.fire($("form_field"), "chosen:updated");
-
+
Event.fire($("form_field"), "chosen:updated");
+
+
+
Destroying Chosen
+
To destroy Chosen and revert back to the native select, call destroy on the Chosen instance:
+
chosen = new Chosen($("form_field"));
+
+// ...later
+chosen.destroy();
Yes! Please report all issues using the GitHub issue tracking tool. Please include the plugin version (jQuery or Prototype), browser and OS. The more information provided, the easier it is to fix a problem.
What browsers are supported?
-
All modern browsers are supported (Firefox, Chrome, Safari and IE9). Legacy support for IE8 is also enabled.
+
All modern desktop browsers are supported (Firefox, Chrome, Safari and IE9). Legacy support for IE8 is also enabled. Chosen is disabled on iPhone, iPod Touch, and Android mobile devices (more information).
Chosen has a number of options and attributes that allow you to have full control of your select boxes.
@@ -86,6 +86,11 @@
Example:
false
By default, Chosen’s search matches starting at the beginning of a word. Setting this option to true allows matches starting from anywhere within a word. This is especially useful for options that include a lot of special characters or phrases in ()s and []s.
+
+
group_search
+
true
+
By default, Chosen will search group labels as well as options, and filter to show all options below matching groups. Set this to false to search only in the options.
+
single_backstroke_delete
true
@@ -127,14 +132,14 @@
Example:
case_sensitive_search
false
-
By default Chosen's search is case-insensitive. Setting this option to true makes the search case-sensitive.
+
By default, Chosen's search is case-insensitive. Setting this option to true makes the search case-sensitive.
hide_results_on_select
true
-
By default Chosen's results are hidden after a option is selected. Setting this option to false will keep the results open after selection. This only applies to multiple selects.
+
By default, Chosen's results are hidden after a option is selected. Setting this option to false will keep the results open after selection. This only applies to multiple selects.
@@ -204,7 +209,7 @@
Example:
Chosen supports right-to-left text in select boxes. Add the class chosen-rtl to your select tag to support right-to-left text options.
Note: The chosen-rtl class will pass through to the Chosen select even when the inherit_select_classes option is set to false.
-
Note: This is deprecated in favor of using the rtl: true option (see the Options section).
+
Note: This is deprecated in favor of using the rtl: true option (see the Options section).
").html(tmpl)
select = div.find("select")
- expect(select.size()).toBe(1)
+ expect(select.length).toBe(1)
select.chosen()
# very simple check that the necessary elements have been created
["container", "container-single", "single", "default"].forEach (clazz)->
el = div.find(".chosen-#{clazz}")
- expect(el.size()).toBe(1)
+ expect(el.length).toBe(1)
# test a few interactions
expect(select.val()).toBe ""
@@ -44,7 +44,7 @@ describe "Basic setup", ->
"
div = $("
").html(tmpl)
select = div.find("select")
- expect(select.size()).toBe(1)
+ expect(select.length).toBe(1)
select.chosen()
# very simple check that the necessary elements have been created
["container", "container-single", "single", "default"].forEach (clazz)->
el = div.find(".chosen-#{clazz}")
- expect(el.size()).toBe(1)
+ expect(el.length).toBe(1)
# test a few interactions
event_sequence = []
diff --git a/spec/jquery/max_shown_results.spec.coffee b/spec/jquery/max_shown_results.spec.coffee
index e37cb23b475..e329e16fc8a 100644
--- a/spec/jquery/max_shown_results.spec.coffee
+++ b/spec/jquery/max_shown_results.spec.coffee
@@ -16,7 +16,7 @@ describe "search", ->
container.trigger("mousedown") # open the drop
# Expect all results to be shown
results = div.find(".active-result")
- expect(results.size()).toBe(3)
+ expect(results.length).toBe(3)
# Enter some text in the search field.
search_field = div.find(".chosen-search input").first()
@@ -25,7 +25,7 @@ describe "search", ->
# Expect to only have one result: 'Afghanistan'.
results = div.find(".active-result")
- expect(results.size()).toBe(1)
+ expect(results.length).toBe(1)
expect(results.first().text()).toBe "Afghanistan"
it "should only show max_shown_results items in results", ->
@@ -44,7 +44,7 @@ describe "search", ->
container = div.find(".chosen-container")
container.trigger("mousedown") # open the drop
results = div.find(".active-result")
- expect(results.size()).toBe(1)
+ expect(results.length).toBe(1)
# Enter some text in the search field.
search_field = div.find(".chosen-search input").first()
@@ -53,12 +53,12 @@ describe "search", ->
# Showing only one result: the one that occurs first.
results = div.find(".active-result")
- expect(results.size()).toBe(1)
+ expect(results.length).toBe(1)
expect(results.first().text()).toBe "United States"
# Showing still only one result, but not the first one.
search_field.val("United Ki")
search_field.trigger("keyup")
results = div.find(".active-result")
- expect(results.size()).toBe(1)
+ expect(results.length).toBe(1)
expect(results.first().text()).toBe "United Kingdom"
diff --git a/spec/jquery/searching.spec.coffee b/spec/jquery/searching.spec.coffee
new file mode 100644
index 00000000000..d17f62f85bc
--- /dev/null
+++ b/spec/jquery/searching.spec.coffee
@@ -0,0 +1,281 @@
+describe "Searching", ->
+ it "should not match the actual text of HTML entities", ->
+ tmpl = "
+
+
+
+
+
+ "
+
+ div = $("
").html(tmpl)
+ select = div.find("select")
+ select.chosen({search_contains: true})
+
+ container = div.find(".chosen-container")
+ container.trigger("mousedown") # open the drop
+
+ # Both options should be active
+ results = div.find(".active-result")
+ expect(results.length).toBe(2)
+
+ # Search for the html entity by name
+ search_field = div.find(".chosen-search input").first()
+ search_field.val("mp")
+ search_field.trigger("keyup")
+
+ results = div.find(".active-result")
+ expect(results.length).toBe(0)
+
+ it "renders options correctly when they contain characters that require HTML encoding", ->
+ div = $("
").html("""
+
+
+
+ """)
+
+ div.find("select").chosen()
+ div.find(".chosen-container").trigger("mousedown") # open the drop
+
+ expect(div.find(".active-result").length).toBe(1)
+ expect(div.find(".active-result").first().html()).toBe("A & B")
+
+ search_field = div.find(".chosen-search-input").first()
+ search_field.val("A")
+ search_field.trigger("keyup")
+
+ expect(div.find(".active-result").length).toBe(1)
+ expect(div.find(".active-result").first().html()).toBe("A & B")
+
+ it "renders optgroups correctly when they contain html encoded tags", ->
+ div = $("
").html("""
+
+
+
+ """)
+
+ div.find("select").chosen()
+ div.find(".chosen-container").trigger("mousedown") # open the drop
+
+ expect(div.find(".group-result").length).toBe(1)
+ expect(div.find(".group-result").first().html()).toBe("A <b>hi</b> B")
+
+ it "renders optgroups correctly when they contain characters that require HTML encoding when searching", ->
+ div = $("
").html("""
+
+
+
+ """)
+
+ div.find("select").chosen()
+ div.find(".chosen-container").trigger("mousedown") # open the drop
+
+ expect(div.find(".group-result").length).toBe(1)
+ expect(div.find(".group-result").first().html()).toBe("A & B")
+
+ search_field = div.find(".chosen-search-input").first()
+ search_field.val("A")
+ search_field.trigger("keyup")
+
+ expect(div.find(".group-result").length).toBe(1)
+ expect(div.find(".group-result").first().html()).toBe("A & B")
+
+ it "renders no results message correctly when it contains characters that require HTML encoding", ->
+ div = $("
").html("""
+
+
+
+ """)
+
+ div.find("select").chosen()
+ div.find(".chosen-container").trigger("mousedown") # open the drop
+
+ search_field = div.find(".chosen-search-input").first()
+ search_field.val("&")
+ search_field.trigger("keyup")
+
+ expect(div.find(".no-results").length).toBe(1)
+ expect(div.find(".no-results").first().html().trim()).toBe("No results match &")
+
+ search_field.val("&")
+ search_field.trigger("keyup")
+
+ expect(div.find(".no-results").length).toBe(1)
+ expect(div.find(".no-results").first().html().trim()).toBe("No results match &")
+
+ it "matches in non-ascii languages like Chinese when selecting a single item", ->
+ div = $("
").html("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ div.find("select").chosen()
+ div.find(".chosen-container").trigger("mousedown") # open the drop
+
+ expect(div.find(".active-result").length).toBe(12)
+
+ search_field = div.find(".chosen-search-input").first()
+ search_field.val("一")
+ search_field.trigger("keyup")
+
+ expect(div.find(".active-result").length).toBe(1)
+ expect(div.find(".active-result")[0].innerHTML).toBe("一")
+
+ it "matches in non-ascii languages like Chinese when selecting a single item with search_contains", ->
+ div = $("
").html("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ div.find("select").chosen({search_contains: true})
+ div.find(".chosen-container").trigger("mousedown") # open the drop
+
+ expect(div.find(".active-result").length).toBe(12)
+
+ search_field = div.find(".chosen-search-input").first()
+ search_field.val("一")
+ search_field.trigger("keyup")
+
+ expect(div.find(".active-result").length).toBe(2)
+ expect(div.find(".active-result")[0].innerHTML).toBe("一")
+ expect(div.find(".active-result")[1].innerHTML).toBe("十一")
+
+ it "matches in non-ascii languages like Chinese when selecting multiple items", ->
+ div = $("
").html("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ div.find("select").chosen()
+ div.find(".chosen-container").trigger("mousedown") # open the drop
+
+ expect(div.find(".active-result").length).toBe(12)
+
+ search_field = div.find(".chosen-search-input")
+ search_field.val("一")
+ search_field.trigger("keyup")
+
+ expect(div.find(".active-result").length).toBe(1)
+ expect(div.find(".active-result")[0].innerHTML).toBe("一")
+
+ it "matches in non-ascii languages like Chinese when selecting multiple items with search_contains", ->
+ div = $("
").html("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ div.find("select").chosen({search_contains: true})
+ div.find(".chosen-container").trigger("mousedown") # open the drop
+
+ expect(div.find(".active-result").length).toBe(12)
+
+ search_field = div.find(".chosen-search-input")
+ search_field.val("一")
+ search_field.trigger("keyup")
+
+ expect(div.find(".active-result").length).toBe(2)
+ expect(div.find(".active-result")[0].innerHTML).toBe("一")
+ expect(div.find(".active-result")[1].innerHTML).toBe("十一")
+
+ it "highlights results correctly when multiple words are present", ->
+ div = $("
").html("""
+
+
+
+ """)
+
+ div.find("select").chosen()
+ div.find(".chosen-container").trigger("mousedown") # open the drop
+
+ expect(div.find(".active-result").length).toBe(1)
+
+ search_field = div.find(".chosen-search-input")
+ search_field.val("h")
+ search_field.trigger("keyup")
+
+ expect(div.find(".active-result").length).toBe(1)
+ expect(div.find(".active-result")[0].innerHTML).toBe("oh hello")
+
+ describe "respects word boundaries when not using search_contains", ->
+ div = $("
").html("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ div.find("select").chosen()
+ div.find(".chosen-container").trigger("mousedown") # open the drop
+
+ search_field = div.find(".chosen-search-input")
+
+ div.find("option").each () ->
+ boundary_thing = this.value.slice(1)
+ it "correctly finds words that start after a(n) #{boundary_thing}", ->
+ search_field.val(boundary_thing)
+ search_field.trigger("keyup")
+ expect(div.find(".active-result").length).toBe(1)
+ expect(div.find(".active-result")[0].innerText.slice(1)).toBe(boundary_thing)
diff --git a/spec/proto/searching.spec.coffee b/spec/proto/searching.spec.coffee
new file mode 100644
index 00000000000..457396b95d2
--- /dev/null
+++ b/spec/proto/searching.spec.coffee
@@ -0,0 +1,293 @@
+describe "Searching", ->
+ it "should not match the actual text of HTML entities", ->
+ tmpl = "
+
+
+
+
+
+ "
+
+ div = new Element('div')
+ document.body.insert(div)
+ div.update(tmpl)
+ select = div.down('select')
+ new Chosen(select, {search_contains: true})
+
+ container = div.down('.chosen-container')
+ simulant.fire(container, 'mousedown') # open the drop
+
+ # Both options should be active
+ results = div.select('.active-result')
+ expect(results.length).toBe(2)
+
+ # Search for the html entity by name
+ search_field = div.down(".chosen-search input")
+ search_field.value = "mp"
+ simulant.fire(search_field, 'keyup')
+
+ results = div.select(".active-result")
+ expect(results.length).toBe(0)
+
+ it "renders options correctly when they contain characters that require HTML encoding", ->
+ div = new Element("div")
+ div.update("""
+
+
+
+ """)
+
+ new Chosen(div.down("select"))
+ simulant.fire(div.down(".chosen-container"), "mousedown") # open the drop
+
+ expect(div.select(".active-result").length).toBe(1)
+ expect(div.down(".active-result").innerHTML).toBe("A & B")
+
+ search_field = div.down(".chosen-search-input")
+ search_field.value = "A"
+ simulant.fire(search_field, "keyup")
+
+ expect(div.select(".active-result").length).toBe(1)
+ expect(div.down(".active-result").innerHTML).toBe("A & B")
+
+ it "renders optgroups correctly when they contain characters that require HTML encoding", ->
+ div = new Element("div")
+ div.update("""
+
+
+
+ """)
+
+ new Chosen(div.down("select"))
+ simulant.fire(div.down(".chosen-container"), "mousedown") # open the drop
+
+ expect(div.select(".group-result").length).toBe(1)
+ expect(div.down(".group-result").innerHTML).toBe("A <b>hi</b> B")
+
+ it "renders optgroups correctly when they contain characters that require HTML encoding when searching", ->
+ div = new Element("div")
+ div.update("""
+
+
+
+ """)
+
+ new Chosen(div.down("select"))
+ simulant.fire(div.down(".chosen-container"), "mousedown") # open the drop
+
+ expect(div.select(".group-result").length).toBe(1)
+ expect(div.down(".group-result").innerHTML).toBe("A & B")
+
+ search_field = div.down(".chosen-search-input")
+ search_field.value = "A"
+ simulant.fire(search_field, "keyup")
+
+ expect(div.select(".group-result").length).toBe(1)
+ expect(div.down(".group-result").innerHTML).toBe("A & B")
+
+ it "renders no results message correctly when it contains characters that require HTML encoding", ->
+ div = new Element("div")
+ div.update("""
+
+
+
+ """)
+
+ new Chosen(div.down("select"))
+ simulant.fire(div.down(".chosen-container"), "mousedown") # open the drop
+
+ search_field = div.down(".chosen-search-input")
+ search_field.value = "&"
+ simulant.fire(search_field, "keyup")
+
+ expect(div.select(".no-results").length).toBe(1)
+ expect(div.down(".no-results").innerHTML.trim()).toBe("No results match &")
+
+ search_field.value = "&"
+ simulant.fire(search_field, "keyup")
+
+ expect(div.select(".no-results").length).toBe(1)
+ expect(div.down(".no-results").innerHTML.trim()).toBe("No results match &")
+
+ it "matches in non-ascii languages like Chinese when selecting a single item", ->
+ div = new Element("div")
+ div.update("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ new Chosen(div.down("select"))
+ simulant.fire(div.down(".chosen-container"), "mousedown") # open the drop
+
+ expect(div.select(".active-result").length).toBe(12)
+
+ search_field = div.down(".chosen-search-input")
+ search_field.value = "一"
+ simulant.fire(search_field, "keyup")
+
+ expect(div.select(".active-result").length).toBe(1)
+ expect(div.select(".active-result")[0].innerHTML).toBe("一")
+
+ it "matches in non-ascii languages like Chinese when selecting a single item with search_contains", ->
+ div = new Element("div")
+ div.update("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ new Chosen(div.down("select"), {search_contains: true})
+ simulant.fire(div.down(".chosen-container"), "mousedown") # open the drop
+
+ expect(div.select(".active-result").length).toBe(12)
+
+ search_field = div.down(".chosen-search-input")
+ search_field.value = "一"
+ simulant.fire(search_field, "keyup")
+
+ expect(div.select(".active-result").length).toBe(2)
+ expect(div.select(".active-result")[0].innerHTML).toBe("一")
+ expect(div.select(".active-result")[1].innerHTML).toBe("十一")
+
+ it "matches in non-ascii languages like Chinese when selecting multiple items", ->
+ div = new Element("div")
+ div.update("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ new Chosen(div.down("select"))
+ simulant.fire(div.down(".chosen-container"), "mousedown") # open the drop
+
+ expect(div.select(".active-result").length).toBe(12)
+
+ search_field = div.down(".chosen-search-input")
+ search_field.value = "一"
+ simulant.fire(search_field, "keyup")
+
+ expect(div.select(".active-result").length).toBe(1)
+ expect(div.select(".active-result")[0].innerHTML).toBe("一")
+
+ it "matches in non-ascii languages like Chinese when selecting multiple items with search_contains", ->
+ div = new Element("div")
+ div.update("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ new Chosen(div.down("select"), {search_contains: true})
+ simulant.fire(div.down(".chosen-container"), "mousedown") # open the drop
+
+ expect(div.select(".active-result").length).toBe(12)
+
+ search_field = div.down(".chosen-search-input")
+ search_field.value = "一"
+ simulant.fire(search_field, "keyup")
+
+ expect(div.select(".active-result").length).toBe(2)
+ expect(div.select(".active-result")[0].innerHTML).toBe("一")
+ expect(div.select(".active-result")[1].innerHTML).toBe("十一")
+
+ it "highlights results correctly when multiple words are present", ->
+ div = new Element("div")
+ div.update("""
+
+
+
+ """)
+
+ new Chosen(div.down("select"))
+ simulant.fire(div.down(".chosen-container"), "mousedown") # open the drop
+
+ expect(div.select(".active-result").length).toBe(1)
+
+ search_field = div.down(".chosen-search-input")
+ search_field.value = "h"
+ simulant.fire(search_field, "keyup")
+
+ expect(div.select(".active-result").length).toBe(1)
+ expect(div.select(".active-result")[0].innerHTML).toBe("oh hello")
+
+ describe "respects word boundaries when not using search_contains", ->
+ div = new Element("div")
+ div.update("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ new Chosen(div.down("select"))
+ simulant.fire(div.down(".chosen-container"), "mousedown") # open the drop
+
+ search_field = div.down(".chosen-search-input")
+
+ div.select("option").forEach (option) ->
+ boundary_thing = option.value.slice(1)
+ it "correctly finds words that start after a(n) #{boundary_thing}", ->
+ search_field.value = boundary_thing
+ simulant.fire(search_field, "keyup")
+ expect(div.select(".active-result").length).toBe(1)
+ expect(div.select(".active-result")[0].innerText.slice(1)).toBe(boundary_thing)
diff --git a/tasks/package.coffee b/tasks/package.coffee
index 8578e3d7e29..70f1e997d97 100644
--- a/tasks/package.coffee
+++ b/tasks/package.coffee
@@ -24,6 +24,7 @@ module.exports = (grunt) ->
grunt.registerTask 'package-npm', 'Generate npm manifest', () ->
pkg = grunt.config.get('pkg')
+ extra = pkg._extra
json =
name: "#{pkg.name}-js"
@@ -35,8 +36,8 @@ module.exports = (grunt) ->
license: pkg.license
contributors: pkg.contributors
dependencies: pkg.dependencies
- files: pkg._extra.files
- main: pkg._extra.files[0]
+ files: extra.files
+ main: extra.main[0]
repository: pkg.repository
grunt.file.write('public/package.json', JSON.stringify(json, null, 2) + "\n")
@@ -53,7 +54,7 @@ module.exports = (grunt) ->
license: extra.license.url
authors: pkg.contributors
dependencies: pkg.dependencies
- main: extra.files
+ main: extra.main
ignore: []
repository: pkg.repository