Connecting Tech Pros Worldwide Help | Site Map

DOM object assignment

Peter Nofelt
Guest
 
Posts: n/a
#1: Jul 23 '05
Hey all,

I am running into an issue. My situation is that I wish to copy the
contents of one listbox to an array, sort it by innerText value, and
write the sorted options into a new listbox.

Currently I am able to do this by assigning the innerText of the old
listbox to the innerText of the new listbox. I find this tedious as i
have some other attributes that I eventually would need to copy over to
the new listbox.

INSTEAD, I would like to assign the <option> object of the old listbox
to the new listbox object by object, but when i do this I get an object
assignment error.

Below is a stripped down demo that you can run to see whats going on. A
few things to note:

o The function CHashTable is a class providing psudeo hastable
functionality that I use as a map to reference the <option>'s from the
old listbox.
o I am not concerned about having this code be cross-browser compliant,
the client is only working in an IE enviorment (due to the applications
reliance on active X controls).

Below is the code, to run it just click on the button. I commented out
the debugger keywords. Also, the most important function to node is
writeAsElement() considering that this is where I am having issues.

Cheers,
Peter


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<title></title>
<meta name="GENERATOR" content="Microsoft Visual Studio .NET 7.1">
<meta name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body>
<script type="text/javascript">



/////////////////////////////////////////
// Function class for providing psudo-hashtable functionality
function CHashTable(){
var m_arryHashTable = new Array();

// function that allows the user to add a specific key
// and value to the hash table
this.addToLookup = function(p_strNewLookupKey, p_lngValue){
m_arryHashTable[p_strNewLookupKey] = p_lngValue;
}

// function to retun if a specific hash function exists
this.checkLookup = function(p_strLookupKey){
if(m_arryHashTable[p_strLookupKey] === undefined)
return false;
else
return true;
}

this.hashSize = function(){return m_arryHashTable.length; }

// function to return a value the value at a specific hash key value
this.getLookupValue = function (p_strLookupKey){
return m_arryHashTable[p_strLookupKey];
}
}


function allyo(){
//debugger;
var oSwap = new CSortList();
oSwap.sendFormReference();
oSwap.writeAsElement();
}

function CSortList(){
var m_docHtmlOptions;
var m_hash = new CHashTable();
var m_array = new Array();
var m_num = new Number();

this.swapOldOptionsWithNew2 = function(p_hash, p_sort){
var docHtmlOptionsTemp = document.createElement("options");
for (var i = 0; i < p_sort.length; i++)
docHtmlOptionsTemp.option[i] = p_hash.getLookupValue(p_sort[i])
return docHtmlOptionsTemp
}

this.writeAsElement = function(){
//debugger;

var docHtmlSelect = document.createElement("select");

/////////////////////////////////////////
/// What currently works
docHtmlSelect[0] = document.createElement("OPTION");
docHtmlSelect[1] = document.createElement("OPTION");
docHtmlSelect[0].innerText = "wawawewow";
docHtmlSelect[1].innerText = "asdfewow";

docHtmlSelect[0].innerText =
m_hash.getLookupValue(m_array[0]).innerText;
docHtmlSelect[1].innerText =
m_hash.getLookupValue(m_array[1]).innerText;
/////////////////////////////////////////
/////////////////////////////////////////

/////////////////////////////////////////
/// What i would like to work
/*
docHtmlSelect[0] = document.createElement("OPTION"); // may not need
this
docHtmlSelect[1] = document.createElement("OPTION"); // may not need
this

docHtmlSelect[0] = m_hash.getLookupValue(m_array[0]);
docHtmlSelect[1] = m_hash.getLookupValue(m_array[1]);
*/
docHtmlSelect.id = "hardSelect";
//docHtmlSelect.style.display = "none";
document.body.appendChild(docHtmlSelect);
}


this.sendFormReference = function()
{
//debugger;
var selectToSort = document.getElementById("formID")

var selectLength = selectToSort.length;
var selectOptions = selectToSort.options;

// store options into lookup table, reference via text element
var oHashOptions = new CHashTable();
for (var i = 0; i< selectLength; i++)
oHashOptions.addToLookup( selectOptions[i].text, selectOptions[i])

// push the text element of each option into an array
var arryOptionsToSort = new Array();
for (var i = 0; i< selectLength; i++)
arryOptionsToSort.push(selectOptions[i].text)
// sort array
arryOptionsToSort.sort();

var docHtmlOptionsTemp = new document.createElement("options");
for (var i = 0; i < arryOptionsToSort.length; i++)
docHtmlOptionsTemp[i] =
oHashOptions.getLookupValue(arryOptionsToSort[i])

m_hash = oHashOptions;
m_array = arryOptionsToSort;
m_docHtmlOptions = docHtmlOptionsTemp;
m_num = 3;
}
}

</script>
<p><br>
<!--<button>hey there</button>-->
<select size="5" name="selectIdName" id="formID">
<option value="value1">cvalue1</option>
<option value="value3">kvalue3</option>
<option value="value2">avalue2</option>
<option value="value3">bvalue3</option>
</select>
<button onclick="allyo();" ID="Button1">clickme</button>
</body>
</html>

Fred Oz
Guest
 
Posts: n/a
#2: Jul 23 '05

re: DOM object assignment


Peter Nofelt wrote:[color=blue]
> Hey all,
>
> I am running into an issue. My situation is that I wish to copy the
> contents of one listbox to an array, sort it by innerText value, and
> write the sorted options into a new listbox.[/color]
[...]

I'd suggest the following approach:

Concatenate the option value and text with a delimiter
Put them into an array
Sort the array
Create a new select with options based on the new sorted array
Split the value and text based on the delimiter used above

The following is only lightly tested, but demonstrates the method. You
may have an issue with delimiters, but the choice is up to you. Also,
you have great flexibility with the sort function to sort any way you
want. If you want to sort on text rather than value, put it first in
the array elements.

Have fun.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Change Data2</title>
<script type="text/javascript">

function allyo(sel) {
var arr = [];
for (var i=0; i<sel.options.length; i++) {
arr.push(sel.options[i].value + '.' + sel.options[i].text);
}
arr = arr.sort();

// Now create the new select element
oSel = document.createElement('SELECT');

// Create the options and append them
for (var j=0; j<arr.length; j++) {
oObj = document.createElement('OPTION');
oObj.value = arr[j].split('.')[0];
oObj.text = arr[j].split('.')[1];
oSel.appendChild(oObj);
}
oSel.size = '5';
sel.parentNode.appendChild(oSel);
}

</script>
</head>
<body>
<p><br>
<form action="">
<select size="5" name="selectIdName" id="selectIdName">
<option value="value1">cvalue1</option>
<option value="value3">kvalue3</option>
<option value="value2">avalue2</option>
<option value="value3">bvalue3</option>
</select>
<input type="button" onclick="allyo(this.form.selectIdName);"
value="click me">
</form>
</body>
</html>


--
Fred
Michael Winter
Guest
 
Posts: n/a
#3: Jul 23 '05

re: DOM object assignment


On 20 Dec 2004 13:55:08 -0800, Peter Nofelt <pcnofelt@gmail.com> wrote:

I presume that Fred has helped with the original problem, so I'll
concentrate elsewhere.

[snip]
[color=blue]
> // Function class for providing psudo-hashtable functionality
> function CHashTable(){[/color]

I thought you might like to know that your hashtable is broken.
[color=blue]
> var m_arryHashTable = new Array();[/color]

The first thing to note is that the length property of an array object
only changes if you assign values to an "array index" - I'll explain what
that is in a moment.

As you seem to understand, when you use square brackets with any
object[1], the expression is used to look up a value. In fact, *every*
expression (even a numeric literal) is evaluated, converted to string, and
used as a property name. The only exception is with array objects.

When the internal [[Put]] method (used to assign to property values) of an
array is called, it performs a test on the property name. It attempts to
convert the (string) property name to a (32-bit) number, then back to a
string. If the number is less than (2^32)-1, and the string values before
and after the conversion match exactly, the property name is considered an
array index. So:

'10' -> 10 -> '10' '10' == '10' therefore an array index
'ff' -> NaN -> 'NaN' 'ff' != 'NaN' therefore not an array index
'01' -> 1 -> '1' '01' != '1' therefore not an array index

Any property name can be used with an array object, but only array
indicies will ever change the length property. The obvious impact of this
is that your hashSize method will fail entirely unless every key is
considered an array index - you have to track addition and removal
operations yourself. The other, not so obvious problem, is that you don't
distinguish between properties that might originate from the object
prototype, and those added as a key.

Every object has a predefined set of properties. Some implementations may
include more than others. It's quite feasible that code may call

hash.checkLookup('pop')

on your hashtable. In this instance, checkLookup would return true even
though the code may not have added its own key named 'pop' because array
objects have a pop method. There are two simple ways to lessen the impact
of this problem:

1) Use a "plain" object to hold the properties, not an array.
Objects have fewer predefined properties so there's less chance
of any name collisions. Moreover, as you're not using any array
features, its more efficient to use an object.
2) Mutate the key before using it. You could easily add a unique
sequence of characters, such as '_ ' (yes, the space is
intentional) to the property name. It's highly unlikely that an
implementation will expose properties like that.

There are several hashtable implementations in the archives of this group
that vary from the quick and dirty to the fully-featured and robust. See
<URL:http://groups.google.com/groups?q=group%3Acomp.lang.javascript+%22hash+tabl e%22+%7C+hashtable>.

[snip]
[color=blue]
> this.checkLookup = function(p_strLookupKey){
> if(m_arryHashTable[p_strLookupKey] === undefined)
> return false;
> else
> return true;
> }[/color]

return undefined !== m_arryHashTable[p_strLookupKey];

or

return 'undefined' != m_arryHashTable[p_strLookupKey];

is preferable.

[snip]
[color=blue]
> function CSortList(){
> var m_docHtmlOptions;
> var m_hash = new CHashTable();
> var m_array = new Array();[/color]

You might want to consider whether it's worth initialising these methods
as you're only going to overwrite them.
[color=blue]
> var m_num = new Number();[/color]

This is certainly unnecessary. Here you're creating an immutable Number
object with a value of zero.

var m_num = 0;

would be more efficient.
[color=blue]
> this.swapOldOptionsWithNew2 = function(p_hash, p_sort){
> var docHtmlOptionsTemp = document.createElement("options");[/color]

There's no such thing as an OPTIONS element.
[color=blue]
> for (var i = 0; i < p_sort.length; i++)
> docHtmlOptionsTemp.option[i] = p_hash.getLookupValue(p_sort[i])
> return docHtmlOptionsTemp
> }[/color]

As this method doesn't access any private data, it would be better to add
it to the prototype of CSortList. That goes for any method in a similar
situation.

[snip]
[color=blue]
> this.sendFormReference = function()[/color]

[snip]
[color=blue]
> var docHtmlOptionsTemp = new document.createElement("options");[/color]

Again, no OPTIONS element. Also, the new operator is unnecessary.

[snip]
[color=blue]
> <p><br>[/color]

You should use padding or a margin rather than a BR element.

Good luck,
Mike


[1] This could cover anything. Objects, functions and arrays are obvious
examples, but the other types - boolean, date, number, regexp, string -
display this ability, too.

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Closed Thread