IE7 and IE8 not liking my clone/replace of form input

I’m trying to do a simple click event on a checkbox that shows/hides the password in a form. It works in FF and IE9, but IE7 and IE8 are not cooperating. I get the following error in the IE console:

SCRIPT5022: Exception thrown and not caught
jquery-1.6.2.js, line 548 character 3

This is using the non-minified version of jquery 1.6.2

Code is super simple:


$(document).ready(function(){

	// Allow the password to be seen as plain text if desired
	$('#passcheck').click(function(e){
		$('.form_input').each( function(i, el){
			var new_input = $(el).clone();
			if( new_input.attr('type') == 'text' ){
				new_input.attr('type', 'password');
			}else{
				new_input.attr('type', 'text');
			}
			$(el).replaceWith(new_input);
		});
	});

});

I know some of you are javascript gurus and can probably tell me what’s wrong instantly. I’ve been working on this for hours, so I’d really appreciate your help!

While it seems to work fine in Firefox/Chrome/IE9 etc, it certainly does fall over in IE7. I have a theory that perhaps IE6/7 don’t allow you to change the type attribute of an input element. (Don’t quote me on that though…)

I just did a quick test to confirm my suspicion. I ran the below code:

<!DOCTYPE html>
<html>
<head>
	<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
	<script type="text/javascript">
	$(document).ready(function(){
		$("#btn").click(function(){
			var new_input = $("#pass").clone();
			if( new_input.attr('type') == 'text' ){
				new_input.attr('type', 'password');
			}else{
				new_input.attr('type', 'text');
			}
			$("#pass").replaceWith(new_input)
		});
	});
	</script>	
</head>
<body>
	Pass: <input type="password" id="pass" ><br>
	Text: <input type="text" id="txt"><br>
	<button id="btn" value="Button">Button</button>
</body>
</html>

This works fine in modern browsers, but IE6/7 has a problem with it. The apparent solution would be to construct a completely new input dynamically based on the current attributes that it has.

For example, replace the JavaScript from the code above and run the code, you’ll see that it works in the modern browsers as well as IE7 (and presumably 6, I haven’t tested this though).

	
$(document).ready(function(){
	$("#btn").click(function(){
		var $input = $("#pass"),
			inputType = $input.attr("type"),
			inputId = $input.attr("id"),
			inputVal = $input.val();
		
		if( inputType == 'text' ){
			newType = "password"
		}else{
			newType = "text"
		}
		$("#pass").replaceWith("<input type='"+newType+"' id='"+inputId+"' value='"+inputVal+"'>");
	});
});

I went around in circles with this for hours… and finally came up with this, which works in all browsers:

$(document).ready(function(){
	// Allow the password to be seen as plain text if desired
	$('#see_pass').click(function(e){
		$('#new_pass, #new_pass_conf').each( function(i, el){
			// Get the value
			var current_password = $(el).val();
			// Get the type
			var current_type = $(el).attr('type');
			// Get the ID
			var current_id = $(el).attr('id');
			// determine the replacement
			if( current_type == 'text' ){
				var replacement = '<input id="' + current_id + '" type="password" value="' + current_password + '" class="form_input"/>';
			}else{
				var replacement = '<input id="' + current_id + '" type="text" value="' + current_password + '" class="form_input"/>';
			}
			// Remove the element
			$(el).remove();
			// Do the replacement
			$('#' + current_id + '_div').append( replacement );
		});
	});
});

It may look clunky, but it gets the job done!

By the way, thanks for an alternative solution. I tried it, but for some reason it was causing the fieldset to have a display issue.

Glad to see you got it going.

A note about your comments though. When comments are used to explain what the code is doing, such comments are not considered to be useful.


// Remove the element
$(el).remove();

Instead of explaining what your code does, comments are more more useful when used to explain why things are happening.


// Allow the password to be seen as plain text if desired
$('#see_pass').click(function(e){