jQuery + TableSorter: Error when table is empty - javascript

jQuery's plugin TableSorter doesn't seem to handle a situation where it is attached to an empty table. Is there a neat way around this?
In my application the user can filter and search the data and eventually he or she will come up with a search criteria which doesn't return any values. In these situations it would be nice to "detach" the TableSorter or somehow fix it's code so that it works with an empty table.
I'm currently using the plugin like this:
$("#transactionsTable")
.tablesorter({ widthFixed: true, widgets: ['zebra'] })
.tablesorterPager({ container: $("#pager"), positionFixed: false });
This works well, until the table is empty. Then I get the following error:
Line: 3
Error: '0.length' is null or not an object
Any ideas? Is it possible to change the script so that the tablesorter is only added to the table if it has rows?

I think you can do it for your self.
if ($("#transactionsTable").find("tr").size() > 1)
{
//> 1 for the case your table got a headline row
$("#transactionsTable")
.tablesorter({ widthFixed: true, widgets: ['zebra'] })
.tablesorterPager({ container: $("#pager"), positionFixed: false });
}
If your table got a tbody tag it is easier:
if ($("#transactionsTable").find("tbody").find("tr").size() > 0)
This way is maybe not the most professional one, but it should work under this circumstatances.

The issue is related to the fact that several parts of the codebase use rows[0] to determine 1) total number of columns, 2) the parser type to use per column (eg "text" vs "digit").
Until this bug gets fixed, here is an easy workaround:
Create a fake row in each table with contents like ("fake", 123, 123, 123, "fake"). Note how my fake contents match the "type" of the column to avoid confusing the column type detector. <tr class="fake_row"><td>fake</td><td>123</td></tr>
Add CSS styling to make the fake row not render:
tr.fake_row {
display: none;
}
This seems to work effectively, allowing tablesorter to initialize and run error-free and has no impact on the rendered output.

A more generic approach would be to override the tablesorter plugin itself to check for empty tables (until they fix the issue). See this post on overriding jquery core methods: http://www.bennadel.com/blog/1624-Ask-Ben-Overriding-Core-jQuery-Methods.htm
(function () {
// Store a reference to the original tablesorter plugin.
var originalTableSorter = jQuery.fn.tablesorter;
// Define overriding method.
jQuery.fn.tablesorter = function () {
if (this.find('tbody tr').size() == 0) {
if (typeof console != "undefined" && console.log) {
console.log('skipping tablesorter initialization - table is empty');
}
return;
}
// Execute the original method.
originalTableSorter.apply(this, arguments);
}
})();

This has been fixed in the lastest tablesorter (see issue 95).

Since overwriting plugins is always a bad idea, here's a different approach: If you just want to make sure your data table contains actual data rows, the jQuery selector :has() gets the job done, too.
$('table.tablesorter:has(tbody tr)').tablesorter({
// your tablesorter config here
});

Related

Detecting valid field on cellEdit

this should be pretty easy just can't find the answer in the documentation. So I'm using jQuery Tabulator and creating an error message when a rule is broken. Easy enough.
validationFailed:function(cell, value, validators){
$('#data-errors').html('<span class="error error-message">....</span>')
},
I want to remove that error message once the error is fixed but I can't see how to do it. I assume there is a really simple callback that I could run in the cellEdited function, a cellEdited callback sort of thing, or validate the entire table like how other validate plugins work:
if($('#data-table').valid()){ ... }
I just can't find it in the documentation:)
The cellEdited callback will be called if a cell passes validation and has been successfully edited.
You can either bind to this for the table as a whole
var table = new Tabulator("#example-table", {
cellEdited:function(cell){
//cell - cell component
},
});
or if you only want to monitor a specific column you can set it in a column definition:
{title:"Name", field:"name", cellEdited:function(cell){
//cell - cell component
},
}

Confused on getting DataTables Render Text Helper?

I am trying to render my DataTables table so that it allows HTML characters to be shown.
From my reading it seems that this can be done using the DataTables Text Helper (as seen here https://datatables.net/manual/data/renderers)
In the example they give they simply put:
data: 'product',
render: $.fn.dataTable.render.text()
However when I have tried this it appears to do nothing at all as all the columns in my DataTable still don't show any HTML special characters (and no errors). I understand that my code is more complex than this example, but is there something simple I am missing?
var dataTableZ = $('#results_table').DataTable({
data: data.value,
render: $.fn.dataTable.render.text(),
/*
Unrelated Code surrounding buttons and column ordering
*/
columns: searchColumnDetails
});
(Where data.value is some data coming back from an Ajax call)
I have tried looking for answers to my question and it seems I am running a version of DataTables that includes this function (1.10.20), but none of the examples I could find online shed any light into my confusion.
Thank you for any assistance!
I Managed to find an answer to my question on the DataTables Forums!
Datatables doesn't have an option called render. There is a columns.render. You need to use either columns or columnDefs to to apply the render. Something like this:
columnDefs: [ {
targets: 0,
render: $.fn.dataTable.render.text() } ]
By putting this code into my code, it worked as intended.
Forum Post: https://datatables.net/forums/discussion/59325/render-text-helper-not-showing-html/p1?new=1

Extjs 4.1 pagingtoolbar default page

I want to change default page of pagination toolbar to 1 of 1 instead 0 of 0 in case of no record.Plus I am not using store proxy to request any records, so is there any way to accomplish it without using store proxy. According to my requirement user can add rows manually to the grid with the pagination toolbar showing page 1 and when rows exceeds 10 it moves to 2nd page.
In Ext it is possible to overload a component like Ext.toolbar.Paging with your own custom version. Simply specify an alias in your definition and you can us it just like the "native control."
In order to be sure that the approach would work, I set up a test project with a simple datasource and implemented enough of a replacement definition that I could see the "Ext.toolbar.Paging".getPagingItems method being fired in my custom definition.
From that point you can replace the code inside the definition of the original method to allow for a custom minimum in addition to the opportunity to overload the "updateInfo" method to make sure that during data reloads you're not plowing through your customizations.
In addition to these two things, you should (with a relatively small amount of effort) be able to implement on top of the control to support dynamically changing it's values based on the contents of your grid.
If you look at the documentation for ux.data.PagingStore you should be able to suss out the differences in using a remotely supplied store from something that is served with data locally.
Hope this helps you.
Code Sample:
Ext.define(
"Test.view.testview.TvPageBar",
{
extend: "Ext.toolbar.Paging",
alias: "widget.tvpagebar",
title: "Bob",
strictInit: function () {
"use strict";
console.log("TvPageBar init");
},
getPagingItems: function () {
console.log("getPagingItems", this);
this.callParent(arguments);
},
initComponent: function () {
this.strictInit();
this.callParent(arguments);
}
}
);

How to (properly) render additional data in grid with RowExpander

I'm trying to render some data in the rowbody in a grid (with the RowExpander plugin).
My problem is that the ol' rowBodyTpl isn't enough for me as this data is from Records on Stores from the record being rendered (hmmm...).
Putting it simply: Every record of the grid has a store in it (lets call it Items). So, I want to render the record data and some data of the Items records aswell.
What would be the best(ish) way of doing so?
Override the renderer function of the rowexpander plugin, override the getAdditionalData, or none of these?
Thank you.
I know this question is a few years old, but here's a trick I currently use to handle this kind of situation. It takes advantage of "verbatim" blocks that XTemplates allow. These allow you to execute arbitrary code inside an XTemplate by wrapping it with {% ... %}. Inside those code blocks, this is set to the XTemplate itself. The XTemplate has an owner property that, in our case, references the RowExpander plugin itself, which, in turn, has a grid property to reference the grid. So, something like this allows you to add arbitrary data to the values passed into rowBodyTpl.
Ext.create('Ext.grid.Panel', {
...
injectRowBodyData: function(values) {
values.MyInjectedContent = "Here's some extra data!";
},
plugins: [
{
ptype: 'rowexpander',
rowBodyTpl: [
'{% this.owner.grid.injectRowBodyData(value); %}',
'<div>',
'<h1>{Title}</h1>',
'<p>{Content}</p>,
'<p>{MyInjectedContent}</p>',
'</div>'
]
}
]
});
Hhopefully Sencha will fix the plugin to provide a way to handle this in the future. But for now this works well. I tested this with v4.2.1.883, but this should work with any previous version of Ext 4. The only thing I can think of that may prevent it from working in the future is the XTemplate's owner property no longer being pointed to the plugin, or the plugin not having a reference to the grid with it's grid property.
How I "solve" this problem, it might help somebody else:
I overrode the getRowBodyFeatureData of the rowexpander plugin, as this function not only receives the data to be applied on the template, but also the record itself, so I just data added the extra stores/arrays from the record.
Not sure if its the best way, but hey... at least it works.
You can also use if else statements in rowBodyTpl:
Check for ":"
"<tpl if='phone == \":\"'>",
"<tpl else>",
"</tpl>"
Check for empty string
"<tpl if='phone == \"\"'>",
"</tpl>"
this sample is taken from here: link
This is how I usually do:
Ext.create('Ext.grid.Panel',{
border: true,
store: 'ds',
columns: []
plugins: [{
ptype: 'rowexpander',
rowBodyTpl : ['<p><b>Title:</b>{name}<br/><b>Description:</b> {description}<br/><b>Experiment Design:</b> {experimentdesign}</p>']
}],
renderTo:
});

Dojo EnhancedGrid nested sorting not working

I am trying to create an Enhanced Grid with nested sorting functionality in Dojo but when I go to add the nested sorting functionality via the plugins the grid no longer works (shows up) in the page. My enhanced grid creation code is as follows:
dojo.require("dojox.grid.EnhancedGrid");
dojo.require("dojox.grid.enhanced.plugins.NestedSorting");
grid = new dojox.grid.EnhancedGrid({
canSort: function(colIndex) {
//colIndex = -colIndex; //make columns decend
if ((colIndex == colA) || (colIndex == colB)) {
return false;
}
return true;
},
onHeaderCellMouseOver:function(event{onGridHeaderCellMouseOver(event,layout[0]);},
onHeaderCellMouseOut: function(event){onGridHeaderCellMouseOut(event,layout[0]);},
store: msgStore,
structure: layout,
plugins: {nestedSorting: true}
},document.createElement("div"));
dojo.byId("TableHolder").appendChild(grid.domNode);
grid.startup();
grid.setSortInfo(-1);
If I comment out the plugins line then it will work perfectly w/o nested sort. Does anyone know how I would be able to get nested sorting functionality?
I am using Dojo 1.4.
Thanks
Seems like I have solved this issue .... I figured out that a file that must be included 'required' is: "dojox.grid.cells.dijit". Weird thing is that I found no indication that this was necessary from the documentation, but did happen to find it in the examples. Once this was added to my required statements I had nested sorting. Could someone explain this specific require and its seemingly crucial importance?
Thanks
Just had a quick try with 1.4.3, seems the same code works for me:
dojo.addOnLoad(function(){
var grid = new dojox.grid.EnhancedGrid({
id:'grid',
canSort: function(colIndex) {
if ((colIndex == 0) || (colIndex == 1)) {
return false;
}
return true;
},
onHeaderCellMouseOver:function(event)onGridHeaderCellMouseOver(event,layout[0]);},
onHeaderCellMouseOut: function(event)onGridHeaderCellMouseOut(event,layout[0]);},
store: csvStore1,
structure: layout,
plugins : {nestedSorting: true}
}, document.createElement("div"));
dojo.byId("gridDiv").appendChild(grid.domNode);
grid.startup();
grid.setSortInfo(-1); });
it's malformed in your onHeaderCellMouseOver:function(event{, but don't think that's the cause since single sort works for you.
BTW, setting default nested sorting order by grid.setSortInfo(-1) aren't supported in 1.4(it's in plan for 1.6)
Should be a defect in earlier version, it's working for me in 1.5, also a related thread at dojo forum

Categories

Resources