I have a report that has some headers on the top of the table(columns) but also some headers on the left of the table (rows). Those headers are variable, never fixed. The whole entire table is built through DOM Scripting based on an Ajax response that returns me the top headers, the left headers, and the qty at a particular intersection.
I already have an algorithm that knows how populate the cells in that table based on the column header and the row header.
In Firefox, Chrome, and Safari the following works:
document.getElementById("myTable").rows[row].cells[column].firstChild.nodeValue = item.qty.toString();
The problem is in IE7 (what the client uses). IE 7 does not let me access a particular cell by using the [index] notation.Basically, its blowing up at ".cells[column]" . Do you guys know the equivalent of the statement above in IE7?
Also do you know of a jQuery way to fill a known cell once I have the row and the column coordinates?
Thanks,
-Dario
jQuery("#myTable tbody tr:eq(" + row + ") td:eq(" + column + ")").html("foo");
jQuery selector #id
jQuery selector element
jQuery selector eq()
jQuery html()
row and column will start from 0. Use the above codes.
Non-jquery way:
document.getElementById("myTable").getElementsByTagName('tbody')[0].getElementsByTagName('tr')[row].getElementsByTagName('td')[column].innerHTML = item.qty.toString();
$("#myTable tr:eq(" + row + ") td:eq(" + column + ")").html(item.qty.toString());
However you should be aware of nested tables. Especially if you have another table inside the table with the myTable id. If so let me know, i might rewrite the line for you.
Also you should be aware that I was using jQuery here. To add jQuery to your page you should add the following to the page, preferably in the <head> element:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
This if you want to make use of the jQuery file hosted by google, but of course you can download it and host it yourself if you wish so.
Try this:
$("#myTable tr:eq(" + row + ") td:eq(" + columnh + ")").html(item.qty.toString());
Related
DataTables allows you to create "complex headers" (which entails spanning multiple columns or rows). The Responsive plugin is compatible with this if you add some extra CSS as per the documentation.
Here is a working fiddle: https://jsfiddle.net/hmr9qtx3/1/
As you can see, resizing the rendered output frame correctly removes the <th> tags from the row. This is with versions 1.10.1 of DataTables and 1.0.0 of Responsive.
The most current DataTables build is 1.10.12, and the version of Responsive it comes packaged with is 2.1.0. Here is an identical fiddle with those versions swapped out: https://jsfiddle.net/hmr9qtx3/
Between the working and non-working version numbers, usage of datatables and the responsive plugin is identical.
You will notice that the responsive plugin functions correctly for the non-spanning table headers and the body of the table. However, the spanning headers are not removed from the DOM when the page is resized enough that they would add a scrollbar/overflow.
How can I fix or patch my code so the spanning headers are responsive like in the working fiddle? I'd prefer to not use older versions of the plugins.
Complex headers are not supported with Responsive plug-in 2.0, see this thread or this issue #59.
As a workaround you can continue using Responsive plugin 1.0 with the most recent version of jQuery DataTables.
Per author's post:
Unfortunately yes, this is a limitation in Responsive 2.0. (...) The plan is to resolve it for 2.1. (...) The only option at the moment is to roll back to Responsive 1.x I'm afraid.
Although you're using v2.1.0, maybe it wasn't yet added because issue #59 on GitHub remains open.
I created a hot fix on the fly for this issue for the responsive plugin.
Issue: (last column disappears)
DataTables 1.10.13 hot-fix → datatables.responsive v2.1.1
Adds responsive support to datatables.net Complex Headers
This hot-fix works perfectly well on my page where I have different types of datatables,
but nevertheless, be careful with this patch as it is not tested with all possible dt features/types.
Here is a working demo: jsBin-Demo
_setColumnVis: function (col, showHide) {
var dt = this.s.dt;
var display = showHide ? '' : 'none'; // empty string will remove the attr
$(dt.column(col).header()).css('display', display);
$(dt.column(col).footer()).css('display', display);
dt.column(col).nodes().to$().css('display', display);
var parentrow = $(dt.column(col).header()).parent().prev("tr");
var visibleSiblingCount = $(dt.column(col).header()).siblings("th").filter(function (idx, el) {
return $(el).is(":visible");
}).length;
if (parentrow.length > 0 && visibleSiblingCount != 1) {
if (parentrow.find("th:nth-child(" + col + ")").attr("rowspan") == 1) {
parentrow.find("th:nth-child(" + col + ")").css('display', display);
} else {
parentrow.find("th:nth-child(" + (col + 1) + ")").css('display', display);
}
}
},
A clean solution which works well is to add a duplicate, empty row of zero-height columns before the complex header row, followed by the actual row of columns.
<thead>
<tr><th></th><th></th><th></th></tr>
<tr><th colspan="2">Complex!</th><th>yeah</th></tr>
<tr><th>One</th><th>Two</th><th>Three</th></tr>
</thead>
This is because FixedHeader targets the first row it finds in thead for sizing. If you size the dummy row correctly, all the others will follow.
I prefer this solution before there is an official fix because it doesn't require us to maintain a patched version of FixedHeader, and when an official fix is released would degrade gracefully and be removable at our leisure.
This function counts the number of visible columns. Then loops through the headers to make them match. I hope this helps as a patch for someone until Responsive is updated. You will have to put this inside of a document load and window resize function.
function makeColumnsResponsive() {
const visibleColumnCount = $('tbody tr:first-child td:visible').length - 1;
$('thead tr th').show();
for (let i = 1; i <= $('thead tr').length; i++) {
$('thead tr:nth-child(' + i + ') th:gt(' + visibleColumnCount + ')').hide();
}
}
I hope to get some advise about how to write the javascript and jQuery code more beautiful and gain more readability.
In this case, I hope to insert table inside a list element. Both list and table are added dynamic by using script.
I have some code like this:
$('#Items').append("<ul></ul>");
var car_index;
var photo_index;
var lot_index;
for (car_index = 0; car_index < cars.length; car_index++)
{
lot_index = car_index + 1;
//From here, I thought the code is really ugly...though it works.
//I can't image that I will need to adde 3 rows with 6 cols into the table by using this way
//Also each col may has their own style need to be assigned....
//Any advise??
$('#Items ul').append("<li id='r_" + car_index +"'></li>");
$('#r_' + car_index).append("<table cellspacing='2' cellpadding='0'><tr><td width='50' align='left' style='font-size:10pt; font-weight:bold'>Lot " + lot_index +"</td></tr></table>");
}
As I write in the comments of above code. I could use append method and put a lot of HTML code in there. However it really looks ugly... and in the above example, I just added one row in the list. In the final goal, I have to add three rows, with about 6 cells. Each cell will have their own style set for the content. It will really be a mess.
Any advice will be appreciate! Thank you!
Perhaps use templating via either Mustache or jQuery.
See more: What Javascript Template Engines you recommend?
try this, coz
$('#Items ul').append("<li id='r_" + car_index +"'></li>); is not enclosed between " "
$('#Items ul').append("<li id='r_"+car_index+"'></li>");
$('#r_' + car_index).append("<table cellspacing='2' cellpadding='0'><tr><td width='50' align='left' style='font-size:10pt; font-weight:bold'>Lot " + lot_index +"</td></tr></table>");
}
Alright...After some thought, I find a way which will be more clear to write this kind of code. I'm not sure if this is the goog choice since it will require more work...but I feel it is better to write this way.
The idea is really simple, create object to store the HTML tags which will fixed for every block. As my example, it is a table will repeated every time a list will be added. So why not store all fixed table tags and their style attribute into one array like object?
var unit =
{
table_header : "<table border = '1'>",
row_1_col_1 : "<tr><td>Lot ",
row_1_col_2 : "</td><td><a class='addto' href='#'>Add to like</a>",
row_2_col_1 : "</td></tr><tr><td>",
row_2_col_2 : "</td><td><img src='",
row_3 : "'></td></tr><tr><td>",
table_end : "</td></tr></table><hr />"
};
Make this variable global, than when you need to add table, the original code:
$('#r_' + car_index).append("<table cellspacing='2' cellpadding='0'><tr><td width='50' align='left' style='font-size:10pt; font-weight:bold'>Lot " + lot_index +"</td></tr></table>");
Will become like this:
$('#r_' + car_index).append(unit['table_header'] +
unit['row_1_col_1'] + "Content in cell 1" +
unit['row_1_col_2'] + "Content in cell 2" +
unit['row_2_col_1'] + "Content in cell 3" +
unit['row_2_col_2'] + "Content in cell 4" +
unit['row_3'] + unit['table_end']);
Just be careful about double quote sign and single quote sign, and also, the array's index need to be quoted(see javascript array's use for detail if you got problem).
I think the advantage of this method is much more easy to modify the table. Add row, change content, or change style make much more easy since it use the single object.
I also not sure if this is a good way or not, hope to hear more about your thought! Thank you!
IE is giving me an error (Error: Invalid target element for this operation.) when trying to execute this code:
var d1 = document.getElementById( name + '-body');
d1.insertAdjacentHTML('beforeend', html );
Without having to put the entire function in here, the point of it is to add some text inputs dynamically when a user clicks a button. I did a bit of searching and found many statements that insertAdjacentHTML doesn't work right within tables, which is what I need it to do.
Is there a workaround for this?
Edit: Here is the html I am trying to insert. If you want I can post the generated html from Chrome also.
"<tr id=\"node-" + counter + "\">
<td>
<textarea onclick=\"Common.removeInstructions(id)\" name=\"on\" id=\"action-" + counter + "\" wrap=\"soft\" cols=\"35\" rows=\"4\" style=\"resize: none; overflow: hidden;\">
Please limit responses to 150 characters. Blank fields will be ignored.
</textarea>
</td>
<td>
<input classname=\"TextInput\" id=\"actionDate-" + counter + "\" newline=\"1\" style=\"width: 100px;\" class=\"TextInput\" assemblers=\"jaba.ui.input.TextInput\" jaba-pagerowindex=\"1\"/>
</td>
</tr>"
IE often doesn't allow you to dynamically add table rows/cells.
Pre-creating the rows/cells which you want added with display:none, then changing their innerHTML and display when needed is an useful workaround for that.
Adding Fabrício Matté as an answer so I can accept it.
If you'd show us the generated HTML and what you're trying to do, it'd be much easier to reply. Anyway, I've had a problem inserting rows/cells in a table on IE before, my solution was pre-creating the rows/cells with display:none when the table is created, then changing the 's innerHTML together with their display.
I want to update the contents of a TBODY (not the entire TABLE, because there's much more semi-meta data (LOL) in that). I get >= 0 TR's from the server (XHR) and I want to plump those in the existing table. The fresh TR's must overwrite the existing TBODY contents.
I've made a very simple, static example on jsFiddle that works in Chrome and probably all the rest, except for IE (I only use Chrome and test in IE8).
In Chrome, the very first attempt works: plump the TR's in the TBODY. No problem!
In IE it doesn't... I've included a not working example of what I had in mind to get it working.
I'm sure this problem isn't new: how would I insert a string with TR's in an existing TBODY?
PS. jQuery doesn't have a problem with this!? It's used here on SO. jQuery does something to the HTML and then inserts it as HTML nodes..? Or something? I can't read that crazy lib. It happens in this file (look for "html: function(". That's where the magic starts.
Anybody have a function or idea for this to work without JS library?
Here is a good resource about the problems of innerHTML and IE.
The bottom line is that on tbody the innerHTML property is readonly.
Here is a solution presented in one of the comments:
var innerHTML = "<tr><td>Hello world!</td></tr>";
var div = document.createElement("DIV");
div.innerHTML = "<table>" + innerHTML + "</table>";
// Get the tr from the table in the div
var trElem = div.getElementsByTagName("TR")[0];
Regarding the jQuery part of the question:
//inside the html() function:
// If using innerHTML throws an exception, use the fallback method
} catch(e) {
this.empty().append( value );
}
//inside the empty() function (basically removes all child nodes of the td):
while ( elem.firstChild ) {
elem.removeChild( elem.firstChild );
}
//append calls domManip applying this to all table rows:
if ( this.nodeType === 1 ) {
this.appendChild( elem );
}
//domManip as far as I can tell creates a fragment if possible and calls the three lines above with this=each row in turn, elem=the tbody(created if missing)
Using plain JavaScript, you can set the innerHTML property of the relevant element. The text that you set can contain a mix of HTML and text. It will be parsed and added to the DOM.
When I use $('#mygrid').jqGrid('GridUnload'); my grid is destroyed: no pager/ no header.
In a wiki I found:
The only difference to previous method is that the grid is destroyed, but the
table element and pager (if any) are left ready to be used again.
I can't find any difference between GridUnload/ GridDestroy or do I something wrong?
I use jqGrid 3.8.
To be able to create jqGrid on the page you have to insert an empty <table> element on the place of the page where you want see the grid. The simplest example of the table element is <table id="mygrid"></table>.
The empty <table> element itself will be not seen on the page till you call $('#mygrid').jqGrid({...}) and the grid elements like column headers will be created.
The method GridDestroy works like jQuery.remove. It deletes all elements which belong to the grid inclusve the <table> element.
The method GridUnload on the other hand delete all, but the empty <table> element stay on the page. So you are able to create new grid on the same place. The method GridUnload is very usefull if you need create on one place different grids depend on different conditions. Look at the old answer with the demo. The demo shows how two different grids can by dynamically created on the same place. If you would be just replace GridUnload in the code to GridDestroy the demo will be not work: after destroying of the first grid no other grids will be created on the same place.
In addition to Oleg's answer I would like to point out that GridUnload does a little more that just remove the grid from the table. It removes the original HTML table element(and the pager), and ads an identical one in its place(at least in 4.5.4 it does).
This means that if you attached some event handlers to the table HTML element(i.e with jquery on, like ('#gridID').on('event','selector',handler)) they will also be removed. Consiquently the events will not fire on the new grid if you replace the old grid with a new one...
Oleg's answer works fine for me as long as I have no Group headers.
When I add group header row with 'setGroupHeaders'
the results of a 'GridUnload' followed by a $('#mygrid').jqGrid({...}) are not consistent.
It works fine in Chrome but not in IE11.
In IE11, each 'jqg-third-row-header' item ends up rendered on different rows (diagonally).
I am using free-jqGrid:query.jqgrid.src.js version 4.13.4 for debugging.
I traced the problem down to code, in this file, that begins with line 9936:
if (o.useColSpanStyle) {
// Increase the height of resizing span of visible headers
$htable.find("span.ui-jqgrid-resize").each(function () {
var $parent = $(this).parent();
if ($parent.is(":visible")) {
this.style.cssText = "height:" + $parent.height() + "px !important; cursor:col-resize;";
//this.style.cssText = "height:" + $parent.css('line-height'); + "px !important;cursor:col-resize;";
}
});
// Set position of the sortable div (the main lable)
// with the column header text to the middle of the cell.
// One should not do this for hidden headers.
$htable.find(".ui-th-column>div").each(function () {
var $ts = $(this), $parent = $ts.parent();
if ($parent.is(":visible") && $parent.is(":has(span.ui-jqgrid-resize)") && !($ts.hasClass("ui-jqgrid-rotate") || $ts.hasClass("ui-jqgrid-rotateOldIE"))) {
// !!! it seems be wrong now
$ts.css("top", ($parent.height() - $ts.outerHeight(true)) / 2 + "px");
// $ts.css("top", ($parent.css('line-height') - $ts.css('line-height')) / 2 + "px");
}
});
}
$(ts).triggerHandler("jqGridAfterSetGroupHeaders");
});
This code sets the height and top css values related to each 'jqg-third-row-header' item. This leads to a tall and diagonal layout of the 'jqg-third-row-header'
Potential Bug:.
The $parent.height() and $ts.height() methods, above, return the former jqGrid table height in IE11. In Chrome they return the 'th' computed height(top = 0).
I added and tested the 2 commented lines that use line-height.
IE11 works fine when line-height is used.
I do not completely understand the JqGrid resize logic, so this may not be a fix.
Alternate Solution:
If you specify.
colModel:
{
label: 'D',
name: 'W',
width: 6,
align: 'center',
resizable:false //required for IE11 multiple calls to this init()
},
When resizable is false the code above is not encountered and the height and top are not set.
Oleg's jqGrid is a very nice control. Perhaps he can test his demo grid with a groupheader on IE11.