0

Problem

The following scripts do exactly what I require, in all browsers tested except IE8, where it removes the button without replacing it with anything.

Background

I have been working on a method to replace submit type inputs with image type inputs using jQuery.

First, I had this following which works with FF and webkit:

        marker = jQuery('<span class="marker"></span>').insertBefore('input#SearchButton');
        jQuery('input#SearchButton').detach().attr('type', 'image').attr('src',theme_folder+'/style/images/search_button.png').insertAfter(marker);
        marker.remove();

But this fails in all 6+ versions if IE (it removes the button, but doesn't replace with image), so I developed the following script for IE browsers:

        marker = jQuery('<span class="marker"></span>').insertBefore('input#SearchButton');
        new_search = jQuery('<input id="SearchButton" value="Search" name="Searchbutton" type="image" src="'+theme_folder+'/style/images/search_button.png'+'" />')

        jQuery(new_search).insertAfter('input#SearchButton');
        jQuery('input#SearchButton').remove();
        marker.remove();

I am using HTML Conditionals to filter the flow of traffic to the appropriate script, so so the whole thing looks like this:

<!--[if IE]>
    <script>

        marker = jQuery('<span class="marker"></span>').insertBefore('input#SearchButton');
        new_search = jQuery('<input id="SearchButton" value="Search" name="Searchbutton" type="image" src="'+theme_folder+'/style/images/search_button.png'+'" />')

        jQuery(new_search).insertAfter('input#SearchButton');
        jQuery('input#SearchButton').remove();
        marker.remove();

    </script>
<![endif]-->

<![if !IE]>
    <script>

        marker = jQuery('<span class="marker"></span>').insertBefore('input#SearchButton');
        jQuery('input#SearchButton').detach().attr('type', 'image').attr('src',theme_folder+'/style/images/search_button.png').insertAfter(marker);
        marker.remove();

    </script>
<![endif]>
Mild Fuzz
  • 29,463
  • 31
  • 100
  • 148

2 Answers2

6

On IE, the type property of the input element is write-once. You cannot change it once you've set it the first time. (There's a warning about this in the attr documentation.)

Your only real option to be compatible with IE is to actually replace the element with a new one with the same id. Obviously this has an impact on event handlers (any you've attached to the old element won't be attached to the new one), so you may want to use delegate (or the global version, live) rather than attaching handlers directly to the element in question.

Update: Ah, I see you've written some code to do that. The problem with that code is that you're temporarily creating an invalid document (it has two different elements with the same id) and then looking up the element by that duplicate id. It'll be fine if you just grab the element in advance:

// Get the old search button
old_search = jQuery('input#SearchButton');

// Create the new search button
new_search = jQuery('<input id="SearchButton" value="Search" name="Searchbutton" type="image" src="'+theme_folder+'/style/images/search_button.png'+'" />')

// Insert the new one after the old (temporarily creates an invalid document)
jQuery(new_search).insertAfter(old_search);

// Now remove the old one
old_search.remove();

(You don't need the marker for this, so I've removed it from the above.)

But you may want to look at using replaceWith instead:

jQuery('input#SearchButton').replaceWith(
    '<input id="SearchButton" value="Search" name="Searchbutton" type="image" src="'+theme_folder+'/style/images/search_button.png'+'" />'
);

Here's a simplified replaceWith example (also demonstrating delegate):

HTML:

<div id='container'>
  <p>This button is in the container, and so clicks
    on it will convert it back and forth between
    <code>input type='button'</code> and
    <code>input type='image'</code>.</p>
  <input type='button' value='Click Me'>
</div>
<div>
  <p>This button is <strong>not</strong> in the
    container, and so clicks on it aren't processed.</p>
  <input type='button' value='Click Me'>
</div>

JavaScript:

$('#container').delegate('input', 'click', function() {
  if (this.type === "button") {
    $(this).replaceWith(
      "<input type='image' src='" + imageSrc + "'>"
    );
  }
  else {
    $(this).replaceWith(
      "<input type='button' value='Click Me'>"
    );
  }
});

Live copy

The button there doesn't have an id, but it's totally fine if it does:

HTML:

<div id='container'>
  <input type='button' id='theButton' value="Click Me, I'll Change">
  <br><input type='button' value="Click Me, I Won't Change">
</div>

JavaScript:

$('#container').delegate('#theButton', 'click', function() {
  if (this.type === "button") {
    $(this).replaceWith(
      '<input id="theButton" type="image" src="' + imageSrc + '">'
    );
  }
  else {
    $(this).replaceWith(
      '<input id="theButton" type="button" value="Click Me, I\'ll Change">'
    );
  }
});

Live copy


Off-topic: Since you have to replace the element to support IE anyway, I'd recommend just having the one copy of the code and using it on all browsers. It's not that expensive to replace the element, even on browsers that let you change it.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Note about your off topic, there are many buttons I need to change, and the non-IE script is quicker. – Mild Fuzz May 04 '11 at 10:56
  • Will the delegate add the click to the body element? I don't quite understand that! – Mild Fuzz May 04 '11 at 11:10
  • @Mild Fuzz: That's right. It's jQuery's handy syntax for the general technique called *event delegation*. Unless they're stopped, most DOM events bubble from the element on which they actually occurred up to the parent of that element, then the parent of the parent, etc. So if there's a container for all of these buttons, you can use it (instead of "body"). The clicks will start on the buttons but bubble up to the container, where they'll get processed. jQuery will handle checking that the event started on an element matching the selector you give and call your function if so. – T.J. Crowder May 04 '11 at 11:21
  • @Mild Fuzz: I've updated the examples at the end, hopefully clearer. – T.J. Crowder May 04 '11 at 11:29
-1

You cannot dynamically change a the type of an input element in Internet Explorer. You have to remove the old input and add a new input

Khoa Nguyen
  • 1,319
  • 7
  • 21