From: Garrett Smith on 19 Dec 2009 19:40 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 19 Dec 2009 20:15 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 19 Dec 2009 23:10 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 20 Dec 2009 00:44 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 20 Dec 2009 01:50
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 |