Sum a column based on a condition in another column - datatables

Is there any way to exclude rows from footer callback in this example :
I have the total sum of column 4(Salary) in the footer of all records.
Now I want to exclude rows that have names in column 3(Office) like - London, New York.
So now the sum needs to be for all rows except rows with these two cities.
$(document).ready(function() {
$('#example').DataTable( {
"footerCallback": function ( row, data, start, end, display ) {
var api = this.api();
// Remove the formatting to get integer data for summation
var intVal = function ( i ) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
// Total over all pages
total = api
.column( 4 )
.data()
.reduce( function (a, b) {
return intVal(a) + intVal(b);
}, 0 );
// Total over this page
pageTotal = api
.column( 4, { page: 'current'} )
.data()
.reduce( function (a, b) {
return intVal(a) + intVal(b);
}, 0 );
// Update footer
$( api.column( 4 ).footer() ).html(
'$'+pageTotal +' ( $'+ total +' total)'
);
}
} );
} );
Do I need to add classes in the rows have that names or? What is the best way to do it?

Working solution: https://jsfiddle.net/cmjp4b3a/
$(document).ready(function() {
$('#example').DataTable( {
"footerCallback": function ( row, data, start, end, display ) {
var api = this.api();
// Remove the formatting to get integer data for summation
var intVal = function ( i ) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
// Total over all pages
total = api
.column(4)
.data()
.reduce(function (a, b) {
var cur_index = api.column(4).data().indexOf(b);
if (api.column(3).data()[cur_index] != "London" && api.column(3).data()[cur_index] != "New York") {
return intVal(a) + intVal(b);
}
else { return intVal(a); }
}, 0)
// Total over this page
pageTotal = api
.column( 4, { page: 'current'} )
.data()
.reduce(function (a, b) {
var cur_index = api.column(4).data().indexOf(b);
if (api.column(3).data()[cur_index] != "London" && api.column(3).data()[cur_index] != "New York") {
return intVal(a) + intVal(b);
}
else { return intVal(a); }
}, 0)
// Update footer
$( api.column( 4 ).footer() ).html(
'$'+pageTotal +' ( $'+ total +' total)'
);
}
} );
} );

Related

DataTables Filter Dropdown - Parse list, contains not exact

So my javascript is bad, but I have a datatables need that I cannot figure out. Relevant code here:
$('#lesson-table').DataTable( {
'data': cleanData,
'paging': false,
'order': [[ 8, 'asc' ], [ 3, 'desc' ], [ 1, 'desc' ]],
initComplete: function () {
// this is where we populate the filter dropdowns
this.api().columns([0,1,2,6,7]).every( function () {
var column = this;
var select = $('<select><option value=""></option></select>')
.appendTo( $(column.header()) )
.on( 'change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search( val ? '^'+val+'$' : '', true, false )
.draw();
} );
column.data().unique().sort().each( function ( d, j ) {
var val = $('<div/>').html(d).text();
select.append( '<option value="' + val + '">' + val + '</option>' );
} );
} );
}
} );
// this removes duplicate dropdown values
var usedNames = {};
$("#lesson-table select > option").each(function () {
if (usedNames[this.value]) {
$(this).remove();
} else {
usedNames[this.value] = this.text;
}
});
So the change that was made in my datasource is that columns 1, the second column in the set, is now a comma separated list of items. Most of the time it is one item say: "Entertainment", but sometimes it can be "Entertainment, Sports, Healthcare" At the moment, it will show that list as an option in my dropdown, but what I need it to do is split them up and then filter by contains...not by exact.
Hope that makes sense. Can explain more if needed.

Using select2 with datatables to filter on multple values

Im currently trying to filter each column of my datatable using a select2 dropdown.
My code currently filters correctly without the multiple tag on the select tag, but once I add the multiple value to my select tag I get the following error:
TypeError: a.replace is not a function
I have been trying to adapt the following datatables javascript:
link
Here is what I have currently:
$('#caseTable').DataTable( {
initComplete: function () {
var x = 0;
this.api().columns().every( function () {
var column = this;
var select = $('<select class="search2" multiple="multiple"><option value=""></option></select>')
.appendTo( $('.dropdown'+x))
.on( 'change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search( val ? '^'+val+'$' : '', true, false ) //find this value in this column, if it matches, draw it into the table.
.draw();
} );
column.data().unique().sort().each( function ( d, j ) {
select.append( '<option id="'+d+'"value="'+d+'">'+d+'</option>' )
} );
x++
} );
$(".search2").select2();
}
} );
EDIT: I managed to fix it. I needed to store the multiple values into an array, and then pipe the values together to search for each individual value.
Here are the changes I made to the .on('change') function.
.on( 'change', function () { //when an option is selected
var val = new Array();
//set val to current element in the dropdown.
val = $(this).val();
if (val.length > 1){
valString = val.toString();
valPiped = valString.replace(/,/g,"|")
column
.search( valPiped ? '^'+valPiped+'$' : '', true, false ) //find this value in this column, if it matches, draw it into the table.
.draw();
} else if (val.length == 1) {
column
.search( val ? '^'+val+'$' : '', true, false ) //find this value in this column, if it matches, draw it into the table.
.draw();
} else {
column
.search('',true,false)
.draw();
}
} );
I managed to fix it. I needed to store the multiple values into an array, and then pipe the values together to search for each individual value. Here are the changes I made to the .on('change') function.
.on( 'change', function () { //when an option is selected
var val = new Array();
//set val to current element in the dropdown.
val = $(this).val();
if (val.length > 1){
valString = val.toString();
valPiped = valString.replace(/,/g,"|")
column
.search( valPiped ? '^'+valPiped+'$' : '', true, false ) //find this value in this column, if it matches, draw it into the table.
.draw();
} else if (val.length == 1) {
column
.search( val ? '^'+val+'$' : '', true, false ) //find this value in this column, if it matches, draw it into the table.
.draw();
} else {
column
.search('',true,false)
.draw();
}
} );

how to combine combine footer_callback with multi_filter in datatables

I am trying to combine footer_callback with multi_filter
this is my fiddle attempt but I cannot get the footer_callback code to work. I am not sure if I need to do major changes.
I have 2 footers, 1 I use for the search per column(multi_filter) and the 2nd I use for the sumation of a colum(footer_callback). I have slightly modified the code for the multi_filter to work (html and js). I am just not sure what to do for the footer_call_back to work. Can anyone advise how I can get the footer_callback code to work(currenly commented out)?
html code for footer_call_back:
<tfoot>
<tr>
<th colspan="4" style="text-align:right">Total:</th>
<th></th>
</tr>
</tfoot>
js code for footer_callback:
"footerCallback": function ( row, data, start, end, display ) {
var api = this.api(), data;
// Remove the formatting to get integer data for summation
var intVal = function ( i ) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
// Total over all pages
total = api
.column( 4 )
.data()
.reduce( function (a, b) {
return intVal(a) + intVal(b);
}, 0 );
// Total over this page
pageTotal = api
.column( 4, { page: 'current'} )
.data()
.reduce( function (a, b) {
return intVal(a) + intVal(b);
}, 0 );
// Update footer
$( api.column( 4 ).footer() ).html(
'$'+pageTotal +' ( $'+ total +' total)'
);
}
html code for multi_filter:
<tfoot id="search">
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</tfoot>
jscoder for multifilter:
// Setup - add a text input to each footer cell
$('#example tfoot#search th').each(function() {
var title = $(this).text();
$(this).html('<input type="text" placeholder="Search ' + title + '" />');
});
// DataTable
var table = $('#example').DataTable();
// Apply the search
table.columns().every(function() {
var that = this;
$('input', this.footer()).on('keyup change', function() {
if (that.search() !== this.value) {
that
.search(this.value)
.draw();
}
});
EDIT1
That does not work
or
that fixes the footer_callback but breaks the multi_filter
I have tidied up the so the columns line up here FIDDLE:
and then done the changes recommended here FIDDLE
which looks like this:
$(document).ready(function() {
$('#example').DataTable( {
// footer_callback code goes here...
} ); // end $('#example').DataTable( {
//multi_filter code goes here...
} );
and that gets the footer_callback to work but then the multi_filter does not work. Anyway I can get both of them to work together?
You need put this footerCallback in data table initialization function.like this
$('#example').DataTable( {
"footerCallback": function ( row, data, start, end, display ) {
var api = this.api(), data;
// Remove the formatting to get integer data for summation
var intVal = function ( i ) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
// Total over all pages
total = api
.column( 4 )
.data()
.reduce( function (a, b) {
return intVal(a) + intVal(b);
}, 0 );
// Total over this page
pageTotal = api
.column( 4, { page: 'current'} )
.data()
.reduce( function (a, b) {
return intVal(a) + intVal(b);
}, 0 );
// Update footer
$( api.column( 4 ).footer() ).html(
'$'+pageTotal +' ( $'+ total +' total)'
);
}
});
Working demo refer this.
https://jsfiddle.net/dipakthoke07/7bh7w2tu/8/ OR
http://jsfiddle.net/dipakthoke07/s8F9V/569/
Thank you hope this will help you.

Dojo dgrid: Filter data from store with diffrent fields when I click on filter button

I am using 'dgrid/Grid' and dstore/RequestMemory for creating grid and storing data. Now I want to filter data according to values in the fields(see img). I am not sure how to filter data when using simple Dgrid and dstore.
var structure = [{
label : "Value Date",
field : "valueDate"
}, {
id: "currencyCol",
label : "Currency",
field : "currency"
}, {
label : "Nostro",
field : "nostroAgent"
}];
var store= new RequestMemory({
target: 'getReportData',
idProperty: "cashflowId",
headers: structure
});
// Create an instance of OnDemandGrid referencing the store
var grid = new(declare([Grid, Pagination, Selection]))({
collection: store,
columns: structure,
loadingMessage: 'Loading data...',
noDataMessage: 'No results found.',
minRowsPerPage: 50,
}, 'grid');
grid.startup();
on(document.getElementById("filter"), "click", function(event) {
event.preventDefault();
grid.set('collection', store.filter({
**currencyCol: "AED"**
.
.
.
}));
Any help would be appreciated or suggest if I use some diffrent store or grid.
I got the solution for my question. On filter button click I have written all my filtering logic and the final store will set to dgrid:
on(document.getElementById("filter"), "click", function(event) {
var store= new RequestMemory({
target: 'getReportData',
idProperty: "cashflowId",
headers: structure
});
var from=dijit.byId('from').value;
var to=dijit.byId('to').value;
var curr=dijit.byId('currency').value;
var nos=dijit.byId('nostro').value;
var authStatus=dijit.byId('authStatus').value;
var filterStore;
var finalStore=store;
var filter= new store.Filter();
var dateToFindFrom;
var dateToFindTo;
if (from != "" && from !== null) {
var yyyy = from.getFullYear().toString();
var mm = ((from.getMonth()) + 1).toString(); // getMonth() is zero-based
var dd = from.getDate().toString();
if(mm <= 9){
mm= "0" + mm;
}
if(dd <= 9){
dd= "0" + dd;
}
dateToFindFrom =yyyy + mm + dd;
filterStore= filter.gte('valueDate', dateToFindFrom);
finalStore=finalStore.filter(filterStore);
}
if (to != "" && to !== null) {
var yyyy = to.getFullYear().toString();
var mm = ((to.getMonth()) + 1).toString(); // getMonth() is zero-based
var dd = to.getDate().toString();
if(mm <= 9){
mm= "0" + mm;
}
if(dd <= 9){
dd= "0" + dd;
}
dateToFindTo =yyyy + mm + dd;
filterStore= filter.lte('valueDate', dateToFindTo); //.lte('valueDate', dateToFindTo);
finalStore=finalStore.filter(filterStore);
}
if(curr != "" && curr !== null) {
filterStore= filter.eq('currency', curr);
finalStore=finalStore.filter(filterStore);
}
if(nos != "" && nos !== null) {
filterStore= filter.eq('nostroAgent',nos);
finalStore=finalStore.filter(filterStore);
}
if(authStatus != "" && authStatus !== null) {
if (authStatus=='ALL') {
var both= [true, false];
filterStore= filter.in('approved', both);
finalStore=finalStore.filter(filterStore);
} else if (authStatus=='Authorised Only') {
filterStore= filter.eq('approved', true);
finalStore=finalStore.filter(filterStore);
} else if (authStatus=='Unauthorised Only') {
filterStore= filter.eq('approved', false);
finalStore=finalStore.filter(filterStore);
};
};
grid.set('collection', finalStore);
});

Jquery Datatables cant get the sum value of multiple columns

I have a table which is perfectly populating data. There is a shipping cost column which needs to be calculated and shown in a div which is outside the table. I have got the value summed up but how to pass the value to the data table so that it can be populated elsewhere on the page.
Why would you pass a calculated sum to the dataTable, so it can pass it to a <div>? At first I thought you wanted dataTable to calculate sum and return it, so I made this extension or "plugin" up :
//pass columnIndex that needs to be calculated
//and the $(element) that should receive the calculated value
$.fn.dataTableExt.oApi.fnColumnSum = function ( oSettings, iColIndex, oElement ) {
var value,
total = 0;
for (var i=0; i<oSettings.aoData.length;i++) {
value = oSettings.aoData[i]._aData[iColIndex];
if (!isNaN(value)) {
total = total + parseFloat(value);
}
}
oElement.text(total);
}
Now DataTable is extended so you can call for example
dataTable.fnColumnSum(3, $("#shipping-costs"));
jsfiddle with the above -> http://jsfiddle.net/jTgx2/
This piece of code worked for me. I hope it will help you too.
$("#cashSheet").dataTable({
"footerCallback": function(row, data, start, end, display){
var api = this.api(), data;
var intval = function(i){
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1:
typeof i === 'number' ?
i : 0;
};
total = api
.column( 3 )
.data()
.reduce(function(a, b){
return intval(a) + intval(b);
}, 0 );
pageTotal = api
.column( 3, {page: 'current'} )
.data()
.reduce(function(a, b){
return intval(a) + intval(b);
}, 0 );
$(api.column( 3 ).footer() ).html(
''+pageTotal +' ( '+ total + ' total)'
);
total = api
.column( 4 )
.data()
.reduce(function(a, b){
return intval(a) + intval(b);
}, 0 );
pageTotal = api
.column( 4, {page: 'current'} )
.data()
.reduce(function(a, b){
return intval(a) + intval(b);
}, 0 );
$(api.column( 4 ).footer() ).html(
''+pageTotal +' ( '+ total + ' total)'
);
}
});
It calculates the sum of fourth and fifth column and displays it in the footer. Hope it helps you. All the best.
try this instead of writing same function multiple time
$(document).ready(function() {
$('#example').DataTable( {
"footerCallback": function(row, data, start, end, display) {
var api = this.api(),
data;
// Remove the formatting to get integer data for summation
var intVal = function(i) {
return typeof i === 'string' ?
i.replace(/[\$a-zA-Z, ]/g, '') * 1 :
typeof i === 'number' ?
i : 0;
};
var cols = [4, 5]; // your columns position will come in this array
for (let index = 0; index < cols.length; index++) {
var col_data = cols[index];
// Total over all pages
total = api
.column(col_data)
.data()
.reduce(function(a, b) {
return intVal(a) + intVal(b);
}, 0);
// Total over this page
pageTotal = api
.column(col_data, {
page: 'current'
})
.data()
.reduce(function(a, b) {
return intVal(a) + intVal(b);
}, 0);
// Update footer
$(api.column(col_data).footer()).html(
'Total: ' + pageTotal + ' ( GrandTotal: ' + total + ' )'
);
}
},
} );
} );