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