I am using datatables along with highcharts. My goal is when user clicks on buttons 2023, 2022 and ABC button, the charts should reload to provide an animation effect to the user. When I do this, I am running into following issue:
Here is my test case: https://codepen.io/Shawnny-Tandon/pen/bGJeOev
If I change my code from divID to tableID, it works. However, the chart just loads instead of providing animation. Any solution to this?
$('#' + divId).DataTable().destroy(); to $('#' + tableId).DataTable().destroy();
function initializeDataTable(tableSelector) {
$(tableSelector).DataTable({
searching: false,
responsive: true,
lengthChange: false,
ordering: false,
info: false,
paging: false,
initComplete: function (settings, json) {
let api = new $.fn.dataTable.Api(settings);
var headers = api.columns().header().toArray();
headers.forEach(function (heading, index) {
if (index > 0 && index < headers.length) {
categories.push($(heading).html());
}
});
let rows = api.rows().data().toArray();
rows.forEach(function (row) {
group = {
name: '',
data: []
};
row.forEach(function (cell, idx) {
if (idx == 0) {
group.name = cell;
} else if (idx < row.length) {
group.data.push(parseFloat(cell.replace(/,/g, '')));
}
});
allSeriesData.push(group);
});
}
});
}
$(document).ready(function () {
if (typeof Highcharts !== 'undefined') {
initializeChart('demo-output', '#example1', 'test 1');
initializeChart('demo-output2', '#example', 'test 2');
var allSeriesData = [];
var categories = [];
$('#example2').data('scrollX-custom', true);
if (!$.fn.DataTable.isDataTable("#example2 table")) {
initializeDataTable("#example2 table");
}
Highcharts.setOptions({
lang: {
thousandsSep: ','
}
});
var myChart = Highcharts.chart("chart-A", {
chart: {
type: "column",
borderColor: 'lightgray',
borderWidth: 1,
marginTop: 50
},
tooltip: {
headerFormat: '{point.key}<br/>',
pointFormat: '{series.name}: <b>{point.y:.1f}%</b>'
},
legend: {
symbolRadius: 0,
itemStyle: {
color: '#000000',
fontSize: '16px'
}
},
colors: ['#003489', '#ED7D31', '#A5A5A5', '#FFC000', '#5B9BD5'],
credits: {
enabled: false
},
title: {
text: "test3"
},
xAxis: {
categories: categories,
labels: {
style: {
fontWeight: '600',
fontSize: '16px',
color: '#000000'
}
}
},
yAxis: {
title: false,
tickInterval: 10,
max: 60,
labels: {
formatter: function () {
return Highcharts.numberFormat(this.value, 0);
},
style: {
fontWeight: '600',
fontSize: '16px',
color: '#000000'
}
}
},
series: allSeriesData
});
$('#trend').on('click', function () {
$('#chart2').hide();
$('#chart1').hide();
$('#chart3').show();
reloadChart('chart-A', '#example2', 'Top Seven test Award Trends', 'chart-A', 'column');
$('.usa-button').removeClass('active');
$(this).addClass('active');
});
$('.usa-button').on('click', function () {
var buttonId = $(this).attr('id');
if (buttonId === 'previous') {
$('#chart2').show();
$('#chart1').hide();
$('#chart3').hide();
reloadChart('demo-output2', '#example', 'test Awards by NAICS Codes, FY 2022', 'demo-output2', 'pie');
} else if (buttonId === 'trend') {
} else {
$('#chart2').hide();
$('#chart1').show();
$('#chart3').hide();
reloadChart('demo-output', '#example1', 'test Awards by NAICS Codes, FY 2023', 'demo-output', 'pie');
}
$('.usa-button').removeClass('active');
$(this).addClass('active');
});
$('#current').addClass('active');
}
});
function initializeChart(chartId, tableId, chartTitle) {
const table = new DataTable(tableId, {
searching: false,
info: true,
paging: false,
sort: false
});
const chart = Highcharts.chart(chartId, {
chart: {
type: 'pie',
styledMode: false
},
title: {
text: chartTitle
},
colors: ['#1a4480', '#e52207', '#e66f0e', '#ffbe2e', '#fee685', '#538200', '#04c585', '#97d4ea', '#009ec1', '#0076d6', '#adadad', '#8168b3', '#d72d79', '#f2938c'],
tooltip: {
pointFormat: '</b> {point.y:.1f}%'
},
series: [{
data: chartData(table)
}],
credits: {
enabled: false
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
series: {
animation: {
duration: 2000
}
},
dataLabels: {
enabled: true,
format: '{point.y:.1f}%'
},
showInLegend: true
}
}
});
table.on('draw', function () {
chart.series[0].setData(chartData(table));
});
function chartData(table) {
var data = [];
table.rows().every(function () {
var row = this.data();
data.push({
name: row[0],
y: parseFloat(row[1])
});
});
return data;
}
}
function reloadChart(chartId, tableId, chartTitle, divId, chartType) {
$('#' + divId).DataTable().destroy();
const table = new DataTable(tableId, {
searching: false,
info: true,
paging: false,
sort: false
});
const chart = Highcharts.chart(chartId, {
chart: {
type: chartType,
styledMode: false
},
title: {
text: chartTitle
},
colors: ['#1a4480', '#e52207', '#e66f0e', '#ffbe2e', '#fee685', '#538200', '#04c585', '#97d4ea', '#009ec1', '#0076d6', '#adadad', '#8168b3', '#d72d79', '#f2938c'],
tooltip: {
pointFormat: '</b> {point.y:.1f}%'
},
series: [{
data: chartData(table)
}],
credits: {
enabled: false
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
series: {
animation: {
duration: 2000
}
},
dataLabels: {
enabled: true,
format: '{point.y:.1f}%'
},
showInLegend: true
}
}
});
table.on('draw', function () {
chart.series[0].setData(chartData(table), true);
});
function chartData(table) {
var data = [];
table.rows().every(function () {
var row = this.data();
data.push({
name: row[0],
y: parseFloat(row[1])
});
});
return data;
}
}
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<link href="https://nightly.datatables.net/css/dataTables.dataTables.css" rel="stylesheet" type="text/css" />
<script src="https://nightly.datatables.net/js/dataTables.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
</head>
<body>
<div class="ar-controls grid-row tablet:flex-justify-start">
<div class="tablet:grid-col-auto margin-bottom-205"><button id="current" class="usa-button usa-button--outline" title="Select to see related information below">2023</button> <button id="previous" class="usa-button usa-button--outline" title="Select to see related information below">2022</button> <button id="trend" class="usa-button usa-button--outline" title="Select to see related information below">ABC</button></div>
</div>
<div id="chart1">
<div id="demo-output" class="chart-display" style=" margin-bottom: 2em; height: 500px; border: solid 1px lightgray;"></div>
<table id="example1" class="display" style=" width: 100%;"><thead>
<tr>
<th scope="col">2023</th>
<th scope="col">Percent</th>
</tr>
</thead>
<tr>
<td scope="row">A</td>
<td>45.9%</td>
</tr>
<tr>
<td scope="row">B</td>
<td>22.0%</td>
</tr>
<tr>
<td scope="row">C</td>
<td>13.6%</td>
</tr>
</table>
</div>
<div id="chart2" style=" display: none;">
<div id="demo-output2" class="chart-display2" style=" margin-bottom: 2em; height: 680px; border: solid 1px lightgray;"></div>
<table id="example" class="display" style=" width: 100%;"><thead>
<tr>
<th scope="col">2022</th>
<th scope="col">Percent</th>
</tr>
</thead>
<tr>
<td>D</td>
<td>51.90%</td>
</tr>
<tr>
<td>E</td>
<td>18.60%</td>
</tr>
</table>
</div>
<div id="chart3" style=" display: none;">
<div id="chart-A" style=" width: 100%; height: 500px;"></div>
<table class="row-border stripe no-footer cell-border padding-top-5" id="example2" style=" width: 100%;"><thead>
<tr>
<th>Year</th>
<th>column1</th>
<th>column2</th>
<th>column3</th>
<th>column4/th>
<th>column5</th>
<th>column6</th>
<th>column7</th>
</tr>
</thead>
<tr>
<td scope="row" style=" text-align: left; white-space: nowrap;">FY19</td>
<td style=" text-align: left;">42.7%</td>
<td style=" text-align: left;">17.3%</td>
<td style=" text-align: left;">9.5%</td>
<td style=" text-align: left;">3.5%</td>
<td style=" text-align: left;">3.4%</td>
<td style=" text-align: left;">2.9%</td>
<td style=" text-align: left;">2.2%</td>
</tr>
</table>
</div>
</div>
Background
With your current code, you actually get a warning and an error.
The warning occurs when you try to destroy()
the DataTable:
DataTables warning: Non-table node initialisation (DIV). For more information about this error, please see https://datatables.net/tn/2
As explained in the technical note link:
DataTables will initialise only on an HTML table element.
As you note in your question, this is why when you change divId
to tableId
the warning disappears.
Secondly, because the table was not destroyed, you then get a subsequent error because the code tries to initialize a table which already exists:
Cannot reinitialise DataTable.
One Solution
One simple solution is to do the following:
Remove the line of code which attempts to destroy the table:
// $('#' + divId).DataTable().destroy(); REMOVE THIS LINE
Use the retrieve: true
option (the default is false
).
This option works as follows:
if the table has already been initialised, this parameter will cause DataTables to simply return the object that has already been set up
This assumes your table's existing initialization parameters can be re-used.
In your case, the resulting code is this:
function initializeDataTable(tableSelector) {
$(tableSelector).DataTable({
searching: false,
responsive: true,
lengthChange: false,
ordering: false,
info: false,
paging: false,
initComplete: function(settings, json) {
let api = new $.fn.dataTable.Api(settings);
var headers = api.columns().header().toArray();
headers.forEach(function(heading, index) {
if (index > 0 && index < headers.length) {
categories.push($(heading).html());
}
});
let rows = api.rows().data().toArray();
rows.forEach(function(row) {
group = {
name: '',
data: []
};
row.forEach(function(cell, idx) {
if (idx == 0) {
group.name = cell;
} else if (idx < row.length) {
group.data.push(parseFloat(cell.replace(/,/g, '')));
}
});
allSeriesData.push(group);
});
}
});
}
$(document).ready(function() {
if (typeof Highcharts !== 'undefined') {
initializeChart('demo-output', '#example1', 'test 1');
initializeChart('demo-output2', '#example', 'test 2');
var allSeriesData = [];
var categories = [];
$('#example2').data('scrollX-custom', true);
if (!$.fn.DataTable.isDataTable("#example2 table")) {
initializeDataTable("#example2 table");
}
Highcharts.setOptions({
lang: {
thousandsSep: ','
}
});
var myChart = Highcharts.chart("chart-A", {
chart: {
type: "column",
borderColor: 'lightgray',
borderWidth: 1,
marginTop: 50
},
tooltip: {
headerFormat: '{point.key}<br/>',
pointFormat: '{series.name}: <b>{point.y:.1f}%</b>'
},
legend: {
symbolRadius: 0,
itemStyle: {
color: '#000000',
fontSize: '16px'
}
},
colors: ['#003489', '#ED7D31', '#A5A5A5', '#FFC000', '#5B9BD5'],
credits: {
enabled: false
},
title: {
text: "test3"
},
xAxis: {
categories: categories,
labels: {
style: {
fontWeight: '600',
fontSize: '16px',
color: '#000000'
}
}
},
yAxis: {
title: false,
tickInterval: 10,
max: 60,
labels: {
formatter: function() {
return Highcharts.numberFormat(this.value, 0);
},
style: {
fontWeight: '600',
fontSize: '16px',
color: '#000000'
}
}
},
series: allSeriesData
});
$('#trend').on('click', function() {
$('#chart2').hide();
$('#chart1').hide();
$('#chart3').show();
reloadChart('chart-A', '#example2', 'Top Seven test Award Trends', 'chart-A', 'column');
$('.usa-button').removeClass('active');
$(this).addClass('active');
});
$('.usa-button').on('click', function() {
var buttonId = $(this).attr('id');
if (buttonId === 'previous') {
$('#chart2').show();
$('#chart1').hide();
$('#chart3').hide();
reloadChart('demo-output2', '#example', 'test Awards by NAICS Codes, FY 2022', 'demo-output2', 'pie');
} else if (buttonId === 'trend') {} else {
$('#chart2').hide();
$('#chart1').show();
$('#chart3').hide();
reloadChart('demo-output', '#example1', 'test Awards by NAICS Codes, FY 2023', 'demo-output', 'pie');
}
$('.usa-button').removeClass('active');
$(this).addClass('active');
});
$('#current').addClass('active');
}
});
function initializeChart(chartId, tableId, chartTitle) {
const table = new DataTable(tableId, {
searching: false,
info: true,
paging: false,
sort: false
});
const chart = Highcharts.chart(chartId, {
chart: {
type: 'pie',
styledMode: false
},
title: {
text: chartTitle
},
colors: ['#1a4480', '#e52207', '#e66f0e', '#ffbe2e', '#fee685', '#538200', '#04c585', '#97d4ea', '#009ec1', '#0076d6', '#adadad', '#8168b3', '#d72d79', '#f2938c'],
tooltip: {
pointFormat: '</b> {point.y:.1f}%'
},
series: [{
data: chartData(table)
}],
credits: {
enabled: false
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
series: {
animation: {
duration: 2000
}
},
dataLabels: {
enabled: true,
format: '{point.y:.1f}%'
},
showInLegend: true
}
}
});
table.on('draw', function() {
chart.series[0].setData(chartData(table));
});
function chartData(table) {
var data = [];
table.rows().every(function() {
var row = this.data();
data.push({
name: row[0],
y: parseFloat(row[1])
});
});
return data;
}
}
function reloadChart(chartId, tableId, chartTitle, divId, chartType) {
//$('#' + divId).DataTable().destroy( true );
const table = new DataTable(tableId, {
searching: false,
info: true,
paging: false,
sort: false,
retrieve: true
});
const chart = Highcharts.chart(chartId, {
chart: {
type: chartType,
styledMode: false
},
title: {
text: chartTitle
},
colors: ['#1a4480', '#e52207', '#e66f0e', '#ffbe2e', '#fee685', '#538200', '#04c585', '#97d4ea', '#009ec1', '#0076d6', '#adadad', '#8168b3', '#d72d79', '#f2938c'],
tooltip: {
pointFormat: '</b> {point.y:.1f}%'
},
series: [{
data: chartData(table)
}],
credits: {
enabled: false
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
series: {
animation: {
duration: 2000
}
},
dataLabels: {
enabled: true,
format: '{point.y:.1f}%'
},
showInLegend: true
}
}
});
table.on('draw', function() {
chart.series[0].setData(chartData(table), true);
});
function chartData(table) {
var data = [];
table.rows().every(function() {
var row = this.data();
data.push({
name: row[0],
y: parseFloat(row[1])
});
});
return data;
}
}
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<link href="https://nightly.datatables.net/css/dataTables.dataTables.css" rel="stylesheet" type="text/css" />
<script src="https://nightly.datatables.net/js/dataTables.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
</head>
<body>
<div class="ar-controls grid-row tablet:flex-justify-start">
<div class="tablet:grid-col-auto margin-bottom-205"><button id="current" class="usa-button usa-button--outline" title="Select to see related information below">2023</button> <button id="previous" class="usa-button usa-button--outline" title="Select to see related information below">2022</button>
<button
id="trend" class="usa-button usa-button--outline" title="Select to see related information below">ABC</button>
</div>
</div>
<div id="chart1">
<div id="demo-output" class="chart-display" style=" margin-bottom: 2em; height: 500px; border: solid 1px lightgray;"></div>
<table id="example1" class="display" style=" width: 100%;">
<thead>
<tr>
<th scope="col">2023</th>
<th scope="col">Percent</th>
</tr>
</thead>
<tr>
<td scope="row">A</td>
<td>45.9%</td>
</tr>
<tr>
<td scope="row">B</td>
<td>22.0%</td>
</tr>
<tr>
<td scope="row">C</td>
<td>13.6%</td>
</tr>
</table>
</div>
<div id="chart2" style=" display: none;">
<div id="demo-output2" class="chart-display2" style=" margin-bottom: 2em; height: 680px; border: solid 1px lightgray;"></div>
<table id="example" class="display" style=" width: 100%;">
<thead>
<tr>
<th scope="col">2022</th>
<th scope="col">Percent</th>
</tr>
</thead>
<tr>
<td>D</td>
<td>51.90%</td>
</tr>
<tr>
<td>E</td>
<td>18.60%</td>
</tr>
</table>
</div>
<div id="chart3" style=" display: none;">
<div id="chart-A" style=" width: 100%; height: 500px;"></div>
<table class="row-border stripe no-footer cell-border padding-top-5" id="example2" style=" width: 100%;">
<thead>
<tr>
<th>Year</th>
<th>column1</th>
<th>column2</th>
<th>column3</th>
<th>column4/th>
<th>column5</th>
<th>column6</th>
<th>column7</th>
</tr>
</thead>
<tr>
<td scope="row" style=" text-align: left; white-space: nowrap;">FY19</td>
<td style=" text-align: left;">42.7%</td>
<td style=" text-align: left;">17.3%</td>
<td style=" text-align: left;">9.5%</td>
<td style=" text-align: left;">3.5%</td>
<td style=" text-align: left;">3.4%</td>
<td style=" text-align: left;">2.9%</td>
<td style=" text-align: left;">2.2%</td>
</tr>
</table>
</div>
</div>
</body>
</html>