具有不同列数的数据表

Posted

技术标签:

【中文标题】具有不同列数的数据表【英文标题】:DataTables with different number of columns 【发布时间】:2014-12-16 07:23:41 【问题描述】:

我正在使用 ajax 加载数据并在我的 DataTable 中动态生成列名。我的 DataTable 有不同的列数,具体取决于用户的选择。(有一个下拉列表)。

例如,下拉列表中有 Southern ProvinceNorthern Province 两个选项。 Southern Province 表有 4 列,Northern Province 表有 6 列。

场景 1

第一个用户选择 Southern Province,它有 4 列。然后它会生成没有错误的表格,但是之后如果用户选择有6列的Northern Province,则不会生成表格并且js控制台打印错误如下。

Uncaught TypeError: Cannot read property 'style' of undefined jquery.dataTables.js:3828

场景 2

第一个用户选择 Northern Province,它有 6 列。然后它会生成没有错误的表格,但之后如果用户选择有4列的Southern Province,则表格不会生成并且js控制台打印错误如下。

Uncaught TypeError: Cannot read property 'mData' of undefined jquery.dataTables.js:6122

但如果两个表的列数相同,则两个表都会生成而不会出错。

我该如何解决这个问题?

这是 JS 代码

jQuery(document)
.ready(
function() 
    $('#province-list').change(
            function() 
                var prov = $(this).val();
                if (prov == "sp") 
                    make_SP();
                 else if (prov == "np") 
                    make_NP();
                
            );
    function make_SP() 
    $("#dataTables-res_item")
    .dataTable(
    
        "bDestroy" : true,
        "bProcessing" : false,
        "bServerSide" : true,
        "sAjaxSource" : "/province_list_view?p_name=sp",
        "aoColumns" : [
                
                    "mData" : "result_date",
                    "sTitle" : "Result Date"
                ,
                
                    "mData" : "result_day",
                    "sTitle" : "Result Day"
                ,
                
                    "mData" : "draw_number",
                    "sTitle" : "Draw Number"
                ,
                
                    "mData" : "draw_time",
                    "sTitle" : "Draw Time"
                 ],
        "order" : [ [ 0, "desc" ] ]
        );
    ;                  
    function make_NP() 
        $("#dataTables-res_item")
        .dataTable(
        
            "bDestroy" : true,
            "bProcessing" : false,
            "bServerSide" : true,
            "sAjaxSource" : "/province_list_view?p_name=np",
            "aoColumns" : [
                    
                        "mData" : "result_date",
                        "sTitle" : "Result Date"
                    ,
                    
                        "mData" : "result_day",
                        "sTitle" : "Result Day"
                    ,
                    
                        "mData" : "draw_number",
                        "sTitle" : "Draw Number"
                    ,
                    
                        "mData" : "draw_time",
                        "sTitle" : "Draw Time"
                    ,
                    
                        "mData" : "draw_place",
                        "sTitle" : "Draw Place"
                    ,
                    
                        "mData" : "draw_person",
                        "sTitle" : "Agent"
                     ],
            "order" : [ [ 0, "desc" ] ]
        );
    ;
);

【问题讨论】:

制作小提琴并告诉我们 在调用 make_SP() 函数破坏数据表之前尝试一次。 @Gowri 我该怎么做?我用"bDestroy" : true。但它不起作用。 @Bishan 一般要销毁表var table = $('#tabid').DataTable(); table.destroy(); @Gowri 尝试了您的解决方案并得到 js 错误为 Uncaught TypeError: Cannot read property 'aDataSort' of undefined jquery.dataTables.js:4160 【参考方案1】:

当我的更新数据与以前的数据相比列数不同时,我遇到了同样的问题。这个方法真的很简单!列数发生变化的场景中,Destroy function$("#datatable").empty(); 一起工作。因此,在重新加载数据之前,您的代码将包含以下几行:

if (dataTableObject)  // Check if DataTable has been previously created and therefore needs to be flushed

    dataTableObject.fnDestroy(); // destroy the dataTableObject
    // For new version use table.destroy();
    $('#' + DataTableDivID).empty(); // Empty the DOM element which contained DataTable
    // The line above is needed if number of columns change in the Data
    
// DataTable data loading/reloading codes comes here

总的来说,您的代码可能如下所示:

if(dataTableObject)  // Check if table object exists and needs to be flushed
    dataTableObject.fnDestroy(); // For new version use table.destroy();
    $('#myTable').empty(); // empty in case the columns change


var data = (province=='sp') ? sp : np;
var columns = (province=='sp') ? spColumns : npColumns;

dataTableObject = $('#myTable').DataTable(
        columns: columns,
        data:    data
    );

【讨论】:

我已将您的解决方案作为评论发布到datatables.net/manual/tech-notes/3#destroy。 (目前仍在等待审核)。 我刚才为我的一个项目解决这个问题的解决方案与这个非常相似,除了我无法检查它是否是一个数据表工作,所以我将它包装在 <div id='tablewrapper'>并检查了if (table.parent().attr('id') != 'tablewrapper')。这种方法的好处是它不依赖于正在使用的数据表版本中的函数名称。【参考方案2】:

我认为最安全的方法是完全删除表,然后在重新初始化之前将其重新插入 DOM。在我看来,dataTables 并没有完全删除所有生成的内容,这就是发生错误的原因(出于不同的原因)。从理论上讲,它应该或多或少地像上面那样工作,但事实并非如此。考虑这个解决方案:

[下面的演示链接中的完整源代码]

var dataTable,
    domTable, 
    htmlTable = '<table id="example"><tbody></tbody></table>';

function initDataTable(province) 
    if ($.fn.DataTable.fnIsDataTable(domTable)) 
        dataTable.fnDestroy(true);
        $('body').append(htmlTable);
     
    var data = (province=='sp') ? sp : np;
    var columns = (province=='sp') ? spColumns : npColumns;    
    dataTable = $("#example").dataTable(
        aaData : data,
        aoColumns : columns
        /* other options here */
    );        
    domTable = document.getElementById('example');


$('#province-list').change(function() 
    var prov = $(this).val();
    initDataTable(prov);
);

这行得通。查看演示 -> http://jsfiddle.net/gss4a17t/ 基本上和OP里是一样的,只是我没有针对不同的省份有不同的功能,而是针对不同的省份做了不同的aoColumns等等。而不是依赖bDestroy,我用dataTable.fnDestroy(true)(DOM 和dataTables注入)删除了整个&lt;table&gt;,然后在重新初始化dataTable之前重新插入&lt;table&gt;-skeleton。

我不知道这是否适合 OP 的需要,但我会这样做。它对未来的更改更加灵活,aoColumns-objects 可以从脚本自动生成或通过 AJAX 从服务器实现(例如,如果您想为不同的语言设置不同的标题)。 “腰带和背带”:)

【讨论】:

感谢您的回答。我没什么问题。我通过调用 url 获取数据。我如何将它与aaData 一起使用? 嘿@Bishan,感谢您的支持! :) 我认为应该是一样的,你从服务器获取的数据与我猜的小提琴中的 JSON 格式相同吗?然后获取数据,将结果插入为aaData。因此,在 AJAX 的成功处理程序中调用“initDataTable”或任何您命名的名称。我无法在小提琴中重现这一点,但应该是这样的。 谢谢@davidkonrad,我用sAjaxSource 代替了aaData。现在它正在工作。 :)【参考方案3】:

上面有很好的解决方案,但是在遇到这个问题之后,活力仍然在我脑海中敲响。我想分享这个,而不是 js 中的导出。所以请发表评论。

function genericAjaxCall(url, tableId, _header, _dataMapping, isData,
    isEditDelete) 
if (!isData) 
    $.ajax(
        url : url,
        method : "GET",
        dataType : "JSON",
        success : function(data) 
            var editDeletUrl = url.split("/");
            var dataArray = createArray(_header, data, _dataMapping, url,
                    isEditDelete)
            createListHeading(tableId, dataArray, false);
            initDT(tableId, dataArray);
        ,
        error : function(xhr) 
            console.log(xhr);
            openErrorModal("Guru", xhr.responseText);
        
    );
 else 
    var dataArray = createArray(_header, url, _dataMapping);
    console.log(dataArray);
    var finalData = dataArray + objName;
    console.log(finalData);
    createListHeading(tableId, dataArray, false);
    initDT(tableId, dataArray);
 


function createArrayWithDelete(_header, data, _dataMapping, url) 
var posts = ;
posts.postDT = []
for (var i = 0; i < data.length; i++) 
    var jsonData = ;

    for (var j = 0; j < _header.length; j++) 
        if (_dataMapping[j].indexOf('.') !== -1) 
            var parts = _dataMapping[j].split(".");
            if (String(data[i][parts[0]][parts[1]]).indexOf('*') !== -1) 
                jsonData[_header[j]] = data[i][parts[0]][parts[1]].bold()
                        .replace("*", "");
             else 
                jsonData[_header[j]] = data[i][parts[0]][parts[1]];
            

         else 

            if (String(data[i][_dataMapping[j]]).indexOf('*') !== -1) 
                jsonData[_header[j]] = data[i][_dataMapping[j]].bold()
                        .replace("*", "");
             else 
                jsonData[_header[j]] = data[i][_dataMapping[j]];
            
        
    

    if (_header[_header.length - 1]) 
        jsonData["Action"] = deleteOnly(url,
                data[i][_dataMapping[_dataMapping.length - 1]]);
    

    posts.postDT.push(jsonData);
   
   return posts.postDT;
  

function createListHeading(tableId, data, isAction) 
var posts = 
    post : []
;
$.each(data[0], function(key, value) 
    posts.post.push(
        "mDataProp" : key,
        "sTitle" : key
        /* "sType" : "string" */
    );
   );
  cols = posts.post

 

function initDT(tableId, results) 
// Construct the measurement table
data_table = $('#' + tableId).DataTable(
    "iDisplayLength" : 10,
    scrollCollapse : true,
    "aaSorting" : [],
    "aaData" : results,
    "aoColumns" : cols
);
$('#' + tableId).DataTable().columns.adjust();

这就是我的称呼,

$(function() 
    var header = [ "H1", "H2", "H3", "H4" ];
    var dataMapping = [ "d1", "d2", "d3", "d3" ];

    genericAjaxCall("ajaxurlWhichreturnJSON", "tableId", header, dataMapping,
            false, true);
);

这里 d1, d2... 是您的 ajax 响应的关键。现在我们不必担心用户选择哪个值。注意:这不是这个问题的直接解决方案,而是比喻性的

【讨论】:

【参考方案4】:

我知道这是一个老问题,但由于我花了几个小时试图用 DataTables 1.10.18 解决它,我发布它是希望它对某人有所帮助。我使用 javascript 数组作为数据源,使用 jQuery 1.12.4。它基于@davidkonrad 的回答。

HTML:

select province
<select id="province-list">
  <option value="sp">sp</option>
  <option value="np">np</option>    
</select>    
<br><br>

<div id="table-container">
    <table id="example" class="display"></table>
</div>

JS:

var sp = [
  [ 'col1', 'col2'] ,
  [ 'col11', 'col22']    
];

var np = [
  [ 'col1', 'col2', 'col3', 'col4' ],
  [ 'col11', 'col22', 'col33', 'col44' ]
];

var spColumns = [
   title : "column1" ,
   title : "column2" 
];

var npColumns = [
   title : "column1" ,
   title : "column2" ,
   title : "column3" ,
   title : "column4"       
];

var dataTable,
  htmlTable = '<table id="example" class="display"></table>';

function initDataTable(province) 
  if ($.fn.DataTable.isDataTable('#example')) 
    dataTable = $('#example').DataTable();
    dataTable.destroy(true);
    $('#table-container').empty();
    $('#table-container').append(htmlTable);
   
  var data = (province=='sp') ? sp : np;
  var columns = (province=='sp') ? spColumns : npColumns;  

  dataTable = $('#example').DataTable( 
    "data": data,
    "columns": columns
   );


$(document).ready(function() 
  initDataTable('sp');

  $('#province-list').change(function() 
    var prov = $(this).val();
    initDataTable(prov);
  );

);

【讨论】:

以上是关于具有不同列数的数据表的主要内容,如果未能解决你的问题,请参考以下文章

pandas - 追加具有不同列数的新行

Dataprep将具有不同列数的文件导入数据集

将具有未知列数的数据导入R?

如何在 R 中读取具有不同列数的 CSV 文件

Postgresql从具有不同列数的2个表中选择多条记录

SQL Server中具有不同列数的多个查询的联合结果