使用多个jquery datatable实例时,aoData为null [英] aoData is null when using multiple instances of jquery datatable

查看:2647
本文介绍了使用多个jquery datatable实例时,aoData为null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

情景:

在网页上,我有三个div包含表格标签。

On a webpage I have three divs that contain table tags.

有3个按钮,单击每个按钮将使用表标签在特定的div上创建一个数据表的实例。

There are 3 buttons, clicking on each button creates an instance of the datatable on a particular div with the table tag.

datatable从serverside获取数据

The datatable gets the data from serverside

所有返回和显示的数据,分页,过滤工作正常。

All the data returned and displayed, pagination, filtering works fine.

所以当创建所有三个实例,仅在最后一个实例上使用fnSettings()返回正确的对象,另外两个实例返回null

So when all three instances are created, using fnSettings() on only the last instance created returns the proper object, and the other two instances return null

所以使用fnData()等api方法throw错误说:TypeError:无法读取属性aoData为null,因为该数据实例的设置对象以某种方式为空

代码描述

我创建了一个名为datagrid的类,并创建了这个类的多个实例:

I have made a class called datagrid, and I create multiple instances of this class:

/**
 * 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();
};

现在在我的网页中,我创建了3个实例:

Now in my web page this is where I create the 3 instances :

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;
        }

创建所有三个实例后,只有最后一个实例有fnSettings()对象定义的休息实例对于fnSettings返回null,从而调用使用aoData(它是fnSettings()返回的对象的成员)的其他api方法,显示无法读取属性的错误aoData of null

After all three instances are created, only the last one supposedly has fnSettings() object defined rest instances return null for fnSettings and thus calling other api methods that use aoData (which is a member of the fnSettings() returned object) show the error that can't read property aoData of null

控制台预览

3个实例存储在 customergroupDatagrid salesmanDatagrid distributorDatagrid 变量

The 3 instances are stored in customergroupDatagrid, salesmanDatagrid, distributorDatagrid variables

创建customergroupDatagrid实例时

customergroupDatagrid.dataTable.fnSettings(); //返回对象

customergroupDatagrid.dataTable.fnSettings(); // returns object

创建salesmanDatagrid实例时

salesmanDatagrid.dataTable .fnSettings(); // return objects

customergroupDatagrid.dataTable.fnSettings(); //返回null

salesmanDatagrid.dataTable.fnSettings(); // returns object
customergroupDatagrid.dataTable.fnSettings(); // returns null

创建分发代码实例时

distributorDatagrid.dataTable .fnSettings(); //返回对象

salesmanDatagrid.dataTable.fnSettings(); //返回null

customergroupDatagrid.dataTable.fnSettings(); //返回null

distributorDatagrid.dataTable.fnSettings(); // returns object
salesmanDatagrid.dataTable.fnSettings(); // returns null
customergroupDatagrid.dataTable.fnSettings(); // returns null

推荐答案

我相信问题是你的表都有相同的ID。请注意,正确的HTML需要唯一的ID:
http ://www.w3.org/TR/html401/struct/global.html#h-7.5.2

I believe the problem is that your tables all have the same ID. Please note proper HTML requires unique IDs: http://www.w3.org/TR/html401/struct/global.html#h-7.5.2


id = name [CS]
This attribute assigns a name to an element. This name 
must be unique in a document.


这是两个jsfiddles。

< a href =http://jsfiddle.net/QFrz9/ =nofollow> http://jsfiddle.net/QFrz9/

Here are two jsfiddles.
http://jsfiddle.net/QFrz9/

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());

http://jsfiddle.net/mRFaP/1/

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());

第一个复制您的代码,对于两个表使用相同的ID。在第一个表创建之后,它会显示警报; fnSettings不为空。然后在下一个表创建后显示一个警报,突然,表1的fnSettings为空。第二个jsfiddle使用唯一的ids,问题消失。

The first one duplicates your code, using the same id for the two tables. It displays an alert after the first table is created; fnSettings is not null. Then it displays an alert after the next table is created, and suddenly the fnSettings of table 1 is null. The second jsfiddle uses unique ids, and the problem disappears.

也许你的表id可以是div ID和grid的组合,例如div1grid,div2grid等然后,您将使用domContainerSelector +'grid'而不是'#grid'。

Perhaps your table id could be a combination of the div ID and "grid", e.g., div1grid, div2grid etc. Then you would use domContainerSelector + 'grid' instead of ' #grid'.

bqb

这篇关于使用多个jquery datatable实例时,aoData为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆