Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Don't have .val() return selected-but-disabled options, or selected o…

…ptions inside a disabled optgroup. Doesn't change the .val() returned for a disabled select. Fixes #3240, adapted from Nathan Hammond's patch there.
  • Loading branch information...
commit 2c4b20809e5d32e916c479c9b63a6b7528c880ce 1 parent 700ff05
Dave Methvin dmethvin authored jeresig committed
6 src/attributes.js
@@ -163,8 +163,10 @@ jQuery.fn.extend({
163 163 for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
164 164 var option = options[ i ];
165 165
166   - if ( option.selected ) {
167   - // Get the specifc value for the option
  166 + // Don't return options that are disabled or in a disabled optgroup
  167 + if ( option.selected && !option.disabled &&
  168 + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
  169 + // Get the specific value for the option
168 170 value = jQuery(option).val();
169 171
170 172 // We don't need an array for one selects
9 test/index.html
@@ -114,6 +114,15 @@ <h2 id="qunit-userAgent"></h2>
114 114 <option id="option3d" value="3">3</option>
115 115 <option id="option3e">no value</option>
116 116 </select>
  117 + <select name="select4" id="select4" multiple="multiple">
  118 + <optgroup disabled="disabled">
  119 + <option id="option4a" class="emptyopt" value="">Nothing</option>
  120 + <option id="option4b" disabled="disabled" selected="selected" value="1">1</option>
  121 + <option id="option4c" selected="selected" value="2">2</option>
  122 + </optgroup>
  123 + <option selected="selected" disabled="disabled" id="option4d" value="3">3</option>
  124 + <option id="option4e">no value</option>
  125 + </select>
117 126
118 127 <object id="object1" codebase="stupid">
119 128 <param name="p1" value="x1" />
10 test/unit/attributes.js
@@ -302,7 +302,7 @@ test("removeAttr(String)", function() {
302 302 });
303 303
304 304 test("val()", function() {
305   - expect(17);
  305 + expect(20);
306 306
307 307 document.getElementById('text1').value = "bla";
308 308 equals( jQuery("#text1").val(), "bla", "Check for modified value of input element" );
@@ -329,6 +329,14 @@ test("val()", function() {
329 329 jQuery('#select3').val("");
330 330 same( jQuery('#select3').val(), [''], 'Call val() on a multiple="multiple" select' );
331 331
  332 + same( jQuery('#select4').val(), [], 'Call val() on multiple="multiple" select with all disabled options' );
  333 +
  334 + jQuery('#select4 optgroup').add('#select4 > [disabled]').attr('disabled', false);
  335 + same( jQuery('#select4').val(), ['2', '3'], 'Call val() on multiple="multiple" select with some disabled options' );
  336 +
  337 + jQuery('#select4').attr('disabled', true);
  338 + same( jQuery('#select4').val(), ['2', '3'], 'Call val() on disabled multiple="multiple" select' );
  339 +
332 340 var checks = jQuery("<input type='checkbox' name='test' value='1'/><input type='checkbox' name='test' value='2'/><input type='checkbox' name='test' value=''/><input type='checkbox' name='test'/>").appendTo("#form");
333 341
334 342 same( checks.serialize(), "", "Get unchecked values." );
2  test/unit/event.js
@@ -255,7 +255,7 @@ test("bind(), iframes", function() {
255 255 });
256 256
257 257 test("bind(), trigger change on select", function() {
258   - expect(3);
  258 + expect(4);
259 259 var counter = 0;
260 260 function selectOnChange(event) {
261 261 equals( event.data, counter++, "Event.data is not a global event object" );
12 test/unit/selector.js
@@ -21,7 +21,7 @@ test("element", function() {
21 21 same( jQuery("p", jQuery("div")).get(), q("firstp","ap","sndp","en","sap","first"), "Finding elements with a context." );
22 22 same( jQuery("div").find("p").get(), q("firstp","ap","sndp","en","sap","first"), "Finding elements with a context." );
23 23
24   - same( jQuery("#form").find("select").get(), q("select1","select2","select3"), "Finding selects with a context." );
  24 + same( jQuery("#form").find("select").get(), q("select1","select2","select3","select4"), "Finding selects with a context." );
25 25
26 26 ok( jQuery("#length").length, '&lt;input name="length"&gt; cannot be found under IE, see #945' );
27 27 ok( jQuery("#lengthtest input").length, '&lt;input name="length"&gt; cannot be found under IE, see #945' );
@@ -338,7 +338,7 @@ test("pseudo - :not", function() {
338 338 expect(24);
339 339 t( "Not", "a.blog:not(.link)", ["mark"] );
340 340
341   - t( "Not - multiple", "#form option:not(:contains(Nothing),#option1b,:selected)", ["option1c", "option1d", "option2b", "option2c", "option3d", "option3e"] );
  341 + t( "Not - multiple", "#form option:not(:contains(Nothing),#option1b,:selected)", ["option1c", "option1d", "option2b", "option2c", "option3d", "option3e", "option4e"] );
342 342 t( "Not - recursive", "#form option:not(:not(:selected))[id^='option3']", [ "option3b", "option3c"] );
343 343
344 344 t( ":not() failing interior", "p:not(.foo)", ["firstp","ap","sndp","en","sap","first"] );
@@ -360,8 +360,8 @@ test("pseudo - :not", function() {
360 360 t( "No element not selector", ".container div:not(.excluded) div", [] );
361 361
362 362 t( ":not() Existing attribute", "#form select:not([multiple])", ["select1", "select2"]);
363   - t( ":not() Equals attribute", "#form select:not([name=select1])", ["select2", "select3"]);
364   - t( ":not() Equals quoted attribute", "#form select:not([name='select1'])", ["select2", "select3"]);
  363 + t( ":not() Equals attribute", "#form select:not([name=select1])", ["select2", "select3", "select4"]);
  364 + t( ":not() Equals quoted attribute", "#form select:not([name='select1'])", ["select2", "select3", "select4"]);
365 365
366 366 t( ":not() Multiple Class", "#foo a:not(.blog)", ["yahoo","anchor2"] );
367 367 t( ":not() Multiple Class", "#foo a:not(.link)", ["yahoo","anchor2"] );
@@ -427,7 +427,7 @@ test("pseudo - visibility", function() {
427 427 test("pseudo - form", function() {
428 428 expect(8);
429 429
430   - t( "Form element :input", "#form :input", ["text1", "text2", "radio1", "radio2", "check1", "check2", "hidden1", "hidden2", "name", "search", "button", "area1", "select1", "select2", "select3"] );
  430 + t( "Form element :input", "#form :input", ["text1", "text2", "radio1", "radio2", "check1", "check2", "hidden1", "hidden2", "name", "search", "button", "area1", "select1", "select2", "select3", "select4"] );
431 431 t( "Form element :radio", "#form :radio", ["radio1", "radio2"] );
432 432 t( "Form element :checkbox", "#form :checkbox", ["check1", "check2"] );
433 433 t( "Form element :text", "#form :text:not(#search)", ["text1", "text2", "hidden2", "name"] );
@@ -435,5 +435,5 @@ test("pseudo - form", function() {
435 435 t( "Form element :checkbox:checked", "#form :checkbox:checked", ["check1"] );
436 436 t( "Form element :radio:checked, :checkbox:checked", "#form :radio:checked, #form :checkbox:checked", ["radio2", "check1"] );
437 437
438   - t( "Selected Option Element", "#form option:selected", ["option1a","option2d","option3b","option3c"] );
  438 + t( "Selected Option Element", "#form option:selected", ["option1a","option2d","option3b","option3c","option4b","option4c","option4d"] );
439 439 });
4 test/unit/traversing.js
@@ -152,7 +152,7 @@ test("not(Selector)", function() {
152 152 equals( jQuery("#main > p#ap > a").not("#google").length, 2, "not('selector')" );
153 153 same( jQuery("p").not(".result").get(), q("firstp", "ap", "sndp", "en", "sap", "first"), "not('.class')" );
154 154 same( jQuery("p").not("#ap, #sndp, .result").get(), q("firstp", "en", "sap", "first"), "not('selector, selector')" );
155   - same( jQuery("#form option").not("option.emptyopt:contains('Nothing'),[selected],[value='1']").get(), q("option1c", "option1d", "option2c", "option3d", "option3e" ), "not('complex selector')");
  155 + same( jQuery("#form option").not("option.emptyopt:contains('Nothing'),[selected],[value='1']").get(), q("option1c", "option1d", "option2c", "option3d", "option3e", "option4e" ), "not('complex selector')");
156 156
157 157 same( jQuery('#ap *').not('code').get(), q("google", "groups", "anchor1", "mark"), "not('tag selector')" );
158 158 same( jQuery('#ap *').not('code, #mark').get(), q("google", "groups", "anchor1"), "not('tag, ID selector')" );
@@ -163,7 +163,7 @@ test("not(Element)", function() {
163 163 expect(1);
164 164
165 165 var selects = jQuery("#form select");
166   - same( selects.not( selects[1] ).get(), q("select1", "select3"), "filter out DOM element");
  166 + same( selects.not( selects[1] ).get(), q("select1", "select3", "select4"), "filter out DOM element");
167 167 });
168 168
169 169 test("not(Function)", function() {

0 comments on commit 2c4b208

Anton M.

This test fails for all Webkit browsers listed on the testswarm http://swarm.jquery.org/job/225/. The cause seems to be that Webkit (different from all other browsers) returns true for the disabled attribute of all options which are immediate childrens of a disabled select. Even when the options itself hasn't the disabled attribute set explicitly

This is the reason why the option with id option4d is missing from the actual result. The only workaround I could find is to use the getAttribute() function in Safari (didn't test if this also works in the other Webkit based browsers). Which returns null if the disabled attribute isn't set or false and an empty string if it is set to true / disabled. While option.disabled always returns true if the parent select is disabled not matter if the option itself is explicitly disabled or not.

So we would basically need to check if we are using a Webkit based browser or find other means to determine if we can rely on option.disabled in attribute.js val() and I don't know if that's acceptable.

John Resig

Thanks for the catch! I did some additional testing on the technique that you proposed and it seems to work fine everywhere that I can test so I'm going to push ahead with that. Landed in 157a383

Please sign in to comment.
Something went wrong with that request. Please try again.