<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script type="text/javascript">
function dSelect() {
var sel = document.getElementById('mySel');
var o = document.createElement('option');
Your're adding the *same* object to the HTMLSelectElement twice. What's
happening is explained in the specs
(<http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-94282980>). If you
want to add two "options", you have to create two distinct
HTMLOptionElement objects:
function dSelect() {
var sel = document.getElementById('mySel');
var o = document.createElement('option');
o.value="a";
o.text="apple";
sel.options.add(o);
alert(sel.length);
o = document.createElement('option');
o.value="ora";
o.text="orange";
sel.options.add(o);
alert(sel.length);
}
> Your're adding the *same* object to the HTMLSelectElement twice. What's
> happening is explained in the specs
> (<http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-94282980>). If you
> want to add two "options", you have to create two distinct
> HTMLOptionElement objects:
> function dSelect() {
> var sel = document.getElementById('mySel');
> var o = document.createElement('option');
> o.value="a";
> o.text="apple";
> sel.options.add(o);
> alert(sel.length);
The following code works but I'm wondering if there's more elegant way
to do it, that is, using some sort dynamic variables inside the loop.
case dayAfterTmr:
var sel = document.getElementById('mySel');
var obj = [];
var Os = ['apple','orange','banana'];
for (i=0; i < Os.length; i++) {
obj[i] = document.createElement('option');
obj[i].value = Os[i];
obj[i].text = Os[i];
sel.options.add(obj[i]);
}
In addition to what Christoph posted, you should put a </option>
tag here. Or just leave out the <option> tag; you do not have to have
one. It just gives you a blank selection (which you may or may not
want).
<cmbecke...@gmx.de> wrote:
>justaguy wrote:
>> function dSelect() {
>> var sel = document.getElementById('mySel');
>> var o = document.createElement('option');
>Your're adding the *same* object to the HTMLSelectElement twice. What's
Aren't the values simply taken? If I set o to null after both
adds, it does not affect the select options so it presumably is not
referring to o after it is used to add an option.
Where is it explained, please? I have looked at the whole
section of select options, and I can not see it.
> function dSelect() {
> var sel = document.getElementById('mySel');
> var o = document.createElement('option');
> o.value="a";
> o.text="apple";
> sel.options.add(o);
> alert(sel.length);
> The following code works but I'm wondering if there's more elegant way
> to do it, that is, using some sort dynamic variables inside the loop.
> case dayAfterTmr:
> var sel = document.getElementById('mySel');
> var obj = [];
> var Os = ['apple','orange','banana'];
> for (i=0; i < Os.length; i++) {
> obj[i] = document.createElement('option');
> obj[i].value = Os[i];
> obj[i].text = Os[i];
> sel.options.add(obj[i]);
> }
> break;
I have no idea what you mean with "dynamic variable". I can see that
you're using an 'obj' array that serves no purpose, though. This will do
the same job (given 'sel' and 'Os'):
for (var i = 0; i < Os.length; ++i) {
var opt = document.createElement("option");
opt.text = opt.value = Os[i];
sel.options.add(opt);
}
Note that you're assigning to the _same_ 'opt' variable on each
iteration. Every time you assign it a reference to a new object, the old
value is discarded.
Also note that I declared the 'i' variable. I can't be sure from the
snippet of code you sent, but you seem to have missed that.
If you want something even shorter, you could try this:
for (var i = 0; i < Os.length; ++i) {
sel.options.add(new Option(Os[i], Os[i]));
}
Depending on your choice of standards, you may or may not want to use
"new Option()". It's standard in JavaScript(tm), and documented by
several other implementations, but it's not part of the W3C DOM. That
said, it has worked reliably in every (scripting enabled) browser I've
seen in the last 10 years. I don't hesitate to use it, but this group is
a little "special", and I'm sure somebody will chime in with some
fantastically interesting nitpicks.
By the way, unless you're doing something unusual, it's sufficient to
set the .text of an option element when it's the same as the value.
>>Your're adding the *same* object to the HTMLSelectElement twice. What's
> Aren't the values simply taken? If I set o to null after both
> adds, it does not affect the select options so it presumably is not
> referring to o after it is used to add an option.
No, Christoph has it right. The entries in 'options' never referred to
'o'. They, and the 'o' variable, hold a reference to the same option
object. If you assign something else to 'o' (like null), then the 'o'
variable will contain something else, but that doesn't affect the object
itself.
When you write 'options.add(o)', you're not just passing the 'value' and
'text' properties, you're passing (a reference to) the entire object.
Here's a simpler but similar example:
var arr = [];
var o = {foo: "bar"};
arr.push(o);
o.foo = "qux";
arr.push(o);
o = null;
print(arr[0].foo);
print(arr[1].foo);
This will print "qux" twice. Even though the .foo property was "bar"
when we added the first element, and even though we nulled the 'o'
variable later.
You can still modify an object after adding it to an array, or passing
it to a method - as long as you have a reference to it. When we set 'o'
to null, we lose that reference, but not the object.
>No, Christoph has it right. The entries in 'options' never referred to
I know he has it right. I have run both sets of code. The
question is why is it that way? He posted a reference that he claimed
explains it, but it does not do so.
>'o'. They, and the 'o' variable, hold a reference to the same option
>object. If you assign something else to 'o' (like null), then the 'o'
>variable will contain something else, but that doesn't affect the object
>itself.
I know.
>When you write 'options.add(o)', you're not just passing the 'value' and
>'text' properties, you're passing (a reference to) the entire object.
Yes, I know. My issue is why does the second .add() wipe out the
first when another element object is not created?
>Here's a simpler but similar example:
But not similar enough!
I have put the analogous lines from Christoph's function after
yours.
> var arr = [];
> var o = {foo: "bar"};
var sel = document.getElementById('mySel');
var o = document.createElement('option');
o.value="a";
o.text="apple";
> arr.push(o);
sel.options.add(o);
o = document.createElement('option');
Where is the equivalent of this last line in your code? Why do
you not have to create a second object in your example, but not doing
so with OP's code is why it does not work? I understand your code. I
do not understand Christoph's.
> o.foo = "qux";
o.value="ora";
o.text="orange";
> arr.push(o);
sel.options.add(o);
> o = null;
> print(arr[0].foo);
> print(arr[1].foo);
>This will print "qux" twice. Even though the .foo property was "bar"
>when we added the first element, and even though we nulled the 'o'
>variable later.
So what goes wrong with an element object?
>You can still modify an object after adding it to an array, or passing
>it to a method - as long as you have a reference to it. When we set 'o'
>to null, we lose that reference, but not the object.
I know. Now, why can we not reuse the object?
And here I thought that I understood JavaScript fairly well, but
here we have something where it is not just that I do not understand,
but I misunderstand.
> > The following code works but I'm wondering if there's more elegant way
> > to do it, that is, using some sort dynamic variables inside the loop.
> > case dayAfterTmr:
> > var sel = document.getElementById('mySel');
> > var obj = [];
> > var Os = ['apple','orange','banana'];
> > for (i=0; i < Os.length; i++) {
> > obj[i] = document.createElement('option');
> > obj[i].value = Os[i];
> > obj[i].text = Os[i];
> > sel.options.add(obj[i]);
> > }
> > break;
> I have no idea what you mean with "dynamic variable". I can see that
> you're using an 'obj' array that serves no purpose, though. This will do
> the same job (given 'sel' and 'Os'):
> for (var i = 0; i < Os.length; ++i) {
> var opt = document.createElement("option");
> opt.text = opt.value = Os[i];
> sel.options.add(opt);
> }
> Note that you're assigning to the _same_ 'opt' variable on each
> iteration. Every time you assign it a reference to a new object, the old
> value is discarded.
> Also note that I declared the 'i' variable. I can't be sure from the
> snippet of code you sent, but you seem to have missed that.
> If you want something even shorter, you could try this:
> for (var i = 0; i < Os.length; ++i) {
> sel.options.add(new Option(Os[i], Os[i]));
> }
> Depending on your choice of standards, you may or may not want to use
> "new Option()". It's standard in JavaScript(tm), and documented by
> several other implementations, but it's not part of the W3C DOM. That
> said, it has worked reliably in every (scripting enabled) browser I've
> seen in the last 10 years. I don't hesitate to use it, but this group is
> a little "special", and I'm sure somebody will chime in with some
> fantastically interesting nitpicks.
> By the way, unless you're doing something unusual, it's sufficient to
> set the .text of an option element when it's the same as the value.
> - stefan
Nice. Does opt.text = opt.value = Os[i]; equal to
opt.text = Os[i];
opt.value = Os[i];
?
It appears so. Could you give a practical example of such usage? (as
you mentioned in this case it's not necessary to set the value.
> On Thu, 27 Sep 2012 04:16:08 +0200, Stefan Weiss
>>When you write 'options.add(o)', you're not just passing the 'value' and
>>'text' properties, you're passing (a reference to) the entire object.
> Yes, I know. My issue is why does the second .add() wipe out the
> first when another element object is not created?
>>Here's a simpler but similar example:
> But not similar enough!
...
> o = document.createElement('option');
> Where is the equivalent of this last line in your code? Why do
> you not have to create a second object in your example, but not doing
> so with OP's code is why it does not work? I understand your code. I
> do not understand Christoph's.
Oh that! That's just the DOM. Remember, in justaguy's original code, he
only created a single option object and tried to add it to the select
element multiple times. That doesn't work, just like this won't work:
<div id="target"></div>
<script>
var theDiv = document.getElementById("target");
var newEle = document.createElement("hr");
theDiv.appendChild(newEle);
theDiv.appendChild(newEle);
theDiv.appendChild(newEle);
</script>
This will not append three <hr> elements to the <div>; instead it will
move the single <hr> from wherever it currently is to the end of the
<div>, three times, with the result being <div><hr></div>.
That's because we only created a single element; no matter how often we
append it or move it, it will not become two (or three) elements.
It's the same thing with the <select> and the <option> elements. The
.value and .text properties may have changed between the first and
second add(), but it was still the same element, and can only be added once.
The difference in my simpler (but apparently not so similar) example was
that you can add the same object to an array any number of times, but
not the same DOM element to a parent element.
I hope that clears it up?
> And here I thought that I understood JavaScript fairly well, but
> here we have something where it is not just that I do not understand,
> but I misunderstand.
Gene, I've been doing this (on and off) for 15 years, and I'm still not
done learning. I think what you're doing - putting these questions out
there for others to read and ponder - is the best thing you can do, for
yourself, for the group, and for people like me who can still learn
something by trying to answer in a way that keeps the pedants quiet ;)
Gene Wirchenko wrote:
> I know he has it right. I have run both sets of code. The
> question is why is it that way? He posted a reference that he claimed
> explains it, but it does not do so.
Stefan has already explained, that the add() method of HTMLSelectElement
behaves similar to the appendChild() method of Node. This is clearly
stated in the specs:
<krewech...@gmail.com> wrote:
>On 2012-09-27 04:38, Gene Wirchenko wrote:
>> On Thu, 27 Sep 2012 04:16:08 +0200, Stefan Weiss
>>>When you write 'options.add(o)', you're not just passing the 'value' and
>>>'text' properties, you're passing (a reference to) the entire object.
>> Yes, I know. My issue is why does the second .add() wipe out the
>> first when another element object is not created?
>>>Here's a simpler but similar example:
>> But not similar enough!
>...
>> o = document.createElement('option');
>> Where is the equivalent of this last line in your code? Why do
>> you not have to create a second object in your example, but not doing
>> so with OP's code is why it does not work? I understand your code. I
>> do not understand Christoph's.
>Oh that! That's just the DOM. Remember, in justaguy's original code, he
>only created a single option object and tried to add it to the select
>element multiple times. That doesn't work, just like this won't work:
>This will not append three <hr> elements to the <div>; instead it will
>move the single <hr> from wherever it currently is to the end of the
><div>, three times, with the result being <div><hr></div>.
>That's because we only created a single element; no matter how often we
>append it or move it, it will not become two (or three) elements.
But I reuse other objects. What is so special about the DOM
structure?
>It's the same thing with the <select> and the <option> elements. The
>.value and .text properties may have changed between the first and
>second add(), but it was still the same element, and can only be added once.
>The difference in my simpler (but apparently not so similar) example was
>that you can add the same object to an array any number of times, but
>not the same DOM element to a parent element.
>I hope that clears it up?
No.
I could see it if adding an element added the *object* to the DOM
tree (Is that the correct term?) If that were the case, I would
expect that nulling the object would have an effect since the DOM
would no longer have the data to refer to. But it did not. (Granted,
it might be that the display is not updated right away.)
If the *values of the object* were added to the DOM tree, that is
certainly an implementation that would make sense. In that case, the
object would then be superfluous after it was added to the DOM tree.
But that does not happen.
ISTM that the implementation should reasonably be one or the
other, but it is not (AFAICS). I would really like to learn how and
why it works. URL? I might curse it as stupid, ill-informed, etc. --
I do that for the Date object to which I object quite a bit -- but at
least I would understand how it works.
>> And here I thought that I understood JavaScript fairly well, but
>> here we have something where it is not just that I do not understand,
>> but I misunderstand.
>Gene, I've been doing this (on and off) for 15 years, and I'm still not
>done learning. I think what you're doing - putting these questions out
>there for others to read and ponder - is the best thing you can do, for
>yourself, for the group, and for people like me who can still learn
>something by trying to answer in a way that keeps the pedants quiet ;)
Fair enough.
This matter is more urgent for me than it might be otherwise -- I
stay away from playing with the DOM much for now -- but that I
misunderstand is a red flag for me. Not knowing how something works,
hey, I can deal with that later. Misunderstanding gets me concerned
about what else I may have wrong.
I am quite happy to read explanations elseWeb. I do put in my
study time.
On Thu, 27 Sep 2012 13:00:11 +0200, Christoph Becker
<cmbecke...@gmx.de> wrote:
>Gene Wirchenko wrote:
>> I know he has it right. I have run both sets of code. The
>> question is why is it that way? He posted a reference that he claimed
>> explains it, but it does not do so.
>Stefan has already explained, that the add() method of HTMLSelectElement
>behaves similar to the appendChild() method of Node. This is clearly
>stated in the specs:
It may be stated, but clearly? Ha!
Take a look at that again, and try telling me that it is clearly
written and that someone new to using the DOM would understand the
implications.
Gene Wirchenko wrote:
> On Thu, 27 Sep 2012 13:00:11 +0200, Christoph Becker
> <cmbecke...@gmx.de> wrote:
>> Gene Wirchenko wrote:
>>> I know he has it right. I have run both sets of code. The
>>> question is why is it that way? He posted a reference that he claimed
>>> explains it, but it does not do so.
>> Stefan has already explained, that the add() method of HTMLSelectElement
>> behaves similar to the appendChild() method of Node. This is clearly
>> stated in the specs:
> It may be stated, but clearly? Ha!
> Take a look at that again, and try telling me that it is clearly
> written and that someone new to using the DOM would understand the
> implications.
IMHO someone new to the DOM might better be served by a more gentle
introduction, e.g. the one available on MDN (I just wasn't able to find
the relevant information there).
>> | If the newChild is already in the tree, it is first removed.
> What on earth does this mean? What gets stored in the tree when
> the method is called?
> An object reference? Then, why does nulling the object not
> change the display?
Yes, indeed the reference to the object is stored. But when you set the
variable containing the object reference to null later, the stored
object reference isn't affected (IIRC Stefan had already explained
that). This has nothing to do with the DOM, but with the semantics of
ECMAScript.
IOW: you can't null any object. You only can set a variable which
contains a reference to an object to null. This doesn't affect the
object itself, only the variable changes. If all references to an
existing object are gone, the object might be garbage collected (but
that is semantically irrelevant).
> Gene Wirchenko wrote:
>> What on earth does this mean? What gets stored in the tree when
>> the method is called?
>> An object reference? Then, why does nulling the object not
>> change the display?
> Yes, indeed the reference to the object is stored. But when you set the
> variable containing the object reference to null later, the stored
> object reference isn't affected (IIRC Stefan had already explained
> that). This has nothing to do with the DOM, but with the semantics of
> ECMAScript.
> IOW: you can't null any object. You only can set a variable which
> contains a reference to an object to null. This doesn't affect the
> object itself, only the variable changes. If all references to an
> existing object are gone, the object might be garbage collected (but
> that is semantically irrelevant).
Right.
I was talking about reference types with a co-worker a couple of months
ago, and we found an analogy that seemed to help:
One can imagine variables as small envelopes, just large enough to hold
a single piece of paper. Some things can fit on this piece of paper
entirely, like numbers and strings, others are too large, like objects.
When you create an object, it's like handing your cloak (the object) to
a checkroom attendant. He will put the cloak on a rack and hand you a
paper receipt to identify it later. You put this piece of paper in your
envelope: your variable now contains a reference to an object.
Now you can use this receipt to access your cloak anytime. You can copy
the receipt to another envelope and it will still work. You can show it
to other attendants (methods), who will copy it from you and can now
also access your cloak.
When you empty your envelope, you lose the reference. The cloak still
exists, but you won't be able to find it again. After a while, the
checkroom attendant may (or may not) notice that this cloak has been
hanging around for weeks, and will throw it away (objects with a
reference count of zero may be garbage collected).
The analogy is getting a little stretched now, but bear with me...
When you write options.add(o), that's like showing your receipt to an
attendant and saying "take this cloak from wherever it is and hang it on
the tree outside" (the DOM tree). You can do that any number of times,
but in the end your cloak will be hanging on the tree only once. If you
put something else in your envelope, like a blank piece of paper (o =
null), the cloak on the tree is unaffected by this. You just don't have
an easy way to find it again.
> Does opt.text = opt.value = Os[i]; equal to
> opt.text = Os[i];
> opt.value = Os[i];
> ?
> It appears so. Could you give a practical example of such usage? (as
> you mentioned in this case it's not necessary to set the value.
I thought that was a practical example ;)
You can use 'a = b = c = 42' whenever you want to assign the same value
to more than one variable or property. The values will be assigned from
right to left:
- precedence made explicit: a = (b = (c = 42))
- the expression c = 42 is evaluated first, and returns 42
- that result is assigned to b, and the assignment returns 42 again
- that result is then assigned to a
If you do this with variables, be careful to declare them first. This is
a common mistake:
function makeRedBlock () {
var color = "red",
height = 20,
width = length = 10;
//...
}
This will assign the values as intended, but 'length' has not been
declared and will end up as a global.
>> But I reuse other objects. What is so special about the DOM
>> structure?
>Because appendChild hooks the element you create with createElement, >into the DOM. Before you did the appendChild, it exists and you have a >pointer to it. After, the DOM has a pointer to it too and so it's in the
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^***
Aha! The light has finally gone on.
>DOM - in whatever place you put it. If you append it again, then what >you've done is to *move* it to elsewhere in the DOM.
I was not fully cognisant of references to an object. The object
still exists, even after dSelect()'s o has gone out of scope.
I tried the original code, modifying it so that it was not
.add()ed again. The changes in o's properties still showed up in the
select. This fits my understanding.
Now, I understand.
Sometimes, I miss things. I now wonder how I missed this. Thank
you to all of you who persisted in trying to untangle this for me.
>IOW: you can't null any object. You only can set a variable which
>contains a reference to an object to null. This doesn't affect the
>object itself, only the variable changes. If all references to an
>existing object are gone, the object might be garbage collected (but
>that is semantically irrelevant).
I got it. I messed up on reference count. Thank you very much
for your help.
Stefan Weiss wrote:
> I was talking about reference types with a co-worker a couple of months
> ago, and we found an analogy that seemed to help:
> One can imagine variables as small envelopes, just large enough to hold
> a single piece of paper. Some things can fit on this piece of paper
> entirely, like numbers and strings, others are too large, like objects.
> When you create an object, it's like handing your cloak (the object) to
> a checkroom attendant. He will put the cloak on a rack and hand you a
> paper receipt to identify it later. You put this piece of paper in your
> envelope: your variable now contains a reference to an object.
> Now you can use this receipt to access your cloak anytime. You can copy
> the receipt to another envelope and it will still work. You can show it
> to other attendants (methods), who will copy it from you and can now
> also access your cloak.
> When you empty your envelope, you lose the reference. The cloak still
> exists, but you won't be able to find it again. After a while, the
> checkroom attendant may (or may not) notice that this cloak has been
> hanging around for weeks, and will throw it away (objects with a
> reference count of zero may be garbage collected).
> The analogy is getting a little stretched now, but bear with me...
> When you write options.add(o), that's like showing your receipt to an
> attendant and saying "take this cloak from wherever it is and hang it on
> the tree outside" (the DOM tree). You can do that any number of times,
> but in the end your cloak will be hanging on the tree only once. If you
> put something else in your envelope, like a blank piece of paper (o =
> null), the cloak on the tree is unaffected by this. You just don't have
> an easy way to find it again.
This is arguably the best analogy for this mechanism that I have read so far. And it is funny, too.
+1
PointedEars
-- Anyone who slaps a 'this page is best viewed with Browser X' label on
a Web page appears to be yearning for the bad old days, before the Web,
when you had very little chance of reading a document written on another
computer, another word processor, or another network. -- Tim Berners-Lee
> This matter is more urgent for me than it might be otherwise -- I
>stay away from playing with the DOM much for now -- but that I
>misunderstand is a red flag for me. Not knowing how something works,
>hey, I can deal with that later. Misunderstanding gets me concerned
>about what else I may have wrong.
An important point, which I do not recall having been explicitly made,
is that, although JavaScript permits a whole rats-nest of interlinkings
between Objects (and so, for example, a set of objects cal be linked-
listed in multiple orders at one time), the DOM is a Tree model.
The DOM, therefore, is provided with special Methods for manipulating
its structure; and those preserve the Tree nature.
-- (c) John Stockton, nr London, UK. For Mail, see Home Page. Turnpike, WinXP.
Web <http://www.merlyn.demon.co.uk/> - FAQ-type topics, acronyms, and links.
Command-prompt MiniTrue is useful for viewing/searching/altering files. Free,
DOS/Win/UNIX now 2.0.6; see <URL:http://www.merlyn.demon.co.uk/pc-links.htm>.