21

I'm really suprised I haven't run into this problem before, but it seems that calling jQueries .html() function on an element ignores changes in the DOM, i.e it returns the HTML in the original source. IE doesn't do this. jQueries .html() just uses the innerHTML property internally.

Is this meant to happen? I'm on Firefox 3.5.2. I have a sample below, where no matter what you change the textbox value to, the innerHTML of the "container" element only ever returns the value defined in the HTML markup. The sample isn't using jQuery just to make it simpler (the result is the same using jQuery).

Does anyone have a work around where I can get the html of a container in its current state, i.e. including any scripted changes to the DOM?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <script type="text/javascript">
            <!--
            function BodyLoad(){                
                document.getElementById("textbox").value = "initial UPDATE";
                DisplayTextBoxValue();
            }

            function DisplayTextBoxValue(){
                alert(document.getElementById("container").innerHTML);             
                return false;
            }
            //-->
        </script>
    </head>
    <body onload="BodyLoad();">
        <div id="container">
            <input type="text" id="textbox" value="initial" />
        </div>
        <input type="button" id="button" value="Test me" onclick="return DisplayTextBoxValue();" />
    </body>
</html>
JonoW
  • 14,029
  • 3
  • 33
  • 31

6 Answers6

37

Firefox doesn't update the value attribute of a DOM object based on user input, just its value property - pretty quick work around exists.

DOM:

function DisplayTextBoxValue(){
  var element = document.getElementById('textbox');
  // set the attribute on the DOM Element by hand - will update the innerHTML
  element.setAttribute('value', element.value);
  alert(document.getElementById("container").innerHTML);             
  return false;
}

jQuery plugin that makes .formhtml() automatically do this:

(function($) {
  var oldHTML = $.fn.html;

  $.fn.formhtml = function() {
    if (arguments.length) return oldHTML.apply(this,arguments);
    $("input,button", this).each(function() {
      this.setAttribute('value',this.value);
    });
    $("textarea", this).each(function() {
      // updated - thanks Raja & Dr. Fred!
      $(this).text(this.value);
    });
    $("input:radio,input:checkbox", this).each(function() {
      // im not really even sure you need to do this for "checked"
      // but what the heck, better safe than sorry
      if (this.checked) this.setAttribute('checked', 'checked');
      else this.removeAttribute('checked');
    });
    $("option", this).each(function() {
      // also not sure, but, better safe...
      if (this.selected) this.setAttribute('selected', 'selected');
      else this.removeAttribute('selected');
    });
    return oldHTML.apply(this);
  };

  //optional to override real .html() if you want
  // $.fn.html = $.fn.formhtml;
})(jQuery);
gnarf
  • 105,192
  • 25
  • 127
  • 161
  • your plugin works fine for all controls but it does not work for Textarea alone in FF :-(....Did you change anything to make it work? Have already added 1 since this helped me a lot :-) – Raja Feb 28 '11 at 16:58
  • This works great, but I needed to use @Dr Fred's adjustment below. Setting the textarea's innerHTML to it's value loses line feeds and any other extra whitespace. – mothmonsterman Nov 19 '12 at 20:41
  • Updated with @Dr Fred's change, makes sense. – gnarf Nov 20 '12 at 18:40
6

This is a known "issue" in Firefox. The specifications for innerHTML are not entirely clear, so different browser vendors implement it in a different way.

A discussion about this topic can be found here:

http://forums.mozillazine.org/viewtopic.php?t=317838#1744233

Philippe Leybaert
  • 168,566
  • 31
  • 210
  • 223
2

Thanks for your formhtml plugin. In order to use it with textarea, I had to update it :

$("textarea", this).each(function() { 
  $(this).text($(this).val()); 
});
Don
  • 863
  • 1
  • 8
  • 22
Dr Fred
  • 939
  • 8
  • 15
  • I used @gnarf's answer with this adjustment to retain all whitespace in textarea (or close enough... $this.text(this.value)) – mothmonsterman Nov 19 '12 at 20:42
  • Thanks, Wish you would have suggested an edit here! I changed my answer to incorporate this. – gnarf Nov 20 '12 at 18:41
1

I know your question relates to innerHTML, but if it were just the value of textbox inside container that you needed, then

$('#textbox').val()

will give the correct (updated) textbox value.

Russ Cam
  • 124,184
  • 33
  • 204
  • 266
0

This update function was working only on input fields not changed by hand. Added the indicated line to update the visible input text:

  // set text input value from the associated sel dropdown and reset dropdown
  function set_input_value(eid, sel) {
      var el = document.getElementById(eid);
      el.setAttribute("value", sel.options[sel.selectedIndex].text);

      // added this line to solve the issue:
      el.value = el.getAttribute('value');

      sel.selectedIndex=0;
  }
0

Also another DOM Approach is to set the defaultValue on the specific element - borrowing the same code from the voted answer.

function DisplayTextBoxValue(){
  var element = document.getElementById('textbox');
  element.defaultValue = element.value;    
  alert(document.getElementById("container").innerHTML);             
  return false;
}

That should print the updated innerHTML.

jQuery's solution is better as it attaches to all the input elements instead of a specific element. This can be done using "DOM only" too, will involve iterating the DOM to detect all the input elements and adding the onChange method calls on all the input elements. In case you don't know the fields that'd be on hte page.

Swaroop
  • 908
  • 1
  • 12
  • 25