Javascript 使用jquery datatable的多个实例时,aoData为null
场景: 在一个网页上,我有三个包含表标签的div 有3个按钮,单击每个按钮可以在特定的div上创建一个带有table标记的datatable实例 datatable从服务器端获取数据 所有返回和显示的数据、分页、筛选都可以正常工作 因此,在创建所有三个实例时,仅对最后创建的实例使用fnSettings()返回正确的对象,而其他两个实例返回null 因此,使用fnData()etc api方法会抛出一个错误:“TypeError:无法读取null的属性'aoData',因为该datatable实例的设置对象以某种方式为null 代码说明 我创建了一个名为datagrid的类,并创建了该类的多个实例:Javascript 使用jquery datatable的多个实例时,aoData为null,javascript,jquery,jquery-datatables,Javascript,Jquery,Jquery Datatables,场景: 在一个网页上,我有三个包含表标签的div 有3个按钮,单击每个按钮可以在特定的div上创建一个带有table标记的datatable实例 datatable从服务器端获取数据 所有返回和显示的数据、分页、筛选都可以正常工作 因此,在创建所有三个实例时,仅对最后创建的实例使用fnSettings()返回正确的对象,而其他两个实例返回null 因此,使用fnData()etc api方法会抛出一个错误:“TypeError:无法读取null的属性'aoData',因为该datatable实例
/**
* datagrid class contains methods and properties that will help in controllling and manipulating the multiple instances of the datagrid class
*
* This function is the constructor for the datagrid class
*
* @param {string} domContainerSelector DOM selector of the element containing the datagrid
* @param {Array} columns Definitions of the columns of the datagrid
* @param {string} ajaxSource The url that the jqgrid will use to request for data
* @param {Object} configurationParameters The configuration parameters that will be used by the jqGrid and this datagrid instance. Currently suppoted configuration parameters are: initialCacheSize, iDisplayLength, sScrollY, bPaginate, bFilter, sDom, bSort
* @param {Object} uiCallback Contains callback functions that are used when a server request is in progress and after the completion of the request. Mainly used for showing progress indicators.
* @returns {datagrid}
*/
function datagrid(domContainerSelector, columns, ajaxSource, configurationParameters, uiCallback)
{
this.domContainerSelector = domContainerSelector;
this.domTableSelector = this.domContainerSelector + " #grid";
this.domRowSelector = this.domTableSelector + " tbody tr";
this.domGridWrapperSelector = this.domContainerSelector + " .dataTables_wrapper";
this.columns = columns;
this.ajaxSource = ajaxSource;
this.configParams = configurationParameters;
this.uiCallback = uiCallback;
this.cache= {
start: 0,
end: 0,
initialSize:this.configParams.initialCacheSize == undefined ? 2 : this.configParams.initialCacheSize,
pageSize:this.configParams.iDisplayLength == undefined ? 10 : this.configParams.iDisplayLength,
loading:false,
jsondata: {},
reset: function(){
this.start=0;
this.end=0;
this.loading=false;
this.jsondata={};
}
};
/**
* This method returns the row selected by the user
*
* @return {Object} Row object containing columns as its properties
*/
this.getSelectedRow = function()
{
var allrows = this.dataTable.fnGetNodes();
for (i = 0; i < allrows.length; i++)
if ($(allrows[i]).hasClass('row_selected'))
return this.dataTable.fnGetData(allrows[i]);
};
this.getPostDataValue=function(postData, key){
for (var i=0;i<postData.length;i++)
{
if (postData[i].name == key)
{
return postData[i].value;
}
}
return null;
};
this.setPostDataValue=function(postData, key, value){
for (var i=0; i<postData.length;i++)
{
if (postData[i].name == key)
{
postData[i].value = value;
}
}
};
this.setPostDataFilterValues=function(postData){
for (i=0;i<this.columns.length;i++)
{
var key="sSearch_"+i;
this.setPostDataValue(postData,key,this.columns[i].sSearch===undefined?'':this.columns[i].sSearch);
}
};
this.filterColumnKeyupHandler = function(evt) {
var id=evt.target.id;
var index=id.charAt(id.length-1);
var oldvalue=this.columns[index].sSearch;
var value = evt.target.value == '' ? undefined : evt.target.value;
if (oldvalue!=value) this.cache.reset();//resetting the cache because the datagrid is in dirty state
this.columns[index].sSearch=value;
if (evt.keyCode == 13) this.dataTable.fnFilter();
};
/**
* This method acts as the general button handler when an operation is in progress
*/
this.busyStateButtonHandler=function()
{
ui.showmessage("Another operation is in progress. Please wait for the operation to complete");
};
/**
* This method sets the event handlers for the datagrid
*/
this.setEventHandlers = function() {
var self=this;
$(this.domGridWrapperSelector + " input[class='columnfilterinput']").off("keyup").on("keyup", function(evt) {self.filterColumnKeyupHandler(evt,self)});
$(this.domGridWrapperSelector + " .filterbar .searchbtn").off("click").on("click", function() {self.dataTable.fnFilter()});
};
/**
* This method sets the appropriate event handlers to indicate busy status
*/
this.setBusyStatusEventHandlers=function()
{
$(this.domGridWrapperSelector + " input[class='columnfilterinput']").off("keyup").on("keyup", this.busyStateButtonHandler);
$(this.domGridWrapperSelector + " .filterbar .searchbtn").off("click").on("click", this.busyStateButtonHandler);
};
/**
* This method enables column specific filtering
*
* This methods adds filtering capability to columns whose definitions indicate that they are searchable (bSearchable:true)
*/
this.enablecolumnfilter = function() {
var self = this;
var oTable = self.dataTable;
var oSettings = oTable.fnSettings();
var aoColumns = oSettings.aoColumns;
var nTHead = oSettings.nTHead;
var htmlTrTemplate = "<tr class='filterbar'>{content}</tr>";
var htmlTdTemplate = "<td>{content}</td>";
var htmlInputTemplate = "<input type='text' name='{name}' id='{id}' class='{class}' /><div class='searchbtn' id='{searchbtnid}'><div class='icon-filter'></div></div>";
var isAnyColumnFilterable = false;
var htmlTr = htmlTrTemplate;
var allHtmlTds = "";
for (i = 0; i < aoColumns.length; i++)
{
var column = aoColumns[i];
var htmlTd = htmlTdTemplate;
if (column.bSearchable == true)
{
isAnyColumnFilterable = true;
var htmlInput = htmlInputTemplate;
htmlInput = htmlInput.replace('{name}', column.mData);
htmlInput = htmlInput.replace('{id}', "sSearch_" + i);
htmlInput = htmlInput.replace('{class}', 'columnfilterinput');
htmlTd = htmlTd.replace('{content}', htmlInput);
}
else
htmlTd = htmlTd.replace('{content}', '');
allHtmlTds += htmlTd;
}
if (isAnyColumnFilterable)
{
htmlTr = htmlTr.replace('{content}', allHtmlTds);
nTHead.innerHTML += htmlTr;
$(this.domGridWrapperSelector + " .filterbar input[class='columnfilterinput']").each(function(){
$(this).width($(this).parent().width()-26);
});
}
};
/**
* This method enables single selection on the rows of the grid
*/
this.enableSelection = function()
{
$(this.domRowSelector).die("click").live("click", function() {
if ($(this).hasClass('row_selected')) {
$(this).removeClass('row_selected');
}
else {
$(this).siblings().removeClass('row_selected');
$(this).addClass('row_selected');
}
});
};
this.loadDataIntoCache=function(postData, sourceUrl, start, length){
if (!this.cache.loading)
{
var postData=$.extend(true, [], postData);
var start = start==undefined?this.cache.end:start;
var length = length==undefined?this.cache.pageSize:length;
var end = start + length;
this.setPostDataValue(postData, "iDisplayStart", start);
this.setPostDataValue(postData, "iDisplayLength", length);
var self=this;
this.cache.loading=true;
$.ajax({
type: "POST",
url: sourceUrl,
data: postData,
success:
function(json, textStatus, jqXHR)
{
json = JSON.parse(json);
var olddata=self.cache.jsondata.aaData;
if (olddata===undefined) self.cache.jsondata = $.extend(true, {}, json);
else olddata.push.apply(olddata,json.aaData);
self.cache.end=end;
},
error:
function(jqXHR, textStatus, errorThrown)
{
ui.showmessage(jqXHR.responseText);//remove this from here
},
complete:
function()
{
self.cache.loading=false;
}
});
}
};
this.loadDataFromCache=function(postData,sourceUrl){
var start=this.getPostDataValue(postData, "iDisplayStart");
var length=this.cache.pageSize;
var end=start+length;
var sEcho = this.getPostDataValue(postData,"sEcho");
if (this.cache.end>=end)
{
var jsondata=$.extend(true, {},this.cache.jsondata);
var data=jsondata.aaData;
jsondata.aaData=data.splice(start,length);
jsondata.sEcho = sEcho;
var totalRecords=jsondata.iTotalRecords;
if ((this.cache.end-end)<((this.cache.initialSize*this.cache.pageSize)/2) && (totalRecords==0 || this.cache.end<totalRecords) ) this.loadDataIntoCache(postData, sourceUrl);//prefetch data if needed
return jsondata;
}
else
{
this.loadDataIntoCache(postData,sourceUrl);
return null;
}
};
/**
* This method interfaces with the backend end controller
*
* This method is called when the grid initiates any operation that requires server side processing
*
* @param {String} sSource The source url that will be used for the xhr request
* @param {Array} aoData Contains the parameters sent by the dataTable that will be forwarded to the backend controller
* @param {Function} fnCallback The callback function of the dataTable that gets executed to finally render the grid with the data
*/
this.interfaceWithServer = function(sSource, aoData, fnCallback)
{
this.setPostDataFilterValues(aoData);
var self=this;
if (this.cache.end==0)
{
this.setPostDataValue(aoData, "iDisplayStart", this.cache.start);
if (this.dataTable!=undefined) this.dataTable.fnSettings()._iDisplayStart=0;
this.loadDataIntoCache(aoData, sSource, 0, (this.cache.initialSize*this.cache.pageSize));
}
var data=this.loadDataFromCache(aoData,sSource);
if (data!=null) fnCallback(data);
else
{
this.setBusyStatusEventHandlers();
this.uiCallback.inprogress();
self.cacheLoadingTimerId=setInterval(function(){
if (self.cache.loading==false)
{
clearInterval(self.cacheLoadingTimerId);
var data=self.loadDataFromCache(aoData,sSource);
fnCallback(data);
self.uiCallback.completed();
self.setEventHandlers();
}
},500);
}
};
/**
* This method destroys the datatable instance
*
* Remove all the contents from the parent div and reinserts a simple table tag on which a fresh datatable will be reinitialized
*/
this.destroy = function()
{
$(this.domRowSelector).die("click");
$(this.domGridWrapperSelector).remove();//remove only the datatable generated dynamic code
$(this.domContainerSelector).prepend("<table id='grid'></table>");
};
/**
* The dataTable property holds the instance of the jquery Datatable
*/
this.dataTable = $(this.domTableSelector).dataTable({
"bJQueryUI": true,
"sScrollY": this.configParams.sScrollY == undefined ? "320px" : this.configParams.sScrollY,
"bAutoWidth": true,
"bPaginate": this.configParams.bPaginate == undefined ? true : this.configParams.bPaginate,
"sPaginationType": "two_button",
"bLengthChange": false,
"bFilter": this.configParams.bFilter == undefined ? true : this.configParams.bFilter,
"sDom": this.configParams.sDom == undefined ? '<"H"lfr>t<"F"ip>' : this.configParams.sDom,
"bSort": this.configParams.bSort == undefined ? true : this.configParams.bSort,
"iDisplayLength": this.configParams.iDisplayLength == undefined ? 10 : this.configParams.iDisplayLength,
"bServerSide": true,
"sAjaxSource": this.ajaxSource,
"fnServerData": this.interfaceWithServer.bind(this),
"oLanguage": {
"sZeroRecords": "No Records Found",
"sInfo": "_START_ - _END_ of _TOTAL_",
"sInfoEmpty": "0 to 0 of 0"
},
"aoColumns": this.columns
});
this.init=function(){
this.enableSelection();
this.enablecolumnfilter();
this.setEventHandlers();
};
this.init();
};
/**
*datagrid类包含有助于控制和操作datagrid类的多个实例的方法和属性
*
*此函数是datagrid类的构造函数
*
*@param{string}domContainerSelector包含datagrid的元素的DOM选择器
*@param{Array}columns数据网格列的定义
*@param{string}ajaxSource jqgrid将用于请求数据的url
*@param{Object}configurationParameters jqGrid和此datagrid实例将使用的配置参数。当前支持的配置参数有:initialCacheSize、iDisplayLength、sScrollY、bPaginate、bFilter、sDom、bSort
*@param{Object}uiCallback包含在服务器请求进行中和请求完成后使用的回调函数。主要用于显示进度指标。
*@returns{datagrid}
*/
函数datagrid(domContainerSelector、columns、ajaxSource、configurationParameters、uiCallback)
{
this.domContainerSelector=domContainerSelector;
this.domTableSelector=this.domContainerSelector+“网格”;
this.domRowSelector=this.domTableSelector+“tbody tr”;
this.domGridWrapperSelector=this.domContainerSelector+“.dataTables\u wrapper”;
this.columns=列;
this.ajaxSource=ajaxSource;
this.configParams=配置参数;
this.uiCallback=uiCallback;
此.cache={
起点:0,
完:0,,
initialSize:this.configParams.initialCacheSize==未定义?2:this.configParams.initialCacheSize,
pageSize:this.configParams.iDisplayLength==未定义?10:this.configParams.iDisplayLength,
加载:false,
jsondata:{},
重置:函数(){
这个.start=0;
这个.end=0;
这个。加载=假;
this.jsondata={};
}
};
/**
*此方法返回用户选择的行
*
*@return{Object}包含列作为其属性的行对象
*/
this.getSelectedRow=函数()
{
var allrows=this.dataTable.fnGetNodes();
对于(i=0;i 如果((this.cache.end)我认为问题在于您的表都具有相同的ID。请注意,正确的HTML需要唯一的ID:
这里有两个jsfiddle。
第一个表复制您的代码,对两个表使用相同的id。它在创建第一个表后显示一个警报;fnSettings不为null。然后在创建下一个表后显示一个警报,表1的fnSettings突然为null。第二个JSFIDLE使用唯一的id,问题消失
也许您的表id可以是div id和“grid”的组合,例如div1grid、div2grid等。然后您可以使用domContainerSelector+“grid”而不是“#grid”。我认为问题在于您的表都具有相同的id。请注意,正确的HTML需要唯一的id:
这里有两个jsfiddle。
第一个表复制您的代码,对两个表使用相同的id。它在创建第一个表后显示一个警报;fnSettings不为null。然后在创建下一个表后显示一个警报,表1的fnSettings突然为null。第二个JSFIDLE使用唯一的id,问题消失
也许您的表id可以是div id和“grid”的组合,例如,div1grid、div2grid等。然后您将使用domContainerSelector+“grid”而不是“#grid”。您可以模拟相同的吗?您可以模拟相同的吗?虽然我同意您的回答,但我很确定w3schools作为一种资源是不受欢迎的。是的,我似乎忽略了这一方面,用unqiue选择器初始化了每个数据表,但是还是那个“身份证”问题出现了。@JayRizzi-针对w3学校的观点。我将答案编辑为参考w3.org。奇怪的是,这对我有帮助。我在代码中的任何地方都没有使用id。我认为DataTables使用id作为选择器(如果可用)。我只是完全删除了id。虽然我同意你的答案,但我非常确定w3学校是不赞成的作为一个资源,我似乎忽略了这一点,用unqiue选择器初始化了每个数据表,但仍然是相同的“id”问题终于解决了。@JayRizzi-关于w3学校的观点。我已经编辑了参考w3.org的答案。这帮助了我,奇怪的是。我在代码中的任何地方都没有使用id。我认为DataTables使用了id a
switch (dialog)
{
case "cusgrp_dialog":
var columndefs = [
{
"sTitle": "XWBNCD",
"mData": "xwbncd",
"sWidth": "40%"
},
{
"sTitle": "XWKHTX",
"mData": "xwkhtx",
"sWidth": "60%"
}
];
var ajaxSource = "./entities/Cusgrp";
var configurationParameters = {
bFilter: null,
sDom: 't<"dataTable_controlbar"ip>'
};
this.customergroupDatagrid = new datagrid(domContainerSelector, columndefs, ajaxSource, configurationParameters, uiCallback);
break;
case "slmen_dialog":
var columndefs = [
{
"sTitle": "PERSON",
"mData": "person",
"sWidth": "40%"
},
{
"sTitle": "PNAME",
"mData": "pname",
"sWidth": "60%"
}
];
var ajaxSource = "./entities/Slmen";
var configurationParameters = {
bFilter: null,
sDom: 't<"dataTable_controlbar"ip>'
};
this.salesmanDatagrid = new datagrid(domContainerSelector, columndefs, ajaxSource, configurationParameters, uiCallback);
break;
case "dists_dialog":
var columndefs = [
{
"sTitle": "DSDCDE",
"mData": "dsdcde",
"sWidth": "40%"
},
{
"sTitle": "DNAME",
"mData": "dname",
"sWidth": "60%"
}
];
var ajaxSource = "./entities/Dists";
var configurationParameters = {
bFilter: null,
sDom: 't<"dataTable_controlbar"ip>'
};
this.distributorDatagrid = new datagrid(domContainerSelector, columndefs, ajaxSource, configurationParameters, uiCallback);
break;
}
id = name [CS]
This attribute assigns a name to an element. This name
must be unique in a document.
var dt1 = $('#div1 #grid').dataTable();
alert('dt1 settings: ' + dt1.fnSettings());
var dt2 = $('#div2 #grid').dataTable();
alert('dt1 settings: ' + dt1.fnSettings());
alert('dt2 settings: ' + dt2.fnSettings());
var dt1 = $('#div1 #grid1').dataTable();
alert('dt1 settings: ' + dt1.fnSettings());
var dt2 = $('#div2 #grid2').dataTable();
alert('dt1 settings: ' + dt1.fnSettings());
alert('dt2 settings: ' + dt2.fnSettings());