Link to home
Start Free TrialLog in
Avatar of MatthewP
MatthewPFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Problem writing Javascript to the DOM in IE only

I've got a bit of a confusing one here regarding writing to the DOM on the fly. I've included a stripped down version of my page in the code section below to highlight the problem that can be reproduced locally.

If you run the page in Firefox and the IE7 it should be pretty obvious what the problem is, but I'll explain: I start my page with 2 select fields in static HTML - the options/values of the second are written dynamically depending on what is selected in the first select field, so they work as a pair. The first is a category, the second essentially is a product. This bit is working fine, when i change category the options change in the product drop down.

I now have a button to add further pairs of these select fields to create further category/product inputs, and when this button is clicked there's a fair amount of script which creates notes and inserts them into the DOM in the appropriate place, giving new names to the fields based on a random number. This bit actually works fine too, and even a button to remove the parent paragraph tag which the new select pairs are in works fine in both browsers.

What Im having trouble with is setting the attribute of 'onChange' in the first select to call the javascript function. The function requires two parameters - the selectedIndex and the name of the field to update, and this is done in line 73 - the variable "passFunctionInSetAttr" is set and ontains the complete function call. This is then added to the node 3 lines later (after being alerted to the screen so I can see what is going on and that it is fine - it is).

And in firefox it works perfectly - I get an alert to say that its reached the updateproducts  function as expected and the newly created select list updates with the products list, but in IE (Im in version 7) - despite that I'm echoing the string back in the alert to see it's working - and it seems to be - it fails silently without an error message or anything and it doesnt reach the function to update the products - I can tell as the alert doesnt come up. I've been pulling this apart today in Visual Web Developer 2008 to try and get some debugging messages and theres no error message or anything, yet it doesn't work and fails in total silence.

I've added a 'Print Dom' button to this too, so I can print out the structure of the document that's been written on the fly and take a look - and it does look a little odd - the paragraph id isn't quoted for example (how can I change this I wonder..) but it seems to look vaguely ok.

Weirdly though, if i then paste the dom that is dumped out into the text area into its own document, and run it locally in a browser (just need to add the Doctype and HTML tags around the core code), it then gets as far as the function in IE and flashes up the alert which it didn't before. It still fails to update the second select..  but this is supposed to be exactly the same script, just one is written on the fly and the other has been run from a static HTML document - and its behaving differently.

Not sure if I've done something stupid here or hit a Javascript bug, but many thanks in advance for any help anyone can give me on this!

Matt


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Select DOM Test</title>
<script type="text/javascript">
    function node_delete(whichPara) {
        if (confirm("Are you sure you want to delete this product?")) {
            document.getElementById('allparas').removeChild(document.getElementById(whichPara));
       }
    }
 
    function printDom() {
        allHTML = document.getElementsByTagName("html")[0].innerHTML;
        document.forms['update_table'].elements['dom'].value = allHTML;
 
    }
    var products_matrix = new Array();
    products_matrix[0] = "";
    products_matrix[1] = new Array("550|X1|product 1|10");
    products_matrix[2] = new Array("551|Y1|Product in section 2|10", "552|Y2|Another Product in Section 2|10");
    products_matrix[3] = new Array("640|B-682|Product in 3|1", "641|B-682-int|Another in 3|1", "642|CD-682|Product|1", "643|CD-6821|Another Product|1", "644|CD-C|And Another Product|1");
    products_matrix[4] = new Array("611|E-API682sd|Item in section 4|15", "612|B-AP|Another item in section 4|15", "613|S2wed|item name here|20", "614|B-Chem|Another items|15", "615|B-Chem|and another|15", "616|B-C|Aargh|15", "624|B-Oi|Final test product|15");
 
    var categories_names_array = new Array("Section 1", "Section 2", "Section 3", "Section 4");
    var categories_ids_array = new Array("6", "7", "12", "9");
 
    function updateproducts(selectedcategory, fieldtoupdate) {
        alert("reached update products function");
        
        var categorieslist = document.update_table.category1
        var productslist = eval("document.forms['update_table'].elements['" + fieldtoupdate + "']")
 
        productslist.options.length = 0
        if (selectedcategory > 0) {
            for (i = 0; i < products_matrix[selectedcategory].length; i++)
                productslist.options[productslist.options.length] = new Option(products_matrix[selectedcategory][i].split("|")[1] + "  -  " + products_matrix[selectedcategory][i].split("|")[2], products_matrix[selectedcategory][i].split("|")[0]);
        }
    }
 
    //-->
</script>
</head>
<body>
 
<form name="update_table" method="post" action="" enctype="multipart/form-data" style="padding:0px; margin:0px">
<p style="font-size:12px">Select Category:<br />
<select name="category1" onChange="updateproducts(this.selectedIndex,'product1')" />
<option value="">Select a category:</option>
<script language="Javascript">
    for (p=0;p<categories_names_array.length;p++){
	document.write("<option value=\"" + categories_ids_array[p] + "\">" + categories_names_array[p] + "</option>\n");
    }
</script></select>
</p>
 
<p style="font-size:12px">Product Name: <select name="product1" style="font-size:13px">
<option value="" style="font-family:tahoma,arial,verdana,helvetica"> Please select a category first </option>
</select>
</p>
 
<div id="allparas">
<span class="order_button" style="margin-top:30px"><a style="font-weight:bold; clear:both; padding-top:10px; margin-top:10px;" href="#" onclick="
if( !document.createElement || !document.childNodes ) {
	window.alert('Your browser is not DOM compliant');
} else {
	// set up paragraph and select
	randomNumber = Math.floor(Math.random()*9999999999999999) 
	var theNewParagraph = document.createElement('p');
	var lineBreak = document.createElement('br');
	var divName = 'div_' + randomNumber;
	var theTopCategorySelect = document.createElement('select');
	var theSelect = document.createElement('select');
	newSelectName= 'select_' + document.getElementsByTagName('p').length;
	newCatSelectName= 'select_category_' + randomNumber
    myRandomNumber = Math.floor(Math.random()*9999999999999999);
	newSelectName = newSelectName + myRandomNumber;
    theSelect.setAttribute('name',newSelectName);
    theSelect.setAttribute('style','font-size:13px;');
	theTopCategorySelect.setAttribute('name',newCatSelectName);
	theTopCategorySelect.setAttribute('style','font-size:13px');
    
	passFunctionInSetAttr='updateproducts(this.selectedIndex,\'' + newSelectName + '\')';
	alert(passFunctionInSetAttr);
	
	theTopCategorySelect.setAttribute('onChange',passFunctionInSetAttr);
 
	// set up options for select
	firstOption = document.createElement('option');
	firstOption.setAttribute('value','');
	firstOption.setAttribute('style','font-weight:bold; font-size:12px');
	firstText = document.createTextNode(' - ');
	theSelect.appendChild(firstOption);
	firstOption.appendChild(firstText);
	arrayOptions=Array();
	arrayText=Array();
   
	// set up options for category select
	catFirstOption = document.createElement('option');
	catFirstOption,setAttribute('value','');
	catFirstOption.setAttribute('style','font-weight:bold; font-size:12px');
	catFirstText = document.createTextNode('Select A Category:');
	theTopCategorySelect.appendChild(catFirstOption);
	catFirstOption.appendChild(catFirstText);
	arrayOptions=Array();
	arrayText=Array();
    for (p=0;p<categories_ids_array.length;p++){
		arrayOptions[p] = document.createElement('option');
		arrayOptions[p].setAttribute('value',categories_ids_array[p]);
		arrayOptions[p].setAttribute('style','font-size:13px; ');
		arrayText[p] = document.createTextNode(categories_names_array[p]);
		theTopCategorySelect.appendChild(arrayOptions[p]);
		arrayOptions[p].appendChild(arrayText[p]);
	}
 
	var theDeleteImage = document.createElement('img');
	
	//set up theNewParagraph
	newParaName= 'para_' + document.getElementsByTagName('p').length;
	newParaName += randomNumber; 
	theNewParagraph.setAttribute('id',newParaName);
	theNewParagraph.setAttribute('style','padding-top:10px; font-size:12px; clear:both;');
 
    // delete image 
	theDeleteImage.setAttribute('src','http://www.dmlmarketing.net/demo/cancel.png');
	deleteImageName = 'delete_' + document.getElementsByTagName('p').length;
	deleteImageName += randomNumber; 
	theDeleteImage.setAttribute('id',deleteImageName);
	theDeleteImage.setAttribute('hspace','20');
	theDeleteImage.setAttribute('vspace','3');
 
    // div
	theDiv = document.createElement('div');
	theDiv.setAttribute('id',divName); 
	theDiv.setAttribute('style','display:inline; float:left;'); 
 
 	//prepare the text nodes
	var theText1 = document.createTextNode('Product Name:');
    theCategoryText = document.createTextNode('Select Category:');
       
    
	//put together the whole paragraph
	theNewParagraph.appendChild(theCategoryText);
	theNewParagraph.appendChild(lineBreak);
	theNewParagraph.appendChild(theTopCategorySelect);
	theNewParagraph.appendChild(lineBreak);
	theNewParagraph.appendChild(theText1);
	theNewParagraph.appendChild(theSelect);
	theNewParagraph.appendChild(theDiv);
	theDiv.appendChild(theDeleteImage);
	
	//insert it into the document somewhere
	this.parentNode.parentNode.insertBefore(theNewParagraph,this.parentNode);
	//make the paragraph delete itself when the delete image is clicked
	document.getElementById(deleteImageName).onclick = function () { node_delete(this.parentNode.parentNode.id); };
}
return false;">Add New</a></span>
<hr />
<span style="disaply:block; clear:both;"><textarea name="dom" rows=10 cols=70></textarea><br /><a href="Javascript:printDom()">Print Dom</a></span>
</form>
</body>
</html>

Open in new window

Avatar of HonorGod
HonorGod
Flag of United States of America image

I'm pretty sure that the problem is with this line of code:

document.getElementById(deleteImageName).onclick = function () { node_delete(this.parentNode.parentNode.id);

I've had problems before trying to change the onclick in IE.
What I had to end up doing was checking for an attachEvent function associated with the object (element), and using it, instead of the
assignment like you have, or setAttribute.

Something like:
var ele = document.getElementById( 'deleteImageName' )
if ( ele.attachEvent ) {
  ele.attachEvent( 'onfocus', function() { doSomething(this.event.srcElement); } )
} else {
  ele.setAttribute( 'onclick', 'doSomething(this);' );
}

Open in new window

sorry, the attachEvent should have been
ele.attachEvent( 'onclick', function() { doSomething(this.event.srcElement); } )

Open in new window

Avatar of MatthewP

ASKER

Hi,

Thanks for taking a look. did you try running the code locally? The delete is working perfectly for me in both browsers, its the onChange when written to the DOM that is failing.

Thanks,
Matt
Haven't had a chance yet... Trying to do way too many things at once. :-)
Tell me about it :) I've been on this 2 days and not got anywhere, I need to forget about it for a bit. If you're up for taking a look though the script i sent should demonstrate it pretty succinctly. I've either done something very stupid.. or its an IE bug.. i *think*.

Cheers,
matt

Bit of a curious one this, I got it fixed but not by what I was trying to do but by adding another line similar to:

document.getElementById(deleteImageName).onclick = function () { node_delete(this.parentNode.parentNode.id); };

it all worked correctly - it seems that the event wouldnt attach directly to the element but would if I attached it later. Not figured out why but there you go.
Wow, somehow, I lost track of this, and never returned.

Please forgive me.

I'm glad that you were able to get the issue resolved though.
ASKER CERTIFIED SOLUTION
Avatar of ee_auto
ee_auto

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial