From: Garrett Smith on
Matt Kruse wrote:
> On Dec 19, 10:43 am, David Mark <dmark.cins...(a)gmail.com> wrote:
>> Ridiculous. Try detecting the problem you are trying to solve (once
>> preferably). There's just no basis for this "solution" (which is also
>> outrageously inefficient).
>
> Detecting the problem would surely be less efficient than simply
> accessing a property, when the latter works just fine.
>

It works, but should it?

You noticed the problem in a page that was not completed (your linked
example). The OPTION's selected property was false before onload and
true after that. So if the OPTION's selected value were related to the
loaded state of the page, then it would make sense to check the state of
the page in the loop. However your observation was limited. The problem
is not related to the page state, but to whether the option is rendered.

You probably tried reading the selectedIndex, and then found that
worked, then tried to read the option.selected, and then found that
worked, and then figured that by simply accessing selectedIndex, the
selected property was achieved. Did I get that right?

Then you went to propose the workaround as a solution. That's a hack.

The problem was identified as: The default OPTION in a non-rendered
SELECT is false, when the option will be selected by default.

That is not a bug.

It would be a bug if, say, the option had the selected property set
before being rendered. For example, given a SELECT that is not yet part
of the dom, adding a selected OPTION to the SELECT should result in the
OPTION selected property being true.

var s = document.createElement("select");
s.options[0] = new Option("a", "a");
s.options[1] = new Option("a", "a", true, true); // Should be selected.

alert(s.options[1].selected); // Should be true.

Safari correctly elerts "true".

OTOH, if the browser is to make the determination of which option to set
the selected property on, you should not expect that information to be
available when the element is not in the DOM.

If we create two OPTIONs, set disabled=true on the first OPTION, the
second OPTION will be selected when the SELECT is rendered on the page.
There is no guarantee that the second OPTION will be selected before the
dom for that object is ready.

var s = document.createElement("select"),
o = new Option("a", "a"),
o2 = new Option("a", "a");

o.disabled = true;
s.add(o);
s.add(o2);

alert(o2.selected); // expect true or false.

To feature test the problem, create a SELECT, add an OPTION, and check
the OPTION's selected property. Save the result in a variable.

var s = document.createElement("select");
s.add(new Option("a"));
IS_NOT_DEFAULT_OPTION_IN_NONRENDRED_SELECTED = s.options[0].selected;

I suggest moving the workaround (and whatever comments may accompany)
with it and moved it out of the loop.

if(prop === "selected" && IS_NOTDEFAULT_OPTION_IN_NONRENDRED_NOTSELECTED) {
updateOptionSelected(elem);
}

function updateOptionSelected(elem) {
// If we're getting a false value, it may be that the option
// will be selected when fully rendered, but has not happened yet.
if(elem.selected === false) {
var selectedOption = elem.parentNode.options[s.selectedIndex];
selectedOption.selected = true;
}
}

Doesn't that make teh loop a lot clearer?

It will be a little slower in Safari but does not punish every browser
with that workaround.

>> Blind faith has no place in programming
>> (especially not browser scripting).
>
> It's not blind faith, it's tested and proven successful.
>
>> During initial feature detection, you could create a SELECT, add a
>> selected option and check the selectedIndex property.
>
> What does selectedIndex have to do with anything? It returns the
> correct value. It's the <option> tag's 'selected' property that is
> incorrect.
>

Accessign the selectedIndex is a hack. It "works" but by no guarantee of
any official or "de facto" standdard.

>> If the SELECT
>> must be in a document to duplicate the quirk, wait until one is passed
>> and do the test on it (perhaps replacing the method as a result).
>> This stuff is not rocket science. :)
>
> If you wait until the document is ready, then the problem goes away.
>
RIght, but your observation was limited. Based on what you observed,
checking isReady would seem like a sensible workaround. However, that
does not address the fact that the SELECT's DOM may not be ready.

> It's a weird quirk, but it looks like you are just spewing "answers"
> when you've never actually looked at the problem.
>

You provide a nonstandard workaround to get non-standard behavior
without looking closely enough at the problem. Your observations of the
problem are limited to "while the page is loading".

Your proposed workaround relies on an even bigger non-standard quirk. It
is possible that bigger quirk (your workaround) will not be present in
Safari 5 and the smaller quirk will remain. If and when that happens,
you're back to trying to figure out the problem.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
From: David Mark on
On Dec 19, 7:40 pm, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
> Matt Kruse wrote:
> > On Dec 19, 10:43 am, David Mark <dmark.cins...(a)gmail.com> wrote:
> >> Ridiculous.  Try detecting the problem you are trying to solve (once
> >> preferably).  There's just no basis for this "solution" (which is also
> >> outrageously inefficient).
>
> > Detecting the problem would surely be less efficient than simply
> > accessing a property, when the latter works just fine.
>
> It works, but should it?

No. It's clearly a side effect. The loophole could close any time
(perhaps it already has in some nightly somewhere).

>
> You noticed the problem in a page that was not completed (your linked
> example). The OPTION's selected property was false before onload and
> true after that. So if the OPTION's selected value were related to the
> loaded state of the page, then it would make sense to check the state of
> the page in the loop.

Would still not be a direct test.

> However your observation was limited. The problem
> is not related to the page state, but to whether the option is rendered.
>
> You probably tried reading the selectedIndex, and then found that
> worked, then tried to read the option.selected, and then found that
> worked, and then figured that by simply accessing selectedIndex, the
> selected property was achieved. Did I get that right?

Sounds like a reasonable explanation to me. That's how these things
are cobbled together, one misconception at a time.

>
> Then you went to propose the workaround as a solution. That's a hack.

Exactly.

>
> The problem was identified as: The default OPTION in a non-rendered
> SELECT is false, when the option will be selected by default.
>
> That is not a bug.

Certainly not. It's an "inconvenience" for the odd script(s) that
want to run queries before the document is ready though.

>
> It would be a bug if, say, the option had the selected property set
> before being rendered.

That would be odd. But still not a bug IMO.

> For example, given a SELECT that is not yet part
> of the dom, adding a selected OPTION to the SELECT should result in the
> OPTION selected property being true.

Yes.

>
>   var s = document.createElement("select");
>   s.options[0] = new Option("a", "a");
>   s.options[1] = new Option("a", "a", true, true); // Should be selected.
>
>   alert(s.options[1].selected); // Should be true.
>
> Safari correctly elerts "true".
>
> OTOH, if the browser is to make the determination of which option to set
> the selected property on, you should not expect that information to be
> available when the element is not in the DOM.

Right. A feature test for this can be run immediately as adding the
element to the DOM would defeat its purpose (so no need to wait for
load).

>
> If we create two OPTIONs, set disabled=true on the first OPTION, the
> second OPTION will be selected when the SELECT is rendered on the page.

Yes.

> There is no guarantee that the second OPTION will be selected before the
> dom for that object is ready.

Right.

>
>   var s = document.createElement("select"),
>       o = new Option("a", "a"),
>       o2 = new Option("a", "a");
>
>   o.disabled = true;
>   s.add(o);
>   s.add(o2);
>
> alert(o2.selected); // expect true or false.

Right.

>
> To feature test the problem, create a SELECT, add an OPTION, and check
> the OPTION's selected property. Save the result in a variable.
>
> var s = document.createElement("select");
> s.add(new Option("a"));
> IS_NOT_DEFAULT_OPTION_IN_NONRENDRED_SELECTED = s.options[0].selected;

I like it.

>
> I suggest moving the workaround (and whatever comments may accompany)
> with it and moved it out of the loop.
>
> if(prop === "selected" && IS_NOTDEFAULT_OPTION_IN_NONRENDRED_NOTSELECTED) {
>    updateOptionSelected(elem);
>
> }
>
> function updateOptionSelected(elem) {
>    // If we're getting a false value, it may be that the option
>    // will be selected when fully rendered, but has not happened yet.
>    if(elem.selected === false) {
>      var selectedOption = elem.parentNode.options[s.selectedIndex];


Exactly. :)


>      selectedOption.selected = true;
>    }
>
> }
>
> Doesn't that make teh loop a lot clearer?

Yes and it actually makes logical sense (always a plus in
programming).

>
> It will be a little slower in Safari but does not punish every browser
> with that workaround.

Right. And the other rendition had severe penalties for all.

> >>  Blind faith has no place in programming
> >> (especially not browser scripting).
>
> > It's not blind faith, it's tested and proven successful.
>
> >> During initial feature detection, you could create a SELECT, add a
> >> selected option and check the selectedIndex property.
>
> > What does selectedIndex have to do with anything? It returns the
> > correct value. It's the <option> tag's 'selected' property that is
> > incorrect.
>
> Accessign the selectedIndex is a hack. It "works" but by no guarantee of
> any official or "de facto" standdard.

What I was getting at is that selectedIndex could be used to determine
if there was a contradiction. As expected, it could.

>
> >>  If the SELECT
> >> must be in a document to duplicate the quirk, wait until one is passed
> >> and do the test on it (perhaps replacing the method as a result).
> >> This stuff is not rocket science.  :)
>
> > If you wait until the document is ready, then the problem goes away.
>
> RIght, but your observation was limited. Based on what you observed,
> checking isReady would seem like a sensible workaround.

It would be a bizarre inference, especially considering the
straightforward solution. ;)
From: RobG on
On Dec 19, 4:25 pm, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
> Matt Kruse wrote:
> > On Dec 18, 9:49 pm, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
> >>>>>> | if ( name == "selected" && elem.parentNode )
> >> One more time: Can anyone demonstrate the problem that the workaround
> >> exists for?
>
> > Yes:
> >http://ejohn.org/files/bugs/selected/
>
> > The bug (or quirk) is valid, but should be documented better, and it's
> > debatable whether it should even be "fixed" to begin with.
>
> Ah, so the selected property is true after onload, but false while the
> page is loading. I can reproduce that.
>
> The workaround of accessign - selectedIndex - of the parent causes the
> OPTION's - selected - to be true.

I think it's a crock. The issue is that during load, if no option has
the selected attribute, the select's selectedIndex property will be
set to 0 but no option's selected property is set to true. That can
also be characterised as a problem with selectedIndex, as it should be
-1 at that moment.

If an option is given the selected attribute, it all works as
expected.

If the load event hasn't occurred yet, and the user *has* selected a
value, is the value reported correctly? I suspect it will be.

If the user hasn't selected an option and the form is submitted before
load has occurred, what will be the value of the select? Should this
be fixed by script, HTML or server code? Should it be fixed at all? Is
this only an issue for serialising forms prior to load? If so, should
it be dealt with there, and only if load hasn't occurred?

Anyhow, it is resolved by following advice in the HTML specification
from a decade ago:

"Since user agent behavior differs, authors should ensure that each
[select] includes a default pre-selected OPTION."

<URL: http://www.w3.org/TR/html4/interact/forms.html#h-17.6.1 >

I'd just document it, job done.

>
> That is considerably different then what the comment states:
> | // Safari mis-reports the default selected property of a hidden option

Which points to an inability to clearly identify the issue in the
first place.

And that reflects on the attr() method in general - there is no clear
idea of what it should do, other than some vague idea of John Resig's
that it should do "what the developer expects". Perhaps he knows the
mind of everyone using jQuery.

It seems to me he wants attr() to do what *he* thinks the developer
expects, despite being told by developers that it doesn't do what
*they* expect. The whole issue would go away if attr() reported
attribute values, a prop() method reported property values and css()
reported (say) computed CSS values.

Then users need only learn the difference between attributes and
properties once. Heaven forbid that they should understand the
technology they're working with.


--
Rob
From: Garrett Smith on
RobG wrote:
> On Dec 19, 4:25 pm, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
>> Matt Kruse wrote:
>>> On Dec 18, 9:49 pm, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
>>>>>>>> | if ( name == "selected" && elem.parentNode )
>>>> One more time: Can anyone demonstrate the problem that the workaround
>>>> exists for?
>>> Yes:
>>> http://ejohn.org/files/bugs/selected/
>>> The bug (or quirk) is valid, but should be documented better, and it's
>>> debatable whether it should even be "fixed" to begin with.
>> Ah, so the selected property is true after onload, but false while the
>> page is loading. I can reproduce that.
>>
>> The workaround of accessign - selectedIndex - of the parent causes the
>> OPTION's - selected - to be true.
>
> I think it's a crock. The issue is that during load, if no option has
> the selected attribute, the select's selectedIndex property will be
> set to 0 but no option's selected property is set to true. That can
> also be characterised as a problem with selectedIndex, as it should be
> -1 at that moment.
>

Right. the selected index could be -1 at that point, and would be
perfectly compliant to the definition of - selected - in DOM 2 html,
which states:

| selectedIndex of type long
| The ordinal index of the selected option, starting from 0. The value
| -1 is returned if no element is selected. If multiple options are
| selected, the index of the first selected option is returned.

A SELECT's selectedIndex property could be 1, by even if no OPTION has
selected attribute.

<select>
<option disabled>not selected</option>
<option>selected by default</option>
</select>

However, you will notice that Safari selects the first OPTION. The most
reliable solution is:-

> If an option is given the selected attribute, it all works as
> expected.
>

Yes, that solves the problem.

<body>
<select><option selected>test</option></select>
<script>
var opt = document.getElementsByTagName("option")[0];
alert( opt.selected );
</script>
</body>

Safari 4:
true

> If the load event hasn't occurred yet, and the user *has* selected a
> value, is the value reported correctly? I suspect it will be.
>

Yes.

Add selected attribute. Problem solved.

> If the user hasn't selected an option and the form is submitted before
> load has occurred, what will be the value of the select? Should this
> be fixed by script, HTML or server code? Should it be fixed at all? Is
> this only an issue for serialising forms prior to load? If so, should
> it be dealt with there, and only if load hasn't occurred?
>
> Anyhow, it is resolved by following advice in the HTML specification
> from a decade ago:
>
> "Since user agent behavior differs, authors should ensure that each
> [select] includes a default pre-selected OPTION."
>
> <URL: http://www.w3.org/TR/html4/interact/forms.html#h-17.6.1 >
>
> I'd just document it, job done.
>

There you go. Already documented in HTML 4.01.

>> That is considerably different then what the comment states:
>> | // Safari mis-reports the default selected property of a hidden option
>
> Which points to an inability to clearly identify the issue in the
> first place.
>

Yep.

> And that reflects on the attr() method in general - there is no clear
> idea of what it should do, other than some vague idea of John Resig's
> that it should do "what the developer expects". Perhaps he knows the
> mind of everyone using jQuery.
>

Right.

> It seems to me he wants attr() to do what *he* thinks the developer
> expects, despite being told by developers that it doesn't do what
> *they* expect. The whole issue would go away if attr() reported
> attribute values, a prop() method reported property values and css()
> reported (say) computed CSS values.
>

Computed CSS values can't happen. IE.

> Then users need only learn the difference between attributes and
> properties once. Heaven forbid that they should understand the
> technology they're working with.
>
What would a developer who understands the technology want jQuery for?
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
From: Matt Kruse on
On Dec 19, 6:40 pm, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
> You probably tried reading the selectedIndex, and then found that
> worked, then tried to read the option.selected, and then found that
> worked, and then figured that by simply accessing selectedIndex, the
> selected property was achieved. Did I get that right?

Me personally? No. I didn't come up with this. I asked about the
rationale for that segment of code because it never made sense to me.

> Then you went to propose the workaround as a solution. That's a hack.

That hack was there, I just suggested a way to improve the comment and
functionality of the hack.

> The problem was identified as: The default OPTION in a non-rendered
> SELECT is false, when the option will be selected by default.
> That is not a bug.

I agree, but it is behavior that is different than other tested
browsers. In the case of jQuery, it is attempting to "normalize"
browsers, and since they found an exception probably in some rare case
that one user had, they tried to fix it. Personally, I don't feel this
section of code deserves to be in there at all.

> function updateOptionSelected(elem) {
>    // If we're getting a false value, it may be that the option
>    // will be selected when fully rendered, but has not happened yet.
>    if(elem.selected === false) {
>      var selectedOption = elem.parentNode.options[s.selectedIndex];
>      selectedOption.selected = true;
>    }
> }
> Doesn't that make teh loop a lot clearer?

Certainly, it looks like a better approach. But it would need to be
cleaned up to consider the possibility that an <option> might in an
<optgroup>.

Perhaps something like this:

if (prop=="selected") {
return getOptionSelected(elem);
}

function getOptionSelected(el) {
var s = document.createElement("select");
s.add(new Option("a"));
if (s.options[0].selected) {
return (getOptionSelected = function(opt) { return opt.selected; })
(el);
}
// If we're getting a false value, it may be that the option
// will be selected when fully rendered, but has not happened yet.
return (getOptionSelected=function(opt) {
if(opt.selected === false) {
var s = (opt.parentNode.tagName=="SELECT")?
opt.parentNode:opt.parentNode.parentNode;
if (s.type=="select-one" && s.selectedIndex>=0) {
s.options[s.selectedIndex].selected=true;
}
}
return opt.selected;
})(el);
}

> Your proposed workaround relies on an even bigger non-standard quirk. It
> is possible that bigger quirk (your workaround) will not be present in
> Safari 5 and the smaller quirk will remain. If and when that happens,
> you're back to trying to figure out the problem.

Possible. Either way, the above solution seems more robust if one were
really interested in dealing with this quirk.

And just to be clear - this is not "my proposed workaround". I was
exploring the problem to understand why those lines have existed in
jQuery for so long. Out of curiosity.

Matt Kruse