DataTables с различным количеством столбцов

я загружаю данные с помощью ajax и динамически генерирую имена столбцов в моем DataTable. Мой DataTable имеет различное количество столбцов, в зависимости от выбора пользователем.(Там выпадающий список).

например, есть 2 варианта в раскрывающемся списке как Южная Провинция и Северные Провинции. Южная Провинция таблица имеет 4 столбца и Северные Провинции таблица имеет 6 колонок.

Сценарий 1

первый пользователь выберите Южная Провинция, который имеет 4 колонны. Затем он генерирует таблицу без ошибок, но после этого, если пользователь выбирает Северные Провинции который имеет 6 столбцов, таблица не генерирует и ошибка печати консоли JS, как показано ниже.

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

Сценарий 2

первый пользователь выберите Северные Провинции, который имеет 6 столбцов. Затем он генерирует таблица без ошибок, но после этого, если пользователь выбирает Южная Провинция который имеет 4 столбца, таблица не генерирует и ошибка печати консоли 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" ] ]
        });
    };
});

3 ответов


Я думаю, что самый безопасный способ-полностью удалить таблицу, а затем повторно вставить ее в 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, Я удаляю весь <table> С dataTable.fnDestroy(true) (оба DOM и и инъекции dataTables), а затем повторно вставляет <table>-скелет перед reinitialising объект DataTable.

Я не знаю, если это адаптируется к потребностям OP, но именно так я бы это сделал. Он более гибок для будущих изменений, и aoColumns-объекты могут быть автоматически из скрипта или добиться от сервера через AJAX (если вы хотите иметь разные названия для разных языков, например). "Ремень и брацес" :)


я столкнулся с той же проблемой, когда мои обновленные данные были разное количество столбцов чем предыдущие данные. Рецепт действительно просто! в сценарии, когда есть изменение количества столбцов, 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
    });

там есть хорошее решение, но после того, как столкнулся с этим вопросом, динамизм все еще звонит в колокол на моем уме. я хотел бы поделиться этим , а не экспортировать в 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. Теперь нам не нужно беспокоиться о том, какое значение выбирает пользователь. Примечание : это не прямое решение этого вопроса, но это образное