Getting Datatables and Sparklines to play nice together? - javascript

Im currently trying to get Datatables and the Sparklines packages to work together kind of like below:
(This stuff is all written in R however)
I realize my issue is similar to this one... However, even after looking at some of the code and adapting it to my own, I was only able to render one or the other.. either the data from my server on the chart or the sparklines rendered with all data missing - never both together...
Here's the code
<table id="table_id" class="display">
<thead>
<tr>
<th>Table Name</th>
<th>Column Name</th>
<th>Rule</th>
<th>Current</th>
<th>Minimum</th>
<th>Maximun</th>
<th>Median</th>
<th>Mean</th>
<th>Sparkline</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
The HTML above and the JS below..
<script>
$SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
CURRENT_JOB = "{{ job_requested }}";
data = {{ data|safe}}
$(function() {
$('.js-typeahead').typeahead({
order: "asc",
source: {
groupName: {
// Array of Objects / Strings
data: {{jobs|safe}}
}
},
callback: {
onInit: function() {
$('#table_id').DataTable({
data:{{ data|safe}},
columns: [
{data: 'table_name'},
{data: 'col_name'},
{data: 'rule'},
{data: 'current'},
{data: 'min'},
{data: 'max'},
{data: 'median'},
{data: 'mean'},
],
"aoColumnDefs": [
{
"aTargets": [8],
"mRender": function (data, type, full) {
// since data is an array of values [1,2,3,4]
data = data.toString()
return '<span class="spark">' + data + '</span>'
}
}
],
"drawCallback": (oSettings) => {
console.log('callback')
$('.spark:not(:has(canvas))').sparkline('html', {
type: 'line',
minSpotColor: 'red',
maxSpotColor: 'green',
spotColor: false
});
}
});
}
}
});
});
Does anyone know what I am doing wrong? I need the columns: [] to point my JSON data to the right columns in the table but I also need to point one of the keys in my data object to the sparkline itself and then call the .sparkline()
Also my data object structure that im getting from the server kinda looks like this:
data = {
'table_name': cow,
'col_name' : cow_col,
'rule' : cow_col,
..etc, etc..
'data4spark: [1,2,3,4]
}
I really appreciate anyones feedback/help! Thanks! ❤️

Got it. This always happen every time I post a stackoverflow question, but I think i'd be stuck for a few days if I didn't post so..
Anyways, after reading the docs for a few hours -- The aoColumnDefs is a selector that can select an entire row in the table (if it's already created in the HTML) and that was wrong in my code above.. The aTargets is the parameter that you pass in the index of the column and the mRender is the call back function that you call right before it spits out whatever to the screen (it can modify the data beforehand for that specific col)
The diff is that I sent the code to the HTML using the columns and then I targeted the whole col to attatch the tags on and sent them over
Posting my code in hopes this saves someone time
$('#table_id').DataTable({
data:{{ data|safe}},
columns: [
{data: 'table_name'},
{data: 'col_name'},
{data: 'rule'},
{data: 'current'},
{data: 'min'},
{data: 'max'},
{data: 'median'},
{data: 'mean'},
{data: 'data'},
],
"aoColumnDefs": [
{
"aTargets": [8],
"mRender": function (data, type, full) {
// since data is an array of values [1,2,3,4]
return '<span class="spark">' + data + '</span>'
}
}
],
"drawCallback": (oSettings) => {
console.log('callback');
console.log($('.spark:not(:has(canvas))'))
$('.spark:not(:has(canvas))').sparkline('html', {
type: 'line',
minSpotColor: 'red',
maxSpotColor: 'green',
spotColor: false
});
}
});

Related

row().child().show() isnt picked up by jquery datatables

After following the examples in https://datatables.net/reference/api/row().child(), I got this working in one project. Now im working on a new one, and everything was fine until the .show() came up with the error 'Property 'show()' does not exist on type Api' I followed the example and my imports seem to be up to date (this function has been in datatables since 1.10) so I dont know what could be wrong. This is in a typescript file, but as far as im aware everything still works like javascript. The function doesnt get upset if I do row.child().show(), but when I put the format function in it doesnt like that. Im still new to programming, so any help is super welcome :)
My HTML Table:
<table id="duckTable" class="display" cellspacing="0" width="80%">
<thead>
<tr>
<th>Select</th>
<th>Id</th>
<th>Name</th>
<th>Type</th>
</tr>
</thead>
</table>
My JS table:
var duckTable = $('#duckTable').DataTable({
"ajax": {
"url": "/Ducks/getDucks",
"type": "GET",
"dataSrc":""
},
paging: false,
ordering: false,
info: false,
"columns": [
{
className: 'dropdown',
orderable: false,
data: null,
defaultContent: '',
},
{ "data": "id" },
{ "data": "name" },
{ "data": "type" }
],
order: [[1, 'asc']],
"columnDefs": [
{
"render": function (data, type, row) {
var status = row.status;
var editButton = "<i name=" + row.id + " class=\"open-table\" style=\"padding-left:27px; padding-top:10px;\">&#8595</i> ";
if (status == null || status === 'D') {
return editButton;
} else {
return "";
}
},
"targets": 0
},
{"width": "10%", "targets":0},
]
});
My function:
function format(d) {
return ('<div>Still doesnt work</div>');
}
$('#duckTable tbody').on('click', 'td.dropdown', function () {
var tr = $(this).closest('tr');
var row = duckTable.row(tr);
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
}
else {
// Open this row (the format() function would return the data to be shown)
row.child(format(row.data())).show();//this throws the error
tr.addClass('shown');
}
});
You mentioned that you're using TypeScript - the error that you're receiving sounds like a TypeScript compilation error.
This is because by the Typescript API definition that DataTables publishes, calling row.child(data) returns a union type of RowChildMethods<T> | Api<T>. Because the .show() method is not defined on the Api type, the Typescript compiler throws an error.
You should be able to get around this by splitting up your code into two statements:
row.child(format(row.data()));
row.show();

How to Refresh table with kendo datasource updates from object, not from ajax request

I have an issue, when I bind data with kendo to a Table I'm using a kendo.data.DataSource object and I'm binding to a table like:
<table class="myClass" id="myTable">
<thead>
<tr>
<th data-bind="visible:Name">Name.Title"</th>
<th data-bind="visible:Type">Type.Title"</th>
<th data-bind="visible: DateAdded">"CreatedDate.Title"</th>
</tr>
</thead>
<tbody id="contactsListView" data-role="listview"
data-bind="source: ListViewSource"
data-template="Template"></tbody>
</table>
on JS I am filling like this:
ListViewSource: new kendo.data.DataSource({
serverPaging: true, // <-- Do paging server-side.
serverSorting: true, // <-- Do sorting server-side.
transport: {
read: {
data: function () {
return globalVariableWithObjectList;
}
}
},
schema: {
data: function () {
return globalVariableWithObjectList;
}
}
}),
and it works for fill table on the first load, but if with some actions I add or delete an element It does not refresh on the table. I'm trying to refresh with:
ListViewSource.read();
It works when I have the kendo.data.DataSource like this:
contactsListViewSource: new kendo.data.DataSource({
serverPaging: true, // <-- Do paging server-side.
serverSorting: true, // <-- Do sorting server-side.
transport: {
read: {
url: myUrl,//Where I'm getting the data
dataType: "json",
type: "POST"
}
},
pageSize: 5,
sort: { field: "CreatedDate", dir: "desc" },
schema: {
data: function () {
return globalVariableWithObjectList;
}
}
}),
I am trying to reduce ajax numerous calls with only one when multiple data to update is needed, and storing data in global variables so that I can use them later. But the read() function for kendo.data.DataSource only refresh table data when it calls for an ajax request and non when I try to get data from the global variable, does anyone knows how can I make it work while reading from the variable ?
Use contactsListViewSource.add(newRecord); for adding new records to the data source, it will automatically bind to HTML list (MVVM) and display it.
Call contactsListViewSource.sync() to send data to server. contactsListViewSource.sync() will call transport.create method if new records are added.
Working example: ListView MVVM

How to combine two columns in one in Yajra datatable

I want to merge restaurant name and location to be in one column, Im uisng laravel and I don't want to merge it using the editcolumn from the controller because this will not allow search to work and I will get in trouble as Im using eloquent as explain here https://github.com/yajra/laravel-datatables/issues/2293
so I have to return the same name as it comes from the elquent, but I need in the same time to combine tow columns in one
Please note, I cant use combination in controller and return it in one column
->editColumn('restaurant_name', function ($data) {
return $data->restaurant_name.' - '.$data->restaurant_city;
}) //this one cant be work because it will give me error message when do search
Javascript:
columns: [
{data: 'id', name: 'id', sClass: 'text-center'},
{data: 'user_name', name: 'users.name', sClass: 'text-center'},
{data: 'restaurant_name', name: 'restaurants.name', sClass: 'text-center'},
{data: 'restaurant_city', name: 'locations.city', sClass: 'text-center'},
{data: 'action', name: 'action', sClass: 'text-center',orderable: false, searchable: false},
],
Controller
return $this->select('orders.*', 'users.name')
->join("food_orders", "orders.id", "=", "food_orders.order_id")
->join("foods", "foods.id", "=", "food_orders.food_id")
->join("restaurant_locations", "restaurant_locations.id", "=", "orders.location_id")
->join("restaurants", "restaurants.id", "=", "foods.restaurant_id")
->join('users', 'orders.user_id', '=', 'users.id')
->select('orders.*',"users.name as user_name","restaurants.name as restaurant_name","restaurant_locations.city as restaurant_city")
->groupBy('orders.id');
return DataTables::of(Order::GetAllOrders())
->addIndexColumn()
->editColumn('created_at', function ($data) {
return date('d-m-Y', strtotime($data->updated_at));
})
->addColumn('action', function($row){
return view('admin.orders.all_orders.action-buttons',compact('row'))->render();
})
->rawColumns(['action'])
->make(true);
I think you should use addColumn instead of editColumn, to display merged name:
->addColumn('full_restaurant_name', function ($data) {
$data->restaurant_name.' - '.$data->restaurant_city
});
By doing this, you are not changing the existing column restaurant_name, but adding another field. Now, if you want to keep this column searchable, you could do two things:
Add custom filter
Define the new full_restaurant_name column like this:
{data: 'full_restaurant_name', name: 'restaurant_name'}
This way, search will work on the full_restaurant_name, because it's referred as restaurant_name column in your database.
PS: I haven't tested this, so if you occur any problems, let me know.
try to use custom filter https://datatables.yajrabox.com/collection/custom-filter
this may help you:
DataTables::of(Order::GetAllOrders())
->addIndexColumn()
->filterColumn('restaurant_name', function($query, $keyword) {
$query->where('restaurant_name', 'like', "%{$keyword}%")
->orWhere('restaurant_city', 'like', "%{$keyword}%"); // you can implement any logic you want here
})
->editColumn('restaurant_name', function ($data) {
return $data->restaurant_name.' - '.$data->restaurant_city;
})
...;

Add json data to datatables

I am trying to populate datatables with a complex json scheme, however I don't know exactly how to do it.
First, some parts of json are nested and it needs iteration.
Second I need to create some markup, basically a href link.
Here is what I have:
$(document).ready(function(){
$('#empTable').DataTable({
'processing': true,
'serverSide': true,
'serverMethod': 'post',
'ajax': {
'url':'/dashboard/ajaxgetrequests',
dataSrc: "json_list"
},
'columns': [
{ data: 'firstname' },
{ data: 'funding_project_name' } // this must be a link like <a href='/<relation_id>'><funding_project_name></a>
]
});
});
{
"json_list":{
"125":{
"firstname":"John",
"funding_project_name":"A",
"relation_id": "7"
},
"133":{
"firstname":"Cesar",
"funding_project_name":[
"A",
"B"
],
"relation_id":[
"7",
"9"
]
}
}
}
1) For nested JSON you can use something like this:
// JSON structure for each row:
// {
// "engine": {value},
// "browser": {value},
// "platform": {
// "inner": {value}
// },
// "details": [
// {value}, {value}
// ]
// }
$('#example').dataTable( {
"ajaxSource": "sources/deep.txt",
"columns": [
{ "data": "engine" },
{ "data": "browser" },
{ "data": "platform.inner" },
{ "data": "details.0" },
{ "data": "details.1" }
]
} );
2) To edit and insert a link you can use columns.render (documentation)
$('#example').dataTable( {
"columnDefs": [ {
"targets": 0,
"data": "download_link",
"render": function ( data, type, row, meta ) {
return 'Download';
}
} ]
} );
Honestly, there may be a better built in way of handling this but when I experience things that do not fit the exact mold of using the base datatable functionality, I prefer to take manual control of the generation. This will give you an overview on how to do it with your structure:
Just basic html for your table (nothing really to see here):
<table id="empTable">
<thead>
<tr><th>First Name</th><th>ProjectName</th></tr>
</thead>
<tbody></tbody>
</table>
In JS we declare a variable we can use throughout our script then on ready event we instatiate our datatable:
var dt;
$(document).ready(function () {
dt = $('#empTable').DataTable();
loadDT();
});
We will also use a function call 'loadDT()' and what this will do is trigger a ajax call to the backend to get your json, in this example, I'm just gonna mock it but in your world so this on the ajax success:
Iterate your list and determine the types then use the api call row.add to dynamically add new rows to your table. (notice we are reusing the stored variable dt that we initially declared.) This is where you can do whatever custom logic fun you need to do.
function loadDT(){
var mockJSON = { "json_list":{ "125":{ "firstname":"John","funding_project_name":"A","relation_id": "7"},"133":{ "firstname":"Cesar","funding_project_name":["A","B"],"relation_id":["7","9"]}}};
$.each(mockJSON.json_list, function (i, n){
if(Array.isArray(n.funding_project_name)) {
$.each(n.funding_project_name, function (i2, p){
dt.row.add([n.firstname,'' + p + '']);
dt.draw(false);
});
} else {
dt.row.add([n.firstname, '' + n.funding_project_name + '']);
dt.draw(false);
}
});
}
Like previously stated, there may be some built in functions to handle this that I am unaware but when things get complicated, just know you can take manual control of it.
Full Example:
var dt;
$(document).ready(function () {
dt = $('#empTable').DataTable();
loadDT();
});
function loadDT(){
var mockJSON = { "json_list":{ "125":{ "firstname":"John","funding_project_name":"A","relation_id": "7"},"133":{ "firstname":"Cesar","funding_project_name":["A","B"],"relation_id":["7","9"]}}};
$.each(mockJSON.json_list, function (i, n){
var projLinks = "";
if(Array.isArray(n.funding_project_name)) {
$.each(n.funding_project_name, function (i2, p){
projLinks += '' + p + ' ';
});
} else {
projLinks = '' + n.funding_project_name + '';
}
dt.row.add([n.firstname, projLinks]);
dt.draw(false);
});
}
<link href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<table id="empTable">
<thead>
<tr><th>First Name</th><th>ProjectName</th></tr>
</thead>
<tbody></tbody>
</table>

JSON to HTML5 table

How to populate a HTML5 table if you receive data in JSON format in jQuery Ajax and based on a specific column on a row color that row on a table (Using bootstrap 4 CSS styles?)
For example if i receive a dataset in JSON format like this:
{ "name":"John", "age":31, "city":"New York" };
The column city is New York so the table row should be colored green so the finished product should be like this:
<tr class="success">
<td>John</td>
<td>31</td>
<td>New York</td>
</tr>
I'm fairly new at jQuery can anyone guide me through how this can be achieved?
I'm using datatables library at the moment and what i have done is this:
function btnSearch_Click() {
$.ajax({
type: "POST",
url: "index.aspx/GetJobs",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
$('.table-sortable').dataTable({
destroy: true,
data: data,
columns: [
{
'd': 'Name'
},
{
'd': 'Age'
},
{
'd': 'City'
}]
});
}
});
};
Current HTML5 code is displayed bellow
<table class="table table-hover thead-inverse table-bordered table-sortable">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>City</th>
</tr>
</thead>
</table>
But when I click the button no data rows are returned by the browser (SQL Server does return data). Also as i mentioned i do not know how to accomplish that if specific data is returned in a row i need to color it...
Thank you for your help in advance...
Try this :
$('.table-sortable').dataTable({
destroy: true,
data: data,
columns: [
{ "data": "name" },
{ "data": "age" },
{ "data": "city" },
]
});
For using DataTables with ajax you usually have something like this:
$(document).ready(function () {
$('.table-sortable').dataTable({
"ajax": {
"url": "index.aspx/GetJobs",
"type": "POST"
},
"columns": [
{ "data": "name" },
{ "data": "age" },
{ "data": "city" },
]
});
});
As you can see the plugin itself has the functionality to use ajax.
So by default your returned data from server should contain a property data which contains the elements that are about to be rendered. You can actually specifiy this by using the dataSrc (reference) prop of ajax, you can set it to other name or remove it if you use plain collection:
"ajax": {
"url": "index.aspx/GetJobs",
"type": "POST"
"dataSrc": ""
},
This however does not change the data name in columns declaration so don't change it there.
You can read more about accepted formats and see examples in the official documentation.
Now regarding your question about row styling, there are a lot of callbacks and declarations which you can use to achieve that. I personally prefer using the createdRow callback (reference):
"createdRow": function( row, data, dataIndex ) {
if ( parseInt(data[1]) >= 18 ) {
$(row).addClass( 'success' );
}
}
So in this case if the age (second column based on 0-start-indexing) of the current row is above 18 it will add the desired class.
I hope this helps resolving your issues, if there still are problems you can try making a working jsfiddle so we can try debugging it in a "real-like" situation.
This is just to get an idea, i will add button click code
$("button").click(function(){
var obj = JSON.parse('[{ "name":"John", "age":30, "city":"New York"},{ "name":"John1", "age":30, "city":"New York"}]');
var t = $('#example');
for (i = 0; i < obj.length; i++) // iterate data from json
{
var name = obj[i].name;
var age = obj[i].age;
var classStyle = 'yellow'
if(name=='John')
{
classStyle = 'green';
}
$('#example').append('<tr style=background:'+classStyle+'><td>'+name+'</td><td>'+age+'</td></tr>');
}
});

Categories