Question

innerHTML and jqueries .html() ... GOTCHA!

I had just created a little template html tag for my javascript to go get a copy of and push into a table... It looked like this:

<div id="TimesheetEntryRow">
            <tr id="row{RowID}">
               <td></td>
            </tr>
</div >

So in jquery I thought, cool let's grab that:

timesheetTemplateHtml = $( "#TimesheetEntryRow" ).html();

and then I appended it to my awesome table:

$( "#TimesheetTable" ).append( timesheetTemplateHtml );

It didn't work?

It had stripped off the <tr> and the <td>s and left true tags like the <input />s I had inside it.

So I thought, oh jquery you naughty little critter, I'll use innerHTML so that I do not have to worry about jquery being clever:

timesheetTemplateHtml = document.getElementById( "TimesheetEntryRow" ).innerHTML;
document.getElementById( "TimesheetTable" ).innerHTML += timesheetTemplateHtml;

Still not working? Still it stripped off all the tags for my template...

I binged the hell out of it and stumbled across these two articles:

FIREFOX: https://developer.mozilla.org/en-US/docs/Web/API/element.innerHTML?redirectlocale=en-US&redirectslug=DOM%2Felement.innerHTML

IE: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx

GREAT, so that function I've used my entire life has been a LIE I tell you. In fact, the only browser it does work in is Chrome ( I think they are ignoring the standards or something? ).

I managed to figure out that if you put the entire tag around the it, seems to copy it okay... Which is very annoying but has saved my bacon on this occasion.

<div id="TimesheetEntryRow">
            <table>
                <tr id="row{RowID}">
                   <td></td>
                </tr>
            </table>
</div>

Now the above makes sense, but I really did not know innerHTML also does html parsing to check you're not being silly... Can any of you think of another way of not having to put an entire tag set in my templater?

Crazy crazy crazy!

Related posts:


My full example template is this:

<div id="TimesheetEntryRow" style="display:none;">
    <table>
        <tbody>
            <tr id="row{RowID}">
                <td>blah</td>
                <td class="timeSpent"><input name="timeMon[]" type="text" class="form-control inputTimeSpent timeSpent timeMon" placeholder="0" /></td>
                <td class="timeSpent"><input name="timeTue[]" type="text" class="form-control inputTimeSpent timeSpent timeTue" placeholder="0" /></td>
                <td class="timeSpent"><input name="timeWed[]" type="text" class="form-control inputTimeSpent timeSpent timeWed" placeholder="0" /></td>
                <td class="timeSpent"><input name="timeThur[]" type="text" class="form-control inputTimeSpent timeSpent timeThur" placeholder="0" /></td>
                <td class="timeSpent"><input name="timeFri[]" type="text" class="form-control inputTimeSpent timeSpent timeFri" placeholder="0" /></td>
                <td class="timeSpent timeSpentWeekend"><input name="timeSat[]" type="text" class="form-control inputTimeSpent timeSpent timeSat" placeholder="0" /></td>
                <td class="timeSpent timeSpentWeekend"><input name="timeSun[]" type="text" class="form-control inputTimeSpent timeSpent timeSun" placeholder="0" /></td>
                <td class="timeSpent"><input disabled type="text" class="form-control timeSpent allocated" /></td>
                <td class="timeSpent"><input disabled type="text" class="form-control timeSpent total" value="0" /></td>
                <td><textarea name="note[]" class="form-control inputNotes" placeholder="Enter notes"></textarea></td>
            </tr>
        </tbody>
    </table>
</div>

NOTE TO EVERYONE : If you use clone, do not forget to display:block on the css style.

Anyways, even with clone, the above example will not do what you expect (if you think it does, actually go inspect the element and it would have stripped the whole load out)

Was it helpful?

Solution

The problem that you're experiencing is due to the fact that the template isn't valid HTML. <tr> elements must be inside of a <table>, <tbody>, <thead>, <tfoot>, and maybe something else I'm forgetting. When the browser sees the <tr> elements in an invalid place, it just deletes them and moves on, leaving the content where it is. (Same for the <td>s not in a <tr>s.) Therefore, what you can do is to make your template element a <table>:

<table id="TimesheetEntryRow" style="display:none">
    <tr>
        <td>blah</td>
    </tr>
</table>

See a working example here: http://jsfiddle.net/6GSJ4/2/

I know that some frameworks such as AngularJS (one I work with) allow you to put your templates inside of <script type="text/template"> elements since those are not processed as DOM elements by the HTML parser so all of your elements will stay intact. That may be an option if you need it (though .innerHTML obviously wouldn't work).

OTHER TIPS

You could of course just add the html back to the template tag right away. Not optimal, but will get the job done

timesheetTemplateHtml = $("#TimesheetEntryRow").html();

$("#TimesheetEntryRow").html(timesheetTemplateHtml);

I would do it like this. Simply use a table for your template without displaying it:

<table id="TimesheetEntryRow" style="display: none;">
  <tr>
    <td>aaa</td>
  </tr>
</table>

and than just select the template and the destination once on document ready. When needed, clone the template and append it to the destination:

$(function(){

  var $table = $( "#TimesheetTable" );
  var $row = $( "#TimesheetEntryRow tr" );

  $('#button').on('click', function(){
    $table.append($row.clone());
  });

});

See a working example here: http://codepen.io/timbuethe/pen/czJla/

You can "misuse" the script tag like this:

<script type="text/template" id="TimesheetEntryRow">
    <tr id="row{RowID}">
        <td></td>
    </tr>
</script>

Some JavaScript templating scripts use this, e.g. Underscore.js

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top