Working with a Select group and cloneNode in JavaScript

Hi experts,
I’m banging my head against the wall on this one and request your assistance.

I have script that creates a form from another pages form and i’m using the cloneNode method javascript.
The problem i have is that when I clone the select groups the currently selected option is lost and i am re-setting the selected option using the selectedIndex property and then writing to the new form with innerHTML. This seams to work in IE but not in Firefox/Chrome/Safari. Any suggestions?


//construct url to submit to popup window
function submitFormToPopup(form) { 
     
    var newWin = window.open("","TestWindow","width=700,height=200,modul"); //window.blur();
    var theForm = document.getElementById(form);
    var adhocForm = document.createElement("div");         

    newWin.document.write('<html><head><title>Popup</title>');
    //newWin.document.write('</head><body onload="document.getElementById(\\'formSubmit\\').submit();">');
    newWin.document.write('</head><body>'); 
	newWin.document.write('<form action="AccountEditConf.php" id="formSubmit" method="GET" style="display: block;">');
	
	for (var i=0;i<theForm.length;i++) {
		var newElement = theForm.elements[i].cloneNode(true);
		if (newElement.type == "select-one") { 
			newElement.value = theForm.elements[i].value;
		}
		adhocForm.appendChild(newElement);
	}
	newWin.document.write(adhocForm.innerHTML); 

//    var ad = adhocForm.innerHTML; 
//    newWin.document.write(adhocForm.innerHTML);
    newWin.document.write('</form>');
    newWin.document.write('</body></html>');
	newWin.document.close();     
	window.blur();
	setTimeout("window.reload()",1600);
    return true; 
 }

Hi,

Well, there’s a few things wrong with that code.
I have never used cloneNode before, it doesn’t seem to have great support.
cloneNode (JavaScript method)

You said you were using selectedIndex which is the correct way to set the value of a select list, but it’s not in your code.

You’re also getting a form element - then trying to iterate over it with:

for (var i=0;i<theForm.length;i++) {

I’m surprised that works in any browser. You need to be getting the list of elements from within the form.

Also, I don’t believe the type will ever be “select-one”.

There is almost certainly a better way to be doing that - but I’m still not sure why you are doing what you are doing :wink:

The following script works in all non-IE browsers - I haven’t been able to find the right syntax for IE, but this works well in the others.

The way to do this is to write the body of newWin and then append the clone of the form to it in newWin. If you use the deep method - all child elements of the target element, you can append the whole form in one go. You can do it the other way too - appending the elements one at a time, but it takes three appends, rather than one.

[HIGHLIGHT=“”]
<!doctype HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>
<html>

<head>

<meta http-equiv=“Content-Type” content=“text/html; charset=windows-1252”>
<title>Clone nodes to new window</title>
<script type=“text/javascript”>
<!–

window.onload=function(){
var newWin = window.open(“”,“TestWindow”,“width=700,height=200,modul”);
var theForm = document.forms[0];
// build html for new window
var build=‘<html>
<head>
‘;
build+=’<style type=“text/css”>
body { font-family:arial, helvetica, sans-serif; font-weight:bold; }
<\/style>
‘;
build+=’<title>This is the new window<\/title>
<\/head>
<body>’;
build+='<p style=“color:#F00”>This is your new window with a form<\/p>
‘;
build+=’<\/body>
<\/html>
';
newWin.document.write(build);
var newElement = theForm.cloneNode(true);
newWin.document.body.appendChild(newElement);
//
newWin.document.close();
}
// ---------
//–>
</script>
</head>

<body>

<form name=“myForm” method=“post” action>
<p class=“a”><input type=“text” name=“txtB1” value=“bbb” size=“20”></p>
<p><input type=“text” name=“txtB2” value=“bbb” size=“20”></p>
<p><input type=“text” name=“txtB3” value=“bbb” size=“20”></p>
</form>

</body>

</html>

Thanks for the response Mark. You’re right i had some issues with this script for sure. It might help to provide some more background to what i’m trying to do here. Essentially I’m using this script to off-load changes to a popup so that the user doesn’t have to navigate to another page to change options in their profile. I’m thinking that there is probably a much better way to handle this in Ajax but i’m not skilled in Ajax or Ruby etc… so this is my work around. I was wondering if there is just a way to dump all the name and value pairs from the form into the windows _GET array and pass that to another page instead but i see how to do that in client side scripting; i see that its fairly easy in PHP but what do you think?

By the way I wrote this last night and it seams to work in both IE and others with the exception of the password field that is previously created using the createElement(“input”) method before the user submits:


//construct url to submit to popup window
function submitFormToPopup(form) { 
     
    var newWin = window.open("","TestWindow","width=700,height=200"); //window.blur();
    var theForm = document.getElementById(form);
    var adhocForm = document.createElement("div");
	var adhocFormIE = document.createElement("div"); 
    newWin.document.write('<html><head><title>Popup</title>');
    newWin.document.write('</head><body onload="document.getElementById(\\'formSubmit\\').submit();">');
	//newWin.document.write('</head><body>'); 
	newWin.document.write('<form action="AccountEditConf.php" id="formSubmit" method="GET" style="display: block;">');

	 	for (var i=0;i<theForm.length;i++) {
			if ( navigator.appName == "Microsoft Internet Explorer") {
				var newElement = document.createElement("<input name="+theForm.elements[i].name+">");
				newElement.setAttribute("value",theForm.elements[i].value);
				newElement.setAttribute("type","text");
				adhocForm.appendChild(newElement);
		
				//alert(newElement);
				//adhocForm.appendChild(newElement);
			} else {
				var newElement = document.createElement("input");
		//window["newElement" + i] = document.createElement("input");
		//eval("var newElement" + i + "=document.createElement(\\"input\\");"); 
			newElement.setAttribute("type","text");
			newElement.setAttribute("name",theForm.elements[i].name); 
			newElement.setAttribute("value",theForm.elements[i].value);
			adhocForm.appendChild(newElement);
			//newWin.document.write(newElement.innerHTML); 
			//document.getElementById("formSubmit").appendChild(window["newElement" + i]); 
			}
		}
		var ad = adhocForm.innerHTML; 
		newWin.document.write(ad)

    newWin.document.write('</form>');
	newWin.document.write('</body></html>');
	newWin.document.close();
	window.blur();
	setTimeout("window.reload()",1600);
    return true; 
 }


Thanks Allan,
This works good in all browsers EXCEPT IE but the reason it doesn’t work in IE is because before the user submits the form he clicks a span that creates on the flyer an optional password update field. What i’m finding out now is that IE doesn’t work so well with the document.createElement(“input”); function because the setAttribute(“name”,“blahblah”) doesn’t work. I’m working around this by doing

document.createElement("&lt;input name=\\"blahblah\\"&gt;");

but that can’t be the right way to do it. maybe you can tell me if there is a better way to commit the user profile changes using ajax or something that wouldn’t require the user to have to navigate another page? If you read my previous post i explain that i’m just trying to keep the user from having to go to a confirmation page using a pop-up but the pop-up thing gets annoying after a while.

It’s sounds like you are wanting to serialize a form into name/value pairs and submit.
If you want to do this without submitting the actual form I’ve used this type of function before, it may not be what you are wanting but could help:


function serialize(els) {
    var values = [];
    for (var i = 0, ii = els.length; i < ii; i++) {
        var input = els[i];
        if (input.tagName == 'SELECT' && input.multiple) {
            for (var j = 0, jj = input.options.length; j < jj; j++) {
                var option = input.options[j];
                if (option.selected) {
                    values.push(input.name + '=' + encodeURIComponent(option.value));
                }
            }
        }
        else if (!(/checkbox|radio/.test(input.type) && !input.checked) && input.type != 'submit') {
            values.push(input.name + '=' + encodeURIComponent(input.value));
        }
    }
    return values.join('&');
}
function serializeForm(form) {
	var els = [],
		types=['input','select','textarea'];
	for (var i = 0, ii = types.length; i < ii; i++) {
		var fields = form.getElementsByTagName(types[i]);
		for (var j = 0, jj = fields.length; j < jj; j++) {
			els.push(fields[j]);
		}
	}
    return form.action + '?' + serialize(els);
}

It takes a form, gets the input,textarea,select elements and puts the name value pairs into a URL as if the form was submitted with the GET method.

The simple solution is to use a frame page with one of the frames hidden . Here’s a typical example:

<frameset framespacing=“0” border=“0” frameborder=“0” cols=“*,100%”>
<frame name=“leftPage” target=“main” src=“leftPage.htm”>
<frame name=“main” scrolling=“auto” src=“main_page.htm”>

Your form is in the main page and the whole of the contents of the form can be stored in the left page, which is hidden. You can then have a success page show in the main page frame and then revert to the form again without losing any of the previously input information.