HTMLInputElement.setAttribute('type') Experiment

The scenario

Consider the following code: (Figure 1)

var form = document.createElement('form'); form.setAttribute('id', 'TheForm'); form.setAttribute('method', 'GET'); document.body.appendChild(form); var textbox1 = document.createElement('input'); form.appendChild(textbox1); textbox1.setAttribute('id', 'Textbox1'); textbox1.setAttribute('type', 'text'); textbox1.setAttribute('value', 'textbox1');

Now consider this snippet: (Figure 2)

var form = document.createElement('form'); form.setAttribute('id', 'TheForm'); form.setAttribute('method', 'GET'); document.body.appendChild(form); var textbox1 = document.createElement('input'); textbox1.setAttribute('id', 'Textbox1'); textbox1.setAttribute('type', 'text'); textbox1.setAttribute('value', 'textbox1'); form.appendChild(textbox1);

What is the difference?

The difference is when textbox1 is appended to the form.

Why is this important? Does it matter?

For all attributes other than 'type', the order doesn't seem to matter from browser to browser.

The 'type' attribute matters when you're dealing with certain browsers like Internet Explorer (IE) versions 5 through 8 (IE9 seems to work, except they don't preserve the "value" property's data when converting to the radio/checkbox controls.)

The issue lies in the timing of appending the textbox element to the form. In the older aforementioned versions of IE, according to "TYPE Attribute | type Property" on MSDN (in the Remarks section):

"As of Microsoft Internet Explorer 5, the type property is read/write-once, but only when an input element is created with the createElement method and before it is added to the document."

It is also important to note that Internet Explorer defaults to type="text" if you don't specify.

Normally the order of one appending an element to the document and setting attributes later wouldn't matter, but since the older versions of IE insist on not allowing this to happen after it's appended to the document or form, we must ensure we append the element AFTER we finish setting it up.

What happens if I append first in the older versions of Internet Explorer?

If you do as Figure 1 suggests, the browser will throw a JavaScript exception saying:

"This command is not supported"

Best practice? How should I handle this normally?

Set up all properties/attributes before you append the element to the document.

Simply put, complete all setup of the HTMLElement's properties/attributes you create via document.createElement() before you call HTMLElement.appendChild() to append it to the document. This should work consistent across all browsers.

Do I have to use setAttribute() to set the data on the element?

No. In fact, normally you'll use the direct properties for attributes the given HTML element already provides. For example, the following are identical:

textbox1.setAttribute('value', 'Some string'); textbox1.value = 'Some string';

The highlighted is the preferred best practice way to set that attribute. Both lines of code are the equal to having a hard-coded line of HTML that said:

<input type="text" value="Some string" />

Another Internet Explorer difference with IE9

You'll notice that when you click the "Change textboxes to different input types" button below after clicking "Create form" that IE9 does not preserve the original values set on the Input element when it was first created. Chrome, Firefox and Safari do.

If I don't have to use setAttribute, why are you telling me this anyway?

I was using the Silverlight HtmlElement.SetAttribute() method to access the DOM from a Silverlight application I was working on. The application kept returning an InvalidOperationException with an obscure "Common_MethodFailed" error message. I wanted to understand if the Silverlight was having issues in that browser, or if it was a problem with the JavaScript engine of the browser.

Incidentally, in Silverlight, one must use the SetAttribute method because the HtmlElement object is generic and doesn't contain all the properties that would match to the actual HTML attributes. Therefore, it was natural for me to assume that Silverlight would also call the JavaScript HtmlElement.setAttribute function when calling down into the DOM.

Further investigation narrowed it down to the line of code where I was calling SetAttribute with the "type" attribute. So I set out to make a plain XHTML/JavaScript page I could test without Silverlight in the browser, and was met with the "This command is not supported" JavaScript error.

I wanted to document it for those that might run into this issue in JavaScript and/or Silverlight. I hope it will help someone find answers to the confusion quickly.

I tried using: inputElement.type = 'checkbox' and it worked the same as calling inputElement.setAttribute('type', 'checkbox');

For the purposes of our experiment here, we'll stick with calling setAttribute.

The experiment

Try it for yourself below... click each button in order to see if your browser supports appending the elements before setting the "type" attribute.

  1. Click the "Create form" button (You'll either see the error, or two textboxes will appear below the buttons with values in them.)
    If you textboxes are there, they have an onclick handler set that will show an alert dialog showing the "value" property/attribute of the element.
  2. Click the "Change textboxes to different input types" button. (You'll see the error in old IE browsers or you'll see the textboxes change into a checkbox and radio button.
  3. Click the checkbox and radio button to again see the alert dialog showing the "value" property/attribute of the element.

It seems IE9 actually creates a new HTMLInputElement with the new type and carries over most properties (like the onclick handler) -- but not the original values. The other browsers carry over the original values. I'll leave you to experiment with the "why" on that one on your own. I've run out of time for now. Happy coding!