Data Tables and Nested tables - javascript

I am having real trouble understanding what is happening with Data Tables. I create a DataTable as follows
var dTable = $('#sessionReport').dataTable({
"bInfo" : false,
"bFilter" : false,
"aaData" : data,
"bDestroy" : true,
"fnFooterCallback" : function(nRow, aaData, iStart, iEnd, aiDisplay){
var totalAttendees = 0;
var totalTime = 0;
var avgSatisfaction = 0;
for(var i=0; i<aaData.length; i++){
avgSatisfaction = avgSatisfaction + ((aaData[i][7]*1)+3*1)/aaData.length; // range is from -2 to + 2; have added 3 to each result to make range of positive numbers only
totalAttendees = totalAttendees + aaData[i][5]*1;
startTime = new Date(aaData[i][0]);
endTime = new Date(aaData[i][1]);
totalTime = totalTime + (endTime - startTime)/10000;
}
//alert(secondsToString(totalTime));
//$('#tfAttendees').innerHTML = parseInt(totalAttendees);
var nCells = nRow.getElementsByTagName('th');
nCells[5].innerHTML = parseInt(totalAttendees);
nCells[7].innerHTML = parseFloat(avgSatisfaction.toFixed(2));
}
});
return dTable;
My data is formatted like this:
[ 0: "2012-10-24 09:43:03"
1: "2012-10-24 09:49:47"
2: "5002028"
3: "Eamonn"
4: "Dannys Memories"
5: "7"
6: ""
7: "0" ],
[O:....],
But I run into problems when I want to add a column with an icon to each row like in this solution
http://datatables.net/blog/Drill-down_rows
I have tried using aoColumns and aoColumnsdef. But not really sure how. My problem is that table html is being built by the data. So if there are only 7 items in the data array there will only be 7 columns in my Html Table. How can I add an eighth column. I want the beginning on each row to have a clickable icon.
And my html looks like this...
<table id="sessionReport" class="table table-striped fTable">
<thead>
<tr>
<td>Start Session</td>
<td>End Session</td>
<td>Session Id</td>
<td>Facilitator</td>
<td>Group Name</td>
<td>No. Attendees</td>
<td>Assistant</td>
<td>Satisfaction</td>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<th id="tfStartSession">
Total Hours
</th>
<th id="tfEndSession">
</th>
<th id="tfSessionId">
</th>
<th id="tfFacilitator">
</th>
<th id="tfGroupName">
TOTAL ATTENDEES :
</th>
<th id="tfAttendees">
</th>
<th id="tfAssistant">
AVG SATISFACTION :
</th>
<th id="tfSatisfaction">
</th>
</tr>
</tfoot>
</table>
Any ideas. I'm a bit stumped by DataTables documentation and they don't seem to provide any usage examples of either aoColumns or aoColumnsDef.
Many thanks

Related

How to prevent column total Count from display on component.html?

I have field total count I need to prevent total Count from display on component.html
I already do it but not working if you can tell me how to do that ?
I display data dynamically on header column and body data with angular 7
I try using filter function below but not working
this._displayreport.GetReportDetailsPaging(this.searchData).subscribe((data: any[]) => {
this.reportdetailslist = data;
this.headerCols = Object.keys(data[0]);
this.contentBody=data.filter(item =>item != data[0].totalCount);
});
}
}
<thead>
<tr>
<th >
<ng-container *ngIf="coln != 'totalCount'">
{{coln}}
</ng-container>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let rep of contentBody">
<td *ngFor="let coln of headerCols">
<span>
{{rep[coln]}}
</span>
</td>
</tr>
<tbody>
data object represent following data as any[]
companyName: "Innovasic, Inc."
done: "0"
notImpacted: "0"
notificationDate: "2009-11-12"
offilneURL: "https://source.z2data.com/2019/1/13/8/55/47/351/662203977/21527_SPCN.PDF"
onlineURL: "N/A"
pending: "3"
reportDate: "2020-05-07"
revisionID: "272299243"
teamName: "MFG"
totalCount: 79
it solved by change my code above to
this.headerCols = Object.keys(data[0]).filter(x => x !== 'totalCount');

Transpose dynamic table from rows to columns and vice versa

config.previewData = [
{
Cartridges:27989,
Total Accounts:294,
Metrices:"MVC",
Toner Cartridges:5928,
INK Cartridges:22061
},
{
Cartridges:56511,
Total Accounts:376,
Metrices:"SMB",
Toner Cartridges:15253,
INK Cartridges:41258
},
{
Cartridges:84,500,
Total Accounts:670,
Metrices:"Grand Total",
Toner Cartridges:21,181,
INK Cartridges:63,319
},
]
and my html code like this
<table class="table table-striped">
<thead>
<tr role="row">
<th data-ng-repeat="(key, val) in config.previewData[0]">
{{ key}}
</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="row in config.previewData">
<td data-ng-repeat="column in row">
{{column}}
</td>
</tr>
</tbody>
</table>
this code will print perfect like below image
now i want to transpose this table into rows to columns and columns to rows.
Is this possible with dynamic table because my object is dynamic not fixed.
Help me if anyone knows how to do this.
After transpose table looks like this
Using the same assumptions your example codes does (i.e. config.previewData always contains at least one object, and all objects have the same properties...)
<table class="table table-striped">
<tbody>
<tr data-ng-repeat="(key, val) in config.previewData[0]">
<th>
{{ key }}
</th>
<td data-ng-repeat="row in config.previewData">
{{ row[key] }}
</td>
</tr>
</tbody>
</table>
Using reduce, you can have something like this to transpose your data, which can then be used to iterate over using ng-repeat very easily!
Example snippet (in Pure JS for simplification):
var previewData = [{
"Cartridges": 27989,
"Total Accounts": 294,
"Metrices": "MVC",
"Toner Cartridges": 5928,
"INK Cartridges": 22061
},
{
"Cartridges": 56511,
"Total Accounts": 376,
"Metrices": "SMB",
"Toner Cartridges": 15253,
"INK Cartridges": 41258
},
{
"Cartridges": 84500,
"Total Accounts": 670,
"Metrices": "Grand Total",
"Toner Cartridges": 21181,
"INK Cartridges": 63319
}
]
var transpose = previewData.reduce(function(arr, obj) {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
arr[key] = arr[key] || []
arr[key].push(obj[key])
}
}
return arr
}, {})
console.log(transpose)
this is the only (dirty) way i could think out
<tr>
<td data-ng-repeat="row in previewData">{{row['Metrices']}}</td>
</tr>
<tr>
<td data-ng-repeat="row in previewData">{{row['Total Accounts']}}</td>
</tr>
<tr>
<td data-ng-repeat="row in previewData">{{row['Toner Cartridges']}}</td>
</tr>
...... and so on
other options: Transposing JSON
If you have a 2-D array which can be logged into console by the function
tab = [[2,3,4],[-4,6,0],[1,0,9]]
console.table(tab)
You can log the transpose of it by using the following function:
function transpose_table(tab) {
let columns = tab.length;
let rows = tab[0].length;
let trans = [];
for (i=0; i<rows; i++) {
trans.push([]);
}
for (i=0; i<columns; i++) {
for (j=0; j<rows; j++) {
trans[j][i] = tab[i][j];
}
}
return trans;
}
Now run:
console.table(transpose_table(tab))

Displaying "Task" in a particular table cell depending on status. ReactJS

I ran into a problem where I need to output my task objects into a table.
I have created status columns (New, To do, In progress etc), but I have no idea how do I output my tasks into a particular table cell depending on its status and if there are going to be two task objects with the same status then for another one I would like to create a separate row so they won't both be inside the same cell.
Unfortunately, I cannot provide any code example since I've tried it so many ways and none of them worked. Here is how I do it now, but it doesn't work as I need.
<div className="taskboard">
<table className="table" id={'board_'+this.amount}>
<tbody>
<tr>
<th className="0">Story</th>
<th className="1">New</th>
<th className="2">To do</th>
<th className="3">Pending</th>
<th className="4">In progress</th>
<th className="5">Internal Review</th>
<th className="6">Customer Review</th>
<th className="7">Done</th>
<th className="8">Reject</th>
</tr>
<tr>
{this.tasks.map((task, i) => <td key={i}><Task task={task}/></td>)}
</tr>
</tbody>
</table>
</div>
how about this? the idea is that for each task you create a <tr/>, then inside of it you decide whether or not to display a <Task /> inside of a <td /> based on the Status of the task (new, pending, etc).
< div className = "taskboard" >
<table className="table" id={'board_' + this.amount}>
<tbody>
<tr>
<th className="0">Story</th>
<th className="1">New</th>
<th className="2">To do</th>
<th className="3">Pending</th>
<th className="4">In progress</th>
<th className="5">Internal Review</th>
<th className="6">Customer Review</th>
<th className="7">Done</th>
<th className="8">Reject</th>
</tr>
{this.tasks.map((task, i) =>
<tr>
// maybe here insert some cells that are common for all task states. like name, date, etc.
// then choose which state to put the task into:
<td>
{ task.status === "New" &&
<Task task={task}/>
}
</td>
<td>
{ task.status === "Pending" &&
<Task task={task}/>
}
</td>
// more <td />
</tr>
)
}
</tbody>
</table>
< /div>
eventually you can refactor the whole <tr /> into a new component that receives a task object and displays a row with the relevant cells
This can also be rendered with a little div - css styling as well.
Here is a working fiddle on ReactJS.
Hope this helps.
JSFiddle
var data = {
"new_item": ['Story 10', 'Story 11'],
"to_do": ['Story 1', 'Story 5'],
"pending": ['Story 2', 'Story 3', 'Story 7'],
"in_progress": ['Story 4', 'Story 6', 'Story 8', 'Story 9']
};
var Container = React.createClass({
render() {
return <div className='divTableBody'>
< StatusColumn name = 'New'
id = 'new_item' ></StatusColumn>< StatusColumn name = 'To Do'
id = 'to_do' > < /StatusColumn> < StatusColumn name = 'Pending'
id = 'pending' > < /StatusColumn> < StatusColumn name = 'In Progress'
id = 'in_progress' > < /StatusColumn> < /div > ;
}
});
var StatusColumn = React.createClass({
render() {
var _this = this;
var items = [];
for( var item in data){
data[item].map(function(x) {
if(item === _this.props.id)
items.push(<div className='divTableCell'>{x}</div>);
})
}
return <div className='divTableRow'>
<div className='divTableHeading'>{this.props.name}</div>
<div>{items}</div>
< /div>
}
});
ReactDOM.render( < Container / > , document.getElementById('root'));

Flot Chart from Data Table

I want to build a flot chart from a table. The table is built using the jquery datatables plugin. The table can be edited inline.
I was wondering if anyone had any tips to display the data in flot. Would you pull the data from json or directly from the chart to build the flot chart?
The data is populated in dynamically using the datatables jquery plugin.
The table looks like this..
<div id="plotarea">
<table>
<caption>GDP, based on exchange rates, over time. Values in billion USDs.</caption>
<tr>
<td></td>
<th scope="col">2003</th>
<th scope="col">2002</th>
<th scope="col">2001</th>
<th scope="col">2000</th>
<th scope="col">1999</th>
<th scope="col">1998</th>
</tr>
<tr>
<th scope="row">USA</th>
<td>10,882</td>
<td>10,383</td>
<td>10,020</td>
<td>9,762</td>
<td>9,213</td>
<td>8,720</td>
</tr>
<tr>
<th scope="row">EU</th>
<td>10,970</td>
<td>9,040</td>
<td>8,303</td>
<td>8,234</td>
<td>8,901</td>
<td>8,889</td>
</tr>
</table>
</div>
Thanks!
You can use loops to go through your table and build the data array for flot. Something like this:
var headerTr = $('table tr:first()');
var rowCount = $('table tr').length - 1;
var data = [];
for (var row = 0; row < rowCount; row++) {
var tr = $('table tr').eq(row + 1);
var dataseries = {
label: tr.find('th').text(),
data: []
};
for (var col = 0; col < tr.find('td').length; col++) {
var xval = headerTr.find('th').eq(col).text();
var yval = tr.find('td').eq(col).text().replace(',', '');
dataseries.data.push([xval, yval]);
}
data.push(dataseries);
};
Here is a fiddle with a working example. The drawing is started by button click. For your datatables you could change that to an onchange event or something similar.

Sorting tbody elements by column value with jQuery

I am trying to sort a table - so when a user clicks on the table heading, it will sort in ascending/descending order. I've got it to the point where I can sort the table based on the column value. However, I have groupings of table rows (two rows per table body), and I want to sort the columns based on the values in the columns of the first row of each table body, but when it reorders the table, it want it to reorder the table bodies, not the table rows.
<table width="100%" id="my-tasks" class="gen-table">
<thead>
<tr>
<th class="sortable"><p>Name</p></th>
<th class="sortable"><p>Project</p></th>
<th class="sortable"><p>Priority</p></th>
<th class="sortable"><p>%</p></th>
</tr>
</thead>
<tbody>
<tr class="sortable-row" id="44">
<td><p>dfgdf</p></td><td><p>Test</p></td>
<td><p>1</p></td><td><p>0</p></td>
</tr>
<tr>
<td></td>
<td colspan="3"><p>asdfds</p></td>
</tr>
</tbody>
<tbody>
<tr class="sortable-row" id="43">
<td><p>a</p></td>
<td><p>Test</p></td>
<td><p>1</p></td>
<td><p>11</p></td>
</tr>
<tr>
<td></td>
<td colspan="3"><p>asdf</p></td>
</tr>
</tbody>
<tbody>
<tr class="sortable-row" id="40">
<td><p>Filter Tasks</p></td>
<td><p>Propel</p></td>
<td><p>10</p></td>
<td><p>10</p></td>
</tr>
<tr>
<td></td>
<td colspan="3"><p>Add a button to filter tasks.</p></td>
</tr>
</tbody>
</table>
With the following javascript:
jQuery(document).ready(function () {
jQuery('thead th').each(function(column) {
jQuery(this).addClass('sortable').click(function() {
var findSortKey = function($cell) {
return $cell.find('.sort-key').text().toUpperCase() + ' ' + $cell.text().toUpperCase();
};
var sortDirection = jQuery(this).is('.sorted-asc') ? -1 : 1;
var $rows = jQuery(this).parent().parent().parent().find('.sortable-row').get();
jQuery.each($rows, function(index, row) {
row.sortKey = findSortKey(jQuery(row).children('td').eq(column));
});
$rows.sort(function(a, b) {
if (a.sortKey < b.sortKey) return -sortDirection;
if (a.sortKey > b.sortKey) return sortDirection;
return 0;
});
jQuery.each($rows, function(index, row) {
jQuery('#propel-my-tasks').append(row);
row.sortKey = null;
});
jQuery('th').removeClass('sorted-asc sorted-desc');
var $sortHead = jQuery('th').filter(':nth-child(' + (column + 1) + ')');
sortDirection == 1 ? $sortHead.addClass('sorted-asc') : $sortHead.addClass('sorted-desc');
jQuery('td').removeClass('sorted').filter(':nth-child(' + (column + 1) + ')').addClass('sorted');
});
});
});
You need to sort the tbody elements, not the row elements. You said that yourself in your description of the problem, but your code actually sorts rows, not tbodies.
A secondary problem is that your sort treats everything as a string, which breaks when sorting 1-digit numeric strings ("2") against two-digit strings ("10").
To fix, replace this:
var $rows = jQuery(this).parent().parent().parent()
.find('.sortable-row').get();
jQuery.each($rows, function(index, row) {
row.sortKey = findSortKey(jQuery(row).children('td').eq(column));
});
with this:
var $tbodies = jQuery(this).parent().parent().parent()
.find('.sortable-row').parent().get();
jQuery.each($tbodies, function(index, tbody) {
var x = findSortKey(jQuery(tbody).find('tr > td').eq(column));
var z = ~~(x); // if integer, z == x
tbody.sortKey = (z == x) ? z : x;
});
And then replace $rows with $tbodies throughout your script, and row with tbody.
Example:
http://jsbin.com/oxuva5
I highly recommend the jQuery plugin http://tablesorter.com/ instead of rolling your own.
It's fully featured and well supported.

Categories