Side navigation
#8813 closed bug (patchwelcome)
Opened April 07, 2011 11:33PM UTC
Closed April 08, 2011 05:02PM UTC
Last modified March 14, 2012 04:56PM UTC
Using .val() on a select with non-existent value produces invalid result
Reported by: | anonymous | Owned by: | timmywil |
---|---|---|---|
Priority: | low | Milestone: | 1.6 |
Component: | attributes | Version: | 1.5.2 |
Keywords: | val | Cc: | |
Blocked by: | Blocking: |
Description
If you start with:
<select id="test_select"> <option value="1" selected="selected">One</option> <option value="2">Two</option> </select>
And do:
$('#test_select').val("3")
jQuery removes the selected attribute from the first option, but then can't find a matching option to select. Depending on the browser, the final behavior is different. In the last version of Firefox 3, the first option is selected. In Safari 5.0.4, you get a blank select (no option selected). Either way, you're setting a value and the value isn't being set.
With a non-multiple select, jQuery needs to preserve the existing value if it can't set the requested one. I don't think there's any other safe behavior, since .val() can't return true/false for success.
Attachments (0)
Change History (12)
Changed April 08, 2011 12:11AM UTC by comment:1
component: | unfiled → attributes |
---|---|
keywords: | → val |
milestone: | 1.next → 1.6 |
owner: | → timmywil |
priority: | undecided → high |
status: | new → assigned |
Changed April 08, 2011 12:22AM UTC by comment:2
keywords: | val → val, needsreview |
---|
Actually, having reviewed the source, this looks intentional. http://bot-t.com/jquery.js#1991
I'll tag this as needsreview. My guess is we probably don't want this behavior as it's not consistent. After setting the selectedIndex to -1, val then returns null instead of the default selected option on retrieval (for certain browsers at least such as chrome 10). F4 returns the default selected option. Depending on which direction we want to go( whether to return null or the default 1), we should probably unify this across browsers.
Changed April 08, 2011 12:56AM UTC by comment:3
priority: | high → low |
---|---|
resolution: | → invalid |
status: | assigned → closed |
This is not a jQuery bug, to add a new, previously non-existent value to a select menu, see the following: http://jsfiddle.net/rwaldron/NxQyh/
Changed April 08, 2011 01:14AM UTC by comment:4
Replying to [comment:3 rwaldron]:
This is not a jQuery bug, to add a new, previously non-existent value to a select menu, see the following: http://jsfiddle.net/rwaldron/NxQyh/
Not sure you understand what I meant. It's not about being able to select new options. It's about passing a value that isn't one of the options. We are the ones setting the selectedIndex to -1 instead of letting nothing happen, which is creating the inconsistency between browsers. I think this is valid.
Changed April 08, 2011 01:29AM UTC by comment:5
resolution: | invalid |
---|---|
status: | closed → reopened |
Given that dynamic values are common in setting values of select elements, reopening for now. I'm not sure rwaldron understood the issue here.
Changed April 08, 2011 04:12PM UTC by comment:6
I'm the reporter of this bug. Timmywil, your assessment of my intent is correct. I am not trying to add new options -- just the opposite. I'm trying to set a value without knowing if the value is available. Rather than check ahead of time, I want to check after calling .val():
var select = $('#select_id'); select.val(value); if (select.val() != value) //No option matched, take appropriate action
If I can't do this, I have to check $('#select_id').find('option[value="' + value + '"]').length before every .val(), which is probably redundant. (I'm guessing jQuery uses that same find() in the val() call.)
Changed April 08, 2011 04:20PM UTC by comment:7
I think you meant rwaldron. That's exactly what I said.
Changed April 08, 2011 04:42PM UTC by comment:8
Replying to [comment:7 timmywil]:
I think you meant rwaldron. That's exactly what I said.
Right. That's why I said you were correct! :-)
I appreciate everything the jQuery team does.
Changed April 08, 2011 04:51PM UTC by comment:9
When you attempt to set a select to a value that does not exist, jQuery behaves the same way that it would if no option was selected, which according to html spec, the correct behaviour is to set the selectedIndex to -1; how the browser handles this is spec dependent. Try this just testing the return from select.val( value ) ?
Changed April 08, 2011 05:02PM UTC by comment:10
keywords: | val, needsreview → val |
---|---|
resolution: | → patchwelcome |
status: | reopened → closed |
Woops, I read "incorrect". Sorry OP.
Anyway, rwaldron and I have discussed this ticket and there do not seem to be other tickets related to this problem. And rwaldron brings up another good point. This is a browser bug. The current version of webkit does not react correctly to setting selectedIndex to -1, but the issue does not exist in Chromium 12. If there are more tickets about this issue in the future, we can investigate further and possibly provide a patch. Currently, the same code is being used for multiple and single select elements, which is ideal since it makes the code short. I could not think of a way to fix without calling val again or differentiating between single and multiple, which does not seem worth it. The user might as well validate the entry. If someone would like to present a patch that has no perf loss and does not inflate the setter for selects, I think we would welcome it.
Changed April 08, 2011 05:50PM UTC by comment:11
Thanks for the explanation. I did suspect that this is a WebKit oddity.
In this situation I need the selects to always have a selection, which WebKit isn't doing. I also need the selected option's text to display elsewhere. Instead of checking for WebKit's behavior every time, I added a simple function. It only changes the selection if the new value exists, and returns the selected object's DOM object so I can access its value and text without additional jQuery calls.
$.fn.setSelectVal = function(value) { this.children('option[value="' + value + '"]').attr('selected', 'selected'); var select = this.get(0); return select.options[select.selectedIndex]; };
In both Safari and Firefox, adding the selected attribute to an option automatically causes attribute removal on the prior selected option. I'm not sure if it's smart to count on this, but it works for me right now and I have a very small user base.
Changed April 15, 2011 04:00AM UTC by comment:12
#5394 is a duplicate of this ticket.
Confirmed http://jsfiddle.net/timmywil/E2cKm/