I have a problem: handsontable scroll is jumping when row height is non-standard.
My code is:
$(document).ready(function () {
function createBigData() {
var rows = []
, i
, j;
for (i = 0; i < 10; i++) {
var row = [];
for (j = 0; j < 7; j++) {
row.push(Handsontable.helper.spreadsheetColumnLabel(j) + i + "\n2nd_row");
}
rows.push(row);
}
return rows;
}
$('#example1').handsontable({
data: createBigData(),
});
});
jsfiddle: http://jsfiddle.net/LR4Ne/
Try to scroll to the bottom of the table. Do you see it jumping back and forth?
I've noticed that old version of handsontable js didn't work that way, try to change
<script src="http://handsontable.com/dist/jquery.handsontable.full.js"></script>
to
<script src="http://old.handsontable.com/dist/jquery.handsontable.full.js"></script>
It works as it should now.
Please advise.
Thanks in advance!
--
Dmitry
I'm entirely sure what the issue with the new handsontable version is, but the problem is occuring because of the \n newline your entering into each cell. Handsontable has a method for entering markup into cells, which I've used in this fiddle, however the problem still exits. If you remove the \n and add more rows, it works fine. (Side note: I'm using a <br> here, because I think symantically, that makes more sense, but it doesn't matter which you use.) You will notice in this example, you can scroll, but once you get to the bottom, it starts getting jumpy again. Which led me to:
To fix the issue you can define the minimum height for the .wtHider class used by the plugin. Here is a working fiddle which shows how to fix the issue.
The main problem here is that when you scroll, handsontable is actually re-rendering the table, with the newly viewable rows. Upon re-render, handsontable is dynamically setting the height of the .wtHider and .wtHolder, which is what is causing the issue.
This is a "hacky" solution, but it should probably work for your needs. Hope this helps.
Per request, here's another fiddle with fixes the space issue at the bottom of the table: http://jsfiddle.net/8awo0gzk/1/
Related
I'm using the Tabulator data tree. I would like to change the row padding only for level 0. Is that possible?
possibly, I havent tested this but if you use a rowFormatter and use getElement() on it, you might be able to change the padding that survives anything Tabulator does behind the scenes. When I do an inspect of one of my rows, I see it sets padding-left:0px , so at least you know that Tabulator uses that, and if you change it, it might get overwritten.
rowFormatter was the key. Thank you!
rowFormatter:function(row){
if(row._row.modules.dataTree.index == 0){ //level 0
var cells = row.getCells();
cells.forEach((cell) => {
cell.getElement().style.paddingTop = "24px";
});
}
},
I'm using JQuery to filter a table (calling tr.hide() on non-matching rows). The table resides within a scrollable div. The problem: unfortunately, on filtering the list, the user loses his/her scroll position every time.
Is there a clean way to
obtain the top row of the current view port before scrolling
scroll to the very same row if it is still visible after filtering
or, if the row is no longer visible, scroll to the closest neighbor row (above or below), which is still visible
just add an anchor in the row you want to keep and go to this anchor after you filtered
Although it say's experimental, there is the element.scrollIntoView. It does seem to be supported by most major browsers. And you could always polyfill for those that don't.
https://developer.mozilla.org/en/docs/Web/API/Element/scrollIntoView#Browser_compatibility
It would look something like this. I don't use jQuery enough to use it in my example, so I will leave that is an exercise for the reader.
var rowToScrollTo = null;
for (var i = 0; i < rows.length; i++)
{
// Find the first visible row.
if (rows[i].offsetTop > scrollableDiv.scrollTop && shouldBeVisible(rows[i]))
{
rowToScrollTo = rows[i];
break;
}
}
// Show/hide rows
scrollableDiv.scrollTop = rowToScrollTo.offsetTop;
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 have, for example, 3 rows from a table. Each of the rows gets its content from a database. By default when the row is collapsed, the text should be shortened -
trs[i].innerText = trs[i].innerText.substring(0,25) + '...';
When a user clicks on the div it expands, and if clicked again - collapses.
if(tr.style.height == "150px")
{
tr.style.height = "20px";
}
else {
tr.style.height = "150px";
}
So far, so good, but I want the text to be shortened only if the div is collapsed. With my solution when the page loads the text is shortened, but when the row is expanded it remains shortened. How can I fix this? I can only think of when the row expands to call an AJAX function which returns the original data, but I don't think it's the best possible way. Thanks in advance.
First you'd have to store the full text before shortening it.
trs[i].fullText = trs[i].innerText;
trs[i].innerText = trs[i].innerText.substring(0,25) + '...';
Then you can restore it in the handler:
tr.innerText = tr.fullText;
tr.style.height = "150px";
Here's a jsFiddle. I'm using jQuery to select the elements, but you already have the correct tr's anyway. If you were using jQuery you could also use $(tr).data("fullText", $(tr).text()) which avoids some minor memory leaks with adding properties to DOM elements in old versions of Internet Explorer.
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.