Javascript Datatable limit amount of characters shown in a cell - javascript

I am creating a DataTable in Javascript, which has the following properties:
var dtable = $('.ssdatatable').DataTable({
"lengthMenu": [[10, 25, 50, 100, 500], [10, 25, 50, 100, 500]],
"bProcessing": true,
"sDom": "TBflrtip",
"bServerSide": true,
"sAjaxSource": ajSource,
"iDisplayLength": 25,
"bJqueryUI": false,
"bAutoWidth": false,
//"bAutoLength": false,
//"bLengthChange": false,
"recordsFiltered": 0,
"sPaginationType": "full_numbers",
"bPaginate": true,
"sServerMethod": "POST",
"responsive": true,
"fixedHeader": true,
"buttons": [
'copy', 'excel', 'pdf'
],
"aoColumns": [
//columns
]
});
One of the particular columns is a Description, which has a LOT of text in it. The width of columns is fixed, however because of that, the height of my rows are blowing out of proportions, making page x10 of its intended size.
My question is: is there anything I can add inside the properties to make it show only N characters, and by hitting limit it would be something like:
|text textte...|
| Show More|
(I tried commented out options, did do me any good)
Or would I need to use some method or modify css?

Had the same problem - only I wanted to show all the text when the table is exported and thus only limit the text, when displayed. So based on this blog https://datatables.net/blog/2016-02-26, I further developed the code in order to allow the whole text to be shown when the table is exported.
In order to do so, I altered the code so text > 50 char is not removed, but instead wrapped in a span which is then hidden from CSS.
The function code looks like this:
function(data, type, row) {
if (type === 'display' && data != null) {
data = data.replace(/<(?:.|\\n)*?>/gm, '');
if(data.length > 50) {
return '<span class=\"show-ellipsis\">' + data.substr(0, 50) + '</span><span class=\"no-show\">' + data.substr(50) + '</span>';
} else {
return data;
}
} else {
return data;
}
}
Then from the CSS file you can add:
span.no-show{
display: none;
}
span.show-ellipsis:after{
content: "...";
}

given data:
var mydt = [{ a: 1, b: 2, c: 3, d: 4 }, { a: 5, b: 6, c: 7, d: 8 }, { a: 10, b: 12, c: 13, d: 14 }];
$("#tbl2").DataTable({
columnDefs: [{ targets:[0] }],
data: mydt, columns: [{ data: "a" }, { data: "b" }, { data: "c" }, { data: "d" }],
createdRow: function (row, data, c, d) {
// so for each row, I am pulling out the 2nd td
// and adding a title attribute from the
// data object associated with the row.
$(row).children(":nth-child(2)").attr("title", data.b)
},
and the rest
here is a working one in jfiddle https://jsfiddle.net/bindrid/wbpn7z57/7/ note that this one has data in a different format but it works (on the first name column)

// DataTable created the createRow hook to allow the row html to be updated after it was created.
-- row is the current row being created
-- data is the data object associated with the row.
createdRow: function (row, data, c, d) {
$(row) gets the tr in a jQuery object
$(row).children() gets all of the td's in the row
(":nth-child(2)") gets the 2nd td in the row. Note, this is 1 based value,not 0 based.
.attr is the jquery command that adds the "title" attribute to the td.
the "title" is missed name but too late now.
data.b matches the data structured used to populate the table.
The actual structure of this data structure is dependent on your data source so you would actually have to check it.
Hope this helps :)

In the below example code block:
Whereas "Targets": 2 indicates column index, "data":"description" points out column name that wanted to be manipulated. When we look at the render function, description column is limited to 100 characters length.
var dtable = $('.ssdatatable').DataTable({
"lengthMenu": [[10, 25, 50, 100, 500], [10, 25, 50, 100, 500]],
"bProcessing": true,
"sDom": "TBflrtip",
"bServerSide": true,
"sAjaxSource": ajSource,
"iDisplayLength": 25,
"bJqueryUI": false,
.....
{
"targets": 2,
"data":"description",
render: function(data, type, row, meta) {
if (type === 'display') {
data = typeof data === 'string' && data.length > 100 ? data.substring(0, 100) + '...' : data;
}
return data;
}
},
});

Related

Chart.js show negative value in the top half

I am creating a chart.js which has both positive and negative values
but how to make all values be on the top half
(ignore the if it's positive or negative when drawing but keep the label)
var tax_dash = new Chart(ctx_tax_dash, {
type: "bar",
data: {
labels: lable_set,
datasets: [{
label: "Tax in",
data: total_tax_in_t_data__year,
backgroundColor: '#0fd96d',
// borderColor: sales_t_data,
borderWidth: 1,
},
{
label: "Tax out",
data: total_tax_out_t_data__year,
backgroundColor: '#0f81d9',
// borderColor: sales_t_data,
borderWidth: 1,
},
{
label: "Net VAT",
data: total_tax_in_out_t_data__year,
backgroundColor: '#d96a0f',
// borderColor: sales_t_data,
borderWidth: 1,
},
],
},
options: {
legend: {
display: true,
}
},
});
EDIT
what I am trying to do
possible solution: is (multi-axis) dual y axis.multi-axis example
~ issue: how to flip the axis so that the -100 be to the top and 0 be on the bottom
~ issue: how to split the data set base on the (sign)
OR
possible solution 2 : make all variable positive
#Gkiokan> solution: use the popup modifier to the showing values with negative
~ ++ issue: how the function will know if the value is negative
~ issue: the user needs to know that this value is negative in the label
Solution 2
I did it this morning user what Math.abs from #Lawrence comment and "popup modifier" from #Gkiokan comment as well as this jsfiddle
Thank you very much for the help. Chatting with smarter people rubs off on you :)
total_tax_in_t_data_portal_month_year = [Math.abs(12),Math.abs(-234),Math.abs(234)];
total_tax_in_t_data_portal_month_year_sign = [12,-234,234];
var tax_dash_portal = new Chart(ctx_tax_dash_portal, {
type: "bar",
data: {
labels: lable_set,
datasets: [
{
label: "VAT In",
data: total_tax_in_t_data_portal_month_year,
sign: total_tax_in_t_data_portal_month_year_sign,
backgroundColor: "#0fd96d",
// borderColor: sales_t_data,
borderWidth: 1,
},
{
label: "VAT Out",
data: total_tax_out_t_data_portal_month_year,
sign: total_tax_out_t_data_portal_month_year_sign,
backgroundColor: "#0f81d9",
// borderColor: sales_t_data,
borderWidth: 1,
},
{
label: "Net VAT",
data: total_tax_t_data_portal_month_year,
sign: total_tax_t_data_portal_month_year_sign,
backgroundColor: "#d96a0f",
// borderColor: sales_t_data,
borderWidth: 1,
},
],
},
options: {
legend: {
display: true,
},
tooltips: {
enabled: true,
callbacks: {
label: function (tooltipItem, data) {
var label = data.labels[tooltipItem.index];
var val = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
var sign = data.datasets[tooltipItem.datasetIndex].sign[tooltipItem.index];
if(sign < 0){
return label + ": -" + val;
}else{
return label + ': ' + val;
}
}
}
}
},
});
total_tax_in_t_data_portal_month_year is an example as the values come from a function
Math.abs is used to remove the negative sign
then I added sign to the datasets for essay access
tooltips callbacks is called on every variable so I added the if statement there
to add - if sign < 0 and do nothing if not
In my opinion you can have a data Set to save the orginal Data and the modified
Data and then use the values as you need. You can not trust the value characters. My solution will work kind cross over as you have control over both values.
I've made a jsfiddle for you which demonstrates the orginal Data vs modified Data usage. Please click first on Modify Data which will then map the data, so you can see the work in progress. In your case you would modify the data before calling the charts.
Actually you will need just a couple of methods as followed:
updateItemValues to modify the negative values and put it to the other object
tooltipCallback callback for the tooltip to use the mapped orginal value
let data = {
modified: false,
orginalData : {
'tax_in' : [10, 20, -30, -40, -100, -50],
'tax_out' : [-10, 10, 20, 10, -40, -70],
'net_vat' : [-50, -9, -40, -20, -10, -90],
},
modifiedData : {
// this modified data will be calculated before putting it in the charts
// for demo purpose we will just copy the values for now.
'tax_in' : [10, 20, -30, -40, -100, -50],
'tax_out' : [-10, 10, 20, 10, -40, -70],
'net_vat' : [-50, -9, -40, -20, -10, -90],
},
updateModifiedData(){
// loop though the orginal Data
Object.keys(this.orginalData).forEach( (item, indexx) => {
console.log('modifying item chart data for: ', item)
this.updateItemValues(item)
})
this.modified = true
document.getElementById('status').innerHTML = 'modified'
},
updateItemValues(dataKey){
let temp = []
this.orginalData[dataKey].forEach( (value, index) => {
console.log('- validating ', dataKey, 'index: ', index, '; value: ', value)
// if we have a negative value, just multiply by -1 so get it positive
if(value <= 0){
value = value * -1
}
// add to the temporary variable
temp.push(value)
})
// put the modified data to some place to have it saved
this.modifiedData[dataKey] = temp
console.log('-- final data modded ', temp)
},
tooltipCallback(tooltipItem, chartData) {
// find reference values
let index = tooltipItem.index
let dataIndex = tooltipItem.datasetIndex
// find the name of dataset
let key = chartData.datasets[dataIndex].name
// validate or whatever with the orginal value
let orginalValueOfItem = data.orginalData[key][index]
let modifiedValueOfItem = data.modifiedData[key][index]
// Modify your final tooltip here
return 'Orginal Value: ' + orginalValueOfItem + ' ; Modified Value: ' + modifiedValueOfItem
}
}
How can you use this solution?
Pretty simple.
Copy that data Object in your code.
Fill the data.orginalData value with your orginal charts data based on key
example data.orginalData.tax_in = [...]
In your datasets add name property with the corresponding key
Extend the Charts options with the tooltipCallback
Call data.updateModifiedData() to get the modified data
Checkout the jsFiddle for reference if you need to.
Have fun.

DataTables data replacement to multiple columns based on one's value

I am trying to make a conditional statement which will replace data not only to the column that I target but also and on a second one based of selected target's value.
setTimeout(function() {
$('#invoices-table').DataTable({
responsive: true,
columnDefs: [{ orderable: false, targets: [-1, -2, -3] }, {
targets: 0, // statement is based on first column data
render: function(data, type) {
// if data in col0 is "1" then replace data in col0 and col5 (pay button)
if (type == 'display' && data == '1') {
return [
{ data: '<i class="fa fa-3 fa-check-circle-o datatable-paid-1"></i>', target: 0 },
{ data: '<button class="pay-btn btn btn-sm btn-success disabled">Paid</button>', target: 5 }
]
} else {
return [
{ data: '<i class="fa fa-3 fa-exclamation-circle datatable-paid-0"></i>', target: 0 }
]
}
},
}],
"lengthMenu": [
[100, 5, 25, 50, -1],
[100, 5, 25, 50, "All"]
],
dom: 'Bfrtip',
initComplete: function() {
var api = this.api();
// my actions upon complete
}
});
}, 1500); // delay is needed due to needed time of mySQL for passing results
https://codepen.io/anon/pen/jmgBdv?editors=0010
EDIT
Updated code both on post and codepen due to wrong target numbers
If you look at column.render as suggested in previous answer, then you will see that the render callback have a few more params :
render: function ( data, type, full, meta ) {
Each section in columnDefs can have multiple targets, but targets is referring to column indexes, not data! So you have got this a little bit wrong. The meaning is : You can pass the same result string to multiple columns, i.e handling columns with for example checkboxes in one callback - but not distinguish between targets (columns) and different return strings in the same columnDefs section. That would not make so much sense, and would be really hard to implement.
Logically, if you want different values for different columns, then use different columnDefs sections. The full param hold all values for the row, so even you are targeting column #14 you can use full to inspect the value of column #0. Here is what you should do :
columnDefs: [
{ orderable: false, targets: [-1, -2, -3] },
{ targets: 0,
render: function(data, type) {
if (type == 'display') {
return data == '1'
? '<i class="fa fa-3 fa-check-circle-o datatable-paid-1"></i>'
: '<i class="fa fa-3 fa-exclamation-circle datatable-paid-0"></i>'
} else {
return data
}
}
},
{ targets: 14,
render: function(data, type, full) {
if (type == 'display') {
return full[0] == '1'
? '<button class="pay-btn btn btn-sm btn-success disabled">Paid</button>'
: '<button class="pay-btn btn btn-sm btn-success">pay</button>'
} else {
return data
}
}
}
]

Apply background-color to dxDataGrid control and export to Excel

I'm using DevExpress's dxDataGrid in a ASP.NET project for show some data stored on a SQL Server database.
The following code shows how I'm setting the dxDataGrid control for render the data:
// Variables.
var vlrMin = [];
var vlrMax = [];
var vlr_to_match = 0;
var colors = [];
var final_rst = "";
// Add values to variables:
vlrMin.push("9");
vlrMin.push("2");
vlrMin.push("9");
// Add values to variables:
vlrMax.push("13");
vlrMax.push("7");
vlrMax.push("4");
colors.push('#ff0000');
colors.push('#92D050');
colors.push('#5B9BD5');
// Start configuration.
$("#gridContainer").dxDataGrid({
dataSource: [{
"Dept": "Local services",
"Employee": "John Doe",
"TotalHours": "11"
}],
paging: {
pageSize: 10
},
export: {
allowExportSelectedData: true,
enabled: true,
fileName: 'Reporte 1',
texts: {
exportAll: 'Export all',
exportSelectedRows: 'Export selected row(s).',
exportTo: 'Export'
},
},
searchPanel: {
visible: true
},
filterRow: {
visible: true,
showOperationChooser: true
},
allowColumnReordering: true,
grouping: {
autoExpandAll: true
},
groupPanel: {
visible: true
},
pager: {
showPageSizeSelector: true,
allowedPageSizes: [5, 10, 20],
showInfo: true
},
columns: ['Dept',
'Employee', {
dataField: 'TotalHours',
allowFiltering: true,
allowSorting: true,
cellTemplate: function(container, options) {
/* Value to check if matches with the criteria. */
var vlr_to_match = options.value;
/* Loop elements. */
for (var mn = 0; mn < vlrMin.length; mn++) {
if (vlr_to_match >= vlrMin[mn] && vlr_to_match <= vlrMax[mn]) {
final_rst = colors[mn];
break;
}
}
/* Apply custom style to element. */
$('<span>').text(options.data.TotalHours)
.attr('style', 'background-color: ' + final_rst)
.appendTo(container);
}
}
]
});
This is the results in the dxDataGrid control:
But, when I open the generated file "using the DevExpress functionality" I'm not getting the same results as is shown in the screenshot (i.e; the cell has values, but no styles are applied).
According to the documentation, and after apply a color to an specific cell in the dxDataGrid control, when the exported Excel file is opened, the cell is not getting the same result as is shown in the dxDataGrid control.
My question is:
How can apply styles to a dxDataGrid cell and apply such results to the generated Excel file?
unfortunately, based on the quite recent (2016-09-20) reply from DX stuff in their support forum, there is no way in DevExtreme suit to export dxDataGrid to excel with formatting.
See yourself: https://www.devexpress.com/Support/Center/Question/Details/T429240
If you were using the DevEpress ASPxGridView control together with ASPxGridViewExporter you would be able to customize format in the exported Excel doc per cell or per row.

State Saving with individual column filtering

I am using individual column filtering in data table along with stateSave: true. To perform column filtering I am using column filter.js.
I am facing one issue If I filtered data in the column and reload the page it maintains state for table only but textbox becomes empty.
On page refresh, the state remains same for the table and for searching textbox too.
On page refresh, the textbox value should be shown, but instead of that, text box becomes empty.
Please, someone, let me know how can I maintain textbox value along with table state.
I am using this code
jQuery('#Gridtable').dataTable({
stateSave: true,
"aLengthMenu": [[10, 25, 50, 100, 500, -1], [10, 25, 50, 100, 500, "All"]],
"iDisplayLength": 10,
}).columnFilter({
sPlaceHolder: "head:after",
aoColumns: [
{ type: "text" },
{ type: "text" },
{ type: "text" },
]
});
"stateLoaded": function stateLoadedCallback(settings, state) {
state.columns.forEach(function (column, index) {
$('#' + settings.sTableId + '-head-filter-' + index).val(column.search.search);
});
}
Just put values from your state into the fields
If you use stateSave=true DataTables option you can load it this way (in footer in my case):
stateSave: true,
stateLoadParams: function(settings, data) {
for (i = 0; i < data.columns["length"]; i++) {
let col_search_val = data.columns[i].search.search;
if (col_search_val !== "") {
$("input", $("#your-id-of-table tfoot th")[i]).val(col_search_val);
}
}
}
Cheers!
Just in case someone stumbles across this post after two years... this should be the solution to the described issue.

how to sort data table rank column rank wise which contains value 'Absent' also

my datatable containes a column Rank.
it includes rank of students starting from 1 and if a student is absent rank is defined as 'Absent'.
The problem is when sorting this column it comes like 1,10,11,12,...,2,20,21,..,Absent,Absent,..
my data table initialisation is
$(document).ready( function () {
var oTable = $('#filtertableobj').dataTable({
"iDisplayLength": 500,"aLengthMenu": [[100, 200, 500, 1000], [100, 200, 500, 1000]],
/*BEGIN Fixing the index row so they are not sorted -r2ros */
"fnDrawCallback": function ( oSettings ) {
var that = this;
/* Need to redo the counters if filtered or sorted */
if ( oSettings.bSorted || oSettings.bFiltered )
{
this.$('td:first-child', {"filter":"applied"}).each( function (i)
{
that.fnUpdate( i+1, this.parentNode, 0, false, false );
} );
}
},
"aoColumnDefs": [{ "bSortable": false, "aTargets": [ 0 ] } ],
});
});
How to sort like 1,2,3,...,10,11,12,..,Absent,Absent,...
What you're looking for is called a "natural sort". If you search that in SO you'll find your answer. Try this
Sort Array Elements (string with numbers), natural sort

Categories

Resources