Skip to main content

Bug Tracker

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 timmywil comment:1

component: unfiledattributes
keywords: → val
milestone: 1.next1.6
owner: → timmywil
priority: undecidedhigh
status: newassigned

Changed April 08, 2011 12:22AM UTC by timmywil comment:2

keywords: valval, 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 rwaldron comment:3

priority: highlow
resolution: → invalid
status: assignedclosed

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 timmywil 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 timmywil comment:5

resolution: invalid
status: closedreopened

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 anonymous 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 timmywil comment:7

I think you meant rwaldron. That's exactly what I said.

Changed April 08, 2011 04:42PM UTC by anonymous 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 rwaldron 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 timmywil comment:10

keywords: val, needsreviewval
resolution: → patchwelcome
status: reopenedclosed

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 anonymous 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 timmywil comment:12

#5394 is a duplicate of this ticket.