javascript - aoData is null when using multiple instances of jquery datatable -


scenario:

on webpage have 3 divs contain table tags.

there 3 buttons, clicking on each button creates instance of datatable on particular div table tag.

the datatable gets data serverside

all data returned , displayed, pagination, filtering works fine.

so when 3 instances created, using fnsettings() on last instance created returns proper object, , other 2 instances return null

so using fndata() etc api methods throw error saying : "typeerror: cannot read property 'aodata' of null" because settings object of datatable instance somehow null

code description

i have made class called datagrid, , create multiple instances of class:

/**  * datagrid class contains methods , properties in controllling , manipulating multiple instances of datagrid class  *   * function constructor datagrid class  *   * @param {string} domcontainerselector dom selector of element containing datagrid  * @param {array} columns definitions of columns of datagrid  * @param {string} ajaxsource url jqgrid use request data  * @param {object} configurationparameters configuration parameters used jqgrid , datagrid instance. suppoted configuration parameters are: initialcachesize, idisplaylength, sscrolly, bpaginate, bfilter, sdom, bsort  * @param {object} uicallback contains callback functions used when server request in progress , after completion of request. used 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={};             }     };     /**      * method returns row selected user      *       * @return {object} row object containing columns properties      */     this.getselectedrow = function()     {         var allrows = this.datatable.fngetnodes();         (i = 0; < allrows.length; i++)             if ($(allrows[i]).hasclass('row_selected'))                 return this.datatable.fngetdata(allrows[i]);     };     this.getpostdatavalue=function(postdata, key){         (var i=0;i<postdata.length;i++)         {             if (postdata[i].name == key)             {                 return postdata[i].value;             }         }         return null;     };     this.setpostdatavalue=function(postdata, key, value){         (var i=0; i<postdata.length;i++)         {             if (postdata[i].name == key)             {                 postdata[i].value = value;             }         }     };     this.setpostdatafiltervalues=function(postdata){         (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 cache because datagrid in dirty state         this.columns[index].ssearch=value;         if (evt.keycode == 13) this.datatable.fnfilter();     };     /**      * method acts general button handler when operation in progress      */     this.busystatebuttonhandler=function()     {         ui.showmessage("another operation in progress. please wait operation complete");     };     /**      * method sets event handlers 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()});     };     /**      * method sets appropriate event handlers 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);     };     /**      * method enables column specific filtering      *       * methods adds filtering capability columns definitions indicate 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 = "";         (i = 0; < 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);             });         }     };     /**      * method enables single selection on rows of 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 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;         }     };     /**      * method interfaces backend end controller      *       * method called when grid initiates operation requires server side processing      *       * @param {string} ssource source url used xhr request      * @param {array} aodata contains parameters sent datatable forwarded backend controller      * @param {function} fncallback callback function of datatable gets executed render grid 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);         }     };     /**      * method destroys datatable instance      *       * remove contents parent div , reinserts simple table tag on fresh datatable reinitialized      */     this.destroy = function()     {         $(this.domrowselector).die("click");         $(this.domgridwrapperselector).remove();//remove datatable generated dynamic code         $(this.domcontainerselector).prepend("<table id='grid'></table>");     };     /**      * datatable property holds instance of 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 0 of 0"         },         "aocolumns": this.columns     });      this.init=function(){         this.enableselection();         this.enablecolumnfilter();         this.seteventhandlers();     };     this.init(); }; 

now in web page create 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;         } 

after 3 instances created, last 1 supposedly has fnsettings() object defined rest instances return null fnsettings , calling other api methods use aodata (which member of fnsettings() returned object) show error can't read property aodata of null

console preview:

the 3 instances stored in customergroupdatagrid, salesmandatagrid, distributordatagrid variables

when customergroupdatagrid instance created

customergroupdatagrid.datatable.fnsettings(); // returns object

when salesmandatagrid instance created

salesmandatagrid.datatable.fnsettings(); // returns object
customergroupdatagrid.datatable.fnsettings(); // returns null

when distributordatagrid instance created

distributordatagrid.datatable.fnsettings(); // returns object
salesmandatagrid.datatable.fnsettings(); // returns null
customergroupdatagrid.datatable.fnsettings(); // returns null

i believe problem tables have 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] attribute assigns name element. name  must unique in document. 

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

the first 1 duplicates code, using same id 2 tables. displays alert after first table created; fnsettings not null. displays alert after next table created, , fnsettings of table 1 null. second jsfiddle uses unique ids, , problem disappears.

perhaps table id combination of div id , "grid", e.g., div1grid, div2grid etc. use domcontainerselector + 'grid' instead of ' #grid'.

bqb


Comments

Popular posts from this blog

linux - xterm copying to CLIPBOARD using copy-selection causes automatic updating of CLIPBOARD upon mouse selection -

c++ - qgraphicsview horizontal scrolling always has a vertical delta -