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:
IE+jQuery+Ajax+XHTML: HTML getting clipped after .html() or .innerHTML
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)
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).
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
Related
I am new in JavaScript and jQuery, and I have a problem when I use the mask money plugin. It worked well, but when I make some JavaScript to add another input in table, the new row doesn't work with the maskmoney even though it had the same class
Here's my table:
<thead>
<tr>
<td width="100"><center>Waqaf</center></td>
<td width="100"><center>Operasional Sekolah</center></td>
<td width="100"><center>Seragam</center></td>
</tr>
</thead>
<tbody>
<tr>
<td width="100"><input type="text" class="form-control price" name="waqaf" id=""></td>
<td width="100"><input type="text" class="form-control price" name="operasional_sekolah" id=""></td>
<td width="100"><input type="text" class="form-control price" name="seragam" id=""></td>
</tr>
</tbody>
The JS for adding new field was running well, when I've checked the inspect element outputing input with same class. And the problem is in the plugin JS mask money
<script type="text/javascript">
$('input.price').number( true, 2 );
</script>
(see picture below)
BUT when I manually make another text input it worked well
Why doesn't it work even though I make another field with js event with same input and class?
You should do $('input.price').number( true, 2 ); each time a new row is created, the method currently only applies to the first row.
If you mean this plugin, then it's important to know it uses $.bind to handle events. It means that new inputs won't be handled in any way by this plugin. Today we should use $.on for this kind of bindings (and '$.live' in early versions of jQuery).
So I have a html table which has a structure like :
<table>
<tbody>
<tr>
<input type="hidden" name="a" value="x">
<input type="hidden" name="b" value="y">
<td>First Cell</td>
<td>Some text</td>
<td>Some text</td>
<td>Last Cell</td>
</tr>
</tbody>
</table>
What i want is a generic way using CSS to always select the first and last occurring of each row as the number of hidden input element may differ with each instance.
PS: What I am trying to do is that in my application i want to remove the left-border from the first 's and right-border from the last 's from all the existing tables using a common css. The overall structure remains the same but the number of hidden input fields and cells may differ.
Any help would be appreciated. Thanks in advance!
You can separate multiple CSS selectors with a comma:
td:first-child, td:last-child { background: red; }
By the way, check your markup as it looks invalid (input element inside tr is not allowed).
You have keywords for that predefined in jquery
See reference :first and :last
To get first td
$("tr").find("td:first").html();
To get last td
$("tr").find("td:last").html();
this works and its easy
NOTE : dont put html content directly into a tr always use td to do so.
ex :
<tr>
<td> <input type="hidden" name="a" value="x"> </td>
<td> <input type="hidden" name="b" value="y"> </td>
</tr>
I have a table with add more button which adds a certain number of rows with inputs in it. But the HTML string for these rows have grown large enough and its becoming a pain.
So, what I am thinking is to have a div hidden tag with the required HTML that is repeated again and again on clicking the add more button.
So, how to push the div tag innerHTML inside a TR. Below is the code that I need to push, so I kept it inside the hidden DIV tag.
<tr>
<td><label for="bucket_size"><b>1.</b> Bucket Size:</label></td>
<td><input type="text" name="bucket_size[]" id="bucket_size"></td>
<td><label for="control_bucket_size">Control Bucket Size: </label></td>
<td><input type="text" name="control_bucket_size[]" id="control_bucket_size" value="0"></td>
</tr>
<tr>
<td><label for="from_date">Active From: </label></td>
<td><input type="text" name="from_date[]" id="from_date" class="hasDatePicker"></td>
<td><label for="to_date">To: </label></td>
<td><input type="text" name="to_date[]" id="to_date" class="hasDatePicker"></td>
</tr>
<tr>
<td><label for="location">Location: </label></td>
<td class="locationSelect">
</td>
<td style="text-align:center;" colspan="2"></td>
</tr>
It doesn't get inserted properly if I directly insert after the particular TR, the innerHTML of the div tag. How to do it?
You can't have a TR as a child of a DIV, even if the DIV is hidden (it's invalid markup). You can't modify a table by changing its innerHTML in IE < 9 (though you can write an entire table or change the contents of a cell). Use DOM methods.
Likely the best method is to clone a row, then update name and id properties, plus anything else that needs it, and append it to the TBODY. If you append to the TABLE, most browsers are OK but IE will barf, so append to the TBODY.
Extremely simple example:
<table>
<tr onclick="this.parentNode.appendChild(this.cloneNode(true))">
<td>Here is a cell in a row
<td>Here is a cell in a row
</table>
If you're trying to clone a table row then use another table row, not a div. And don't use innerHTML, use cloneNode
<table>
<tr id="clone_me" style="display:none">
<td>...</td>
</tr>
</table>
<script>
var original_node = document.getElementById('clone_me');
var clone_node = original_node.cloneNode(true);
clone_node.removeAttribute('id'); // Prevent duplicate ID
try {
clone_node.style.display = 'table-row';
}
catch(iesucks) {
clone_node.style.display = 'block'; // Should be 'table-row' but need this hack for IE 6-7
}
original_node.parentNode.appendChild(clone_node); // Add new node to end of table
</script>
If you find older IE's struggle with display:table-row then try toggling visibility instead.
Okay, so I am dealing with a CMS system here which generated wonderful (not) code. I cannot change the way the code/content is generated, but I can add my own JavaScript / jQuery code to rewrite the generated content. I am looking at a form which looks like this ...
<table>
<tr>
<td>
First Name<br><input id="first_name_field" name="first_name" value="" type="text">
</td>
</tr>
<tr>
<td>
State/Province/Region<br><div id="regstatediv_187"><select name="state" id="state_field" class="inputbox"><option value=" ">Select State/Province/Region</option><option value="ALA">Alabama</option>...</select></div>
</td>
</tr>
</table>
I have been playing with the html() and text() functions in jQuery and thus far cannot find a way to select only the text "label" and then wrap it and write it back without destroying the form field in the process. Any suggestions?
Thanks!
Try this
$('table td').contents().filter(function() {
return this.nodeType == 3;
}).wrap('<span class="label" />');//use any markup you want to wrap with
Demo
I have the following HTML:
<table>
<tr class="row">
<td class="field">
<input type="text" />
</td>
<td class="field">
<input type="text" />
</td>
<td class="field">
<input type="text" />
</td>
</tr>
<tr>
...
...
</tr>
</table>
I want to be able to hide the <tr> with the class="row" but only when the input within the <td> with the class="field" is empty when the page loads.
I've tried this, but it doesn't work:
$('td.field:text[value=""]').parents('tr.row').hide();
However, for some reason, this DOES work:
$('td.field).parents('tr.row').hide();
(ie: it hides all of the rows with class="row")
Also, the following DOES work:
$('td.field:text[value=""]').val('test');
(ie: all empty inputs are populated with 'test' on page load)
I'm new to JQuery so I'm suspecting that I may have just misunderstood the way chaining works. can anyone give me any pointers? It semms like the two parts of what I am trying to do are correct when attempted separately, but don't work together as one.
I think it should be in this way:
$('td.field :text[value=""]').parents('tr.row').hide();
The reason: :text (input) is child from td.field. If you put td.field:text it's wrong because they are diferente selectors.
and why dont you go the oposite way - select the INPUT with empty value, and than go to its
parents().parents().hide()
first parents to get TD, the second one to get TR