JQuery Responsive Datatable doesn't work if table is ever empty - datatable

I have a responsive datatable defined as follows:
function loadCancellations(date) {
$('#cancellations').dataTable({
bDestroy: true,
bProcessing: false,
bServerSide: false,
bAutoWidth: false,
ajax: {
url: 'Modules/Bookings/',
data: {date: date, type: 'cancelled'}
},
sPaginationType: "full_numbers",
iDisplayLength: 50,
bLengthChange: false,
bPaginate: false,
bFilter: false,
bSort: true,
sDom: 't',
rowId: 6,
columns: [/*responsive column information*/],
order: [[0, 'asc'],[1, 'asc']],
asStripeClasses: ['', 'altrow'],
language: {
emptyTable: 'No cancelled bookings for this day'
},
fnCreatedRow: function( nRow, aData, iDataIndex ) {
// last column replaced with buttons
}
});
}
This function is called when the value of a datepicker changes, so it always refreshes the table with the cancelled bookings on the selected day. There are six columns (plus the buttons), two are always hidden until the row is expanded using the responsive interface in the first column, and I've tested it multiple times and it works fine.
except
If the table is ever empty, the responsive interface never works again. Instead it kicks a console error that says TypeError: a[0].aoData[this[0]] is undefined. So if it loads full, then I load a day that doesn't have any, and then I load another day that has some, the responsive plugin breaks. It doesn't matter whether I then destroy and re-initialize the datatable, it simply refuses to work. I can even go back to a date that had working rows - they don't work any more.
Does anyone have any ideas for a solution to this?

The plugin I was using was out of date. This was solved in a later version. I should have checked this before posting, and I feel shame for it.

Related

Programmatically changing a bound check box in Kendo Grid not holding its new value

I am in need of assistance in an attempt to programmatically check/uncheck a checkbox in a kendo grid.
I have part of my Grids datasource for this relevant field as...
receivereport: {
editable: true,
nullable: false,
required: false,
type: 'boolean',
validation: {
required: false
}
},
And the grids configuration is...
$("#contactGrid").kendoGrid({
dataSource: contactGridDS,
navigatable: true,
dataBound: mapContactTypes,
editable: true,
edit: function (input) {
},
toolbar: ["save", "cancel"],
pageable: false,
columns: [
{ field: 'email', title: 'Email', hidden: false, attributes: { "class": 'contactCell_email' } },
{ field: 'receivereport', title: 'Receive Reports?', hidden: false, attributes: { "class": 'contactCell_receivereport' }, template: '<input type="checkbox" #= receivereport ? "checked=checked" : "" # value="" disabled="disabled" ></input>' }
],
//filterable: true,
sortable: {
mode: 'single',
allowUnsort: false
}
});
For brevity sake, I cut some of the other code out that's not relevant, such as other fields not involved here.
So, I have an email method that has a regex in it that works, and what I want to do is, if on focus, or focus out of the email field, if that email is invalid, make the receive report field false, but it's not registering dirty editing, and I even tried forcing it by appending some CSS rules and classes, which makes it "look" dirty, but when I change the value of the checkbox, on save, it goes back to what it was.
The data is bound to the receivereport data. So I think I read on the forums here that I need to do something like datasource.set("receivereport", false); And maybe a sync? The syncinc fires but it doesn't help and I must be calling the set incorrectly because the console says its firing on an unidentified object.
Here's the real kicker, I know how to access that check box and render it as false, but it flips right back to what it was bound to! It's not holding. Unless I click into that cell and do a click on the check box, it doesn't hold...
...unless I can simulate a fake click event on the target, being the checkbox...
I looked at the example here, Disable/Enable the checkbox in kendo grid based on column Value, but it seems a bit different and not what I need.
Bottom line - if the checkbox is true/checked, and a user goes back into the email field and renders it invalid, I want to automatically uncheck that checkbox, as well as make that checkbox disabled, until the user makes the email valid again. This also implies that a null email, means the checkbox must be false and disabled.
Anyways, any help would be immensely appreciated. Thanks.
This can be done using the "change" event of the dataSource:
dataSource = new kendo.data.DataSource({
change: function(e) {
if (e.action == "itemchange" && e.field == "email") {
//you can check the email value as well:
//var model = e.items[0];
e.items[0].set("receivereport", false)
}
},
Here is the full example:
Grid: change field value depending on another field

Grid not working after reloading on alternate calls

$("#tableVisualization").jqGrid('GridUnload');
$("#tableVisualization").jqGrid({
datatype: "local",
mtype: 'GET',
colNames: this.GetGridColumnNames(),
colModel: this.GetGridColumnModel(),
height: "100%",
autowidth: true,
shrinkToFit: true,
sortname: 'monthID',
sortorder: "desc",
rowList: [6, 12],
rowNum: 12,
pager: $('#pager3'),
viewrecords: true,
recordpos: "left",
caption: "Table"
});
//local data array used for example
var data = this.GetGridData();
//FUNCTION CALL
//populate grid with data
$("#tableVisualization").jqGrid("addRowData", "month", data);
$("#tableVisualization").trigger("reloadGrid");
$("#tableVisualization").setGridWidth(1040, true);
Above code works fine.
However if I assign $("#tableVisualization") to a variable and use the variable in the above code it does not work.
//var grid = $("#tableVisualization");
It works every alternate call.
For example if the whole code was inside a javascript method called LoadGrid(), then the first call to the method works, second call does not, third works, fourth does not and so on.
I have seen during debugging, when it reached "grid.jqGrid('GridUnload')" on the even calls, the grid is completely removed(im not sure if the html table is removed or not) and it is not created during "$("#tableVisualization").jqGrid({.....});".
Can anyone please explain me the reason for this behaviour.
I can make the scenario work because now I am not using a local variable but I would like to know why it does not work?
We can see exactly what is going on within the grid's GridUnload method in grid.custom.js:
GridUnload : function(){
return this.each(function(){
if ( !this.grid ) {return;}
var defgrid = {id: $(this).attr('id'),cl: $(this).attr('class')};
if (this.p.pager) {
$(this.p.pager).empty().removeClass("ui-state-default ui-jqgrid-pager corner-bottom");
}
var newtable = document.createElement('table');
$(newtable).attr({id:defgrid.id});
newtable.className = defgrid.cl;
var gid = $.jgrid.jqID(this.id);
$(newtable).removeClass("ui-jqgrid-btable");
if( $(this.p.pager).parents("#gbox_"+gid).length === 1 ) {
$(newtable).insertBefore("#gbox_"+gid).show();
$(this.p.pager).insertBefore("#gbox_"+gid);
} else {
$(newtable).insertBefore("#gbox_"+gid).show();
}
$("#gbox_"+gid).remove();
});
},
The key points to understand are:
A new table element is inserted with the same DOM id as the old table. We can see it created in the call to document.createElement('table') and inserted in one of the calls to insertBefore.
The existing jqGrid DOM is removed in the call to $("#gbox_"+gid).remove(). Since the old table element is contained within the gbox, it is removed as well.
After the call to GridUnload, the DOM element that it refers to no longer exists on the page, so any code that references the element is ineffective.
Does that help?

jqGrid subGrid stops opening after scroll

I have a grid (version 4.1.1) using a subGrid. I'm using loadonce: true and scroll: 1. When the grid first loads, I can open subGrids with no problem, until I scroll the main grid down to the point where it loads more data. After that, no subgrid will open or close. If I click on the plus icon, I see the "Loading...", but nothing happens. I can't even close the subGrids that were previously opened.
Here is my grid definition:
$("#grid_sites").jqGrid({
url:'getgridxmlsites.php',
postData: {detailid: function() {return $('#hdnDetailId').val(); }},
datatype: 'xml',
height: 260,
width: 832,
shrinkToFit: false,
caption:'',
colNames :['studydetailid', 'Site', 'Name', 'Status', 'Location'],
colModel :[
{name:'detailid', index:'detailid', width:0, hidden: true },
{name:'sitenumber', index:'sitenumber', width:60, align:'right'},
{name:'name', index:'name', width:230},
{name:'status', index:'status', width:110, align:'center'},
{name:'location', index:'location', width:74}
],
pager:'pager_sites',
scroll: 1,
viewrecords:true,
sortable:true,
sortname: 'sitenumber',
autowidth: true,
pgbuttons: false,
loadonce: true,
// gridview: true, // Cannot be used when using subGrid.
onSelectRow: function(id){ gridRowSelect(id) },
subGrid: true,
subGridUrl: 'getgridxmldatabysite.php',
subgridtype: 'xml',
subGridModel: [{
name: ['Owner', 'Phone', 'Status'],
width: [120, 100, 100],
align: ['left', 'left', 'left'],
params: ['detailid']
}],
subGridOptions: { reloadOnExpand : false }
});
I hope you can help.
I am experiencing a similar problem. It looks like the addSubGrid function in jqgrid is adding a click event to toggle the subgrid to every row in the table (not just the ones that were just loaded).
This was causing the new rows to behave fine but the first set to rapidly expand and then collapse (two click handlers). When another set of data got loaded the first set of rows worked fine (although they'd expand, collapse, and expand again) but the second set no longer worked.
I got kind of lost in the combination of addJSON and addSubGrid when trying to figure out if I was missing some of the row metadata in the JSON. For now I just modified the line:
$(ts.rows[i].cells[pos]).bind('click', function(e) {
to:
$(ts.rows[i].cells[pos]).unbind('click');
$(ts.rows[i].cells[pos]).bind('click', function(e) {
and everything seems to work as expected. This is for version 4.2.0 of jqGrid. I'm still not sure if this is a bug, a configuration problem, or a data problem but at least I'm working again.
Typical the "Loading..." means an error in the processing of the server response. I recommend you to use jquery.jqGrid.src.js instead of jquery.jqGrid.min.js and to start your page in the debugger. For example you can use Developer Tools of Internet Explorer. Do do this you should press F12 to start Developer Tools, then choose "Script" and click on "Start debugging" button. Either the page will be stopped on error or you will be see some additional information in the "Colsole" on the right pane.
I personally not use scroll: 1 option because of complexity of the data processing and different known bugs or problems. It seems to me that you use incompatible combination of parameters. I would recommended you to remove either loadonce: true or scroll: 1 parameter.
In your configuration, you do not set rowNum. So I believe jqgrid will use the default rowNum which is 20. This causes the scrolling issue due to the click binding issue mentioned by Robert Simmons.
Another way to fix this issue without having to change the jqgrid code is to set the rowNum to -1. This will just get all rows, which should be fine because you are using local data. This fix may not work in previous versions to 4.6.0 however. (See How to show all rows in the jqGrid? for more info on setting rowNum to -1). In versions prior to 4.6.0 I think the main solution was to just set rowNum to a large number.

Posting non-editable values in jqgrid

I'm using jqgrid 3.8.2 and the grid have many columns that are non-editable but still want to be posted to the server. How I can do that? (If I set editable:false then the field is not getting posted the the server)
It seems to me that the column settings
hidden: true, editable: true, editrules: { edithidden: false }
will do what you need.
I realize this question is pretty old now but I needed to do this same thing today and the accepted answer doesn't actually answer the question. Sorry Oleg, you are still awesome. Anyway, if you have visible columns and are doing inline editing where some of those columns should not be editable the following worked for me.
Use these column setting
editable: true, edittype: 'custom', editoptions: { custom_element: readOnlyElement, custom_value: readOnlyValue}
and define these functions
function readOnlyElement(value, options) {
return $('<span></span>', { text: value });
},
function readOnlyValue(elem, operation, value) {
if (operation === 'get') {
return $(elem).text();
} else if (operation === 'set') {
$('span', elem).text(value);
}
}
About 'editable: "hidden"'...
This method is perfect until you change the contents of a cell. With 'editable:' hidden '', the jqgrid does not contain <input /> but aria-describedby which is less simple to target.
ex:
without 'editable:"hidden"'
you target the input by its 'id '==>' $("#yourgrid #jqg3_your_field")
with 'editable:' hidden 'you target like that ...
You need your current row id
rowID = $("#yourgrid").jqGrid('getGridParam', 'selrow');
$("tr[id='"+rowID+"'] [aria-describedby='yourgrid_your_field']>.u-jqgrid-cell-wrapper").html()
It's a lot less convenient :-)
Despite everything, it works very well ;-)
I see the answer in the comments for Oleg's answer by #singe3.
Set,
editable: "hidden"

Why jqGrid is very slow when number of rows displayed increases?

When I display a small amount per page, it's quick and very good. When I increase it to 100 or more it starts getting slow. At 1000 it's unbearable! This is the code used for drawing the grid:
$("#stSearchTermsGrid").jqGrid({
mtype: "POST",
postData:{},
datatype: function(postdata) {
$.ajax({
url: 'ajax/ajax_termsSearchGridSimple.php',
data: postdata,
async: false,
dataType: "xml",
error: function(){
alert('Error loading XML document');
},
success: function(data,stat,xmldata){
//check error
var $error=$(data).find('error').text();
if($error!="0")
{
messageBox("Error",$error);
return;
}
//content
var $content=$(data).find('content').text();
if($content!="0")
{
var thegrid = $("#stSearchTermsGrid")[0];
thegrid.addXmlData(xmldata.responseXML);
}
}
});
},
colNames:["tId","term", "revTerm", "uType","freq","description","fId","facet","modifiedTime"],
colModel:[
//tId
{name:'tId',index:'tId',align:"center",searchoptions:{sopt:['eq','ne','lt','le','gt','ge','in','ni']}},
//term (editable)
{name:'term',index:'term',searchoptions:{sopt:['eq','ne','in','ni','bw','bn','ew','en','cn','nc']},editable:true,edittype:'text',editoptions:{size:20},editrules:{required:true},formoptions:{elmsuffix:'(*)'}},
//revTerm (editable)
{name:'revTerm',index:'revTerm',searchoptions:{sopt:['eq','ne','in','ni','bw','bn','ew','en','cn','nc']},editable:true,edittype:'text',editoptions:{size:20},editrules:{required:true},formoptions:{elmsuffix:'(*)'}},
//uType (editable)
{name:'uType',index:'uType',align:"center",searchoptions:{sopt:['eq','ne','in','ni']},editable:true,edittype:'select',editoptions:{value:{'':'any','NPU':'proper noun','NU':'noun','VU':'verb'}}},
//freq
{name:'freq',index:'freq',align:"center",searchoptions:{sopt:['eq','ne','lt','le','gt','ge','in','ni']}},
//description (editable)
{name:'description',index:'description',searchoptions:{sopt:['bw','bn','ew','en','cn','nc']},editable:true,edittype:'textarea',editoptions:{rows:"3"}},
//fId
{name:'fId',index:'fId',align:"center",searchoptions:{sopt:['eq','ne','lt','le','gt','ge','in','ni']}},
//facet
{name:'facet',index:'facet',searchoptions:{sopt:['eq','ne','in','ni','bw','bn','ew','en','cn','nc']}},
//modifiedTime
{name:'modifiedTime',index:'modifiedTime',align:"center",searchoptions:{sopt:['eq','ne','lt','le','gt','ge','bw','bn','ew','en','cn','nc']}}
],
gridComplete: function(){
var $ids=$("#stSearchTermsGrid").jqGrid('getDataIDs');
for($i=0;$i<$ids.length;$i++){
var $reference="G";
//update columns
$("#stSearchTermsGrid").jqGrid('setRowData',$ids[$i],{"reference":$reference});
//coloring the recently classified row
var $colorRecentlyModified = '#DFFC91';
var modifiedTime = $("#stSearchTermsGrid").jqGrid('getCell',$ids[$i],'modifiedTime');
var timeDiff = Math.abs(new Date() - new Date(modifiedTime.replace(/-/g,'/')));
// 86400000 is the number of milliseconds in one day. Multiplying by days to mark the ones which are modified a few days ago
timeLimit = 86400000 * 1.5;
if(timeDiff < timeLimit)
{
for(colN=2; colN<9; colN++)
$("#stSearchTermsGrid").jqGrid('setCell', $ids[$i], colN, '', {'backgroundColor':$colorRecentlyModified});
}
//coloring the unclassified row
var $colorUnclassified = '#FFCECE';
var $fId = $("#stSearchTermsGrid").jqGrid('getCell',$ids[$i],'fId');
if($fId == "0")
{
for(colN=2; colN<9; colN++)
$("#stSearchTermsGrid").jqGrid('setCell', $ids[$i], colN, '', {'backgroundColor':$colorUnclassified});
}
}
},
sortable: true,
//autowidth:true,
width: 900, //width for grid
height: 250, //height for grid
sortname: 'term', //default sort column
caption: "Terms", //caption for grid (empty will hide)
hidegrid: false,
gridview: true, //load the grid more fast
multiselect: true, //support mulitselect
//multiboxonly: true,
pager: '#stSearchTermsGridPager',
rowNum:10,
rowList:[10,25,50,100,500,1000],
viewrecords: true, //show view record information
viewsortcols: [true,'vertical',true], //show sortable column with icons
editurl: 'ajax/ajax_termsEdit.php'
});
$("#stSearchTermsGrid").jqGrid('navGrid','#stSearchTermsGridPager',
{edit:true,add:false,del:true,search:true,view:true,refresh:true},
// edit options
{
onclickSubmit : function(params, posdata) {
var $tId=$("#stSearchTermsGrid").jqGrid('getGridParam','selrow');
if($tId && $tId.length>0)
{
var $rowAry=$("#stSearchTermsGrid").jqGrid('getRowData',$tId);
var $fId=$rowAry["fId"];
return {"fId":$fId}
}
},
afterSubmit : gridAfterSubmit,
reloadAfterSubmit: true,
closeOnEscape:true,
bottominfo:"Fields marked with (*) are required."
},
// add options
{},
//del options
{
msg: "Selected records(s) will be permanently deleted and cannot be recovered.<br/> Are you sure?",
afterSubmit : gridAfterSubmit,
reloadAfterSubmit: true,
closeOnEscape:true
},
// search options
{multipleSearch:true,closeOnEscape:true},
//view options
{
closeOnEscape:true
}
);
$("#stSearchTermsGrid").jqGrid('gridResize',{minWidth:900,maxWidth:2000,minHeight:250, maxHeight:1000});
I see many places where the grid can be improved.
1) You should use paging. If you show the user 1000 rows of data, the data will be not displayed on the monitor at once. The user have to scroll the windows of web browser to see the most parts of data. Which sense has to spend time to paint the parts of window which will not be seen? The scrolling of data with respect of jqGrid is much more effective as scrolling of browser window. Moreover no person are able to analyse the 1000 rows of data. He have to change sorting and set different filters to understand which from the data are interesting for him. It is one more argument for the data paging and implemented some searching. It you already use advanced searching you can consider to use additionally toolbar searching with the parameter stringResult:true which is compatible with the advanced searching.
2) you should rewrite the code of gridComplete totally. I suppose, that for relatively large number of rows the function is the bottleneck of your code. To verify this just temporary comment the function and compare the time of the grid painting. You should understand that every time you get data by id or set data by id jQuery will have to search the DOM element by id. Especially modification of data on the page can be very slow. By the way it seems to me that you set the same 'background-color' (what is 'backgroundColor' ???) CSS style for almost the whole cells of the rows. Why not set the 'background-color' for the row (<tr> element) instead?
3) I strictly recommend you not use datatype as function. Your server part should return some error HTTP code. In the case the loadError event will work and you can decode and display the custom error message. All other in your data seems be standard and you need not use datatype as function. If you will use datatype:"xml" you can for example try to use loadonce:true and implement client-side data paging and sorting if you will have problem with implementation of this features on the server.
I don't want to write too long text so I stop on the 3 most important points. By the way if you will switch from XML to JSON as the datatype used for the communication with the server, it will also improve a little the performance.
UPDATED: To see the performance of jqGrid with 1000 rows of data without paging and with data paging look at the links. Is by the way the performance of my example with 1000 rows without paging also so slow as in your case?

Resources