I'm using Datatables with server side processing, and i need to add some extra parameters to my query to do some filtering. This is how my setup looks like:
if($('#example').length) {
var oTable = $('#listings').dataTable({
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": ajax_url+'?action=load_table_data',
"fnServerParams": function ( aoData ) {
aoData.push( { "name": "filters", "value": get_table_filters() } );
}
});
var tableFilterArray = {};
//Setting up and changing the filters, etc...
function get_table_filters() {
return JSON.stringify(tableFilterArray);
}
}
The script works fine in Chrome, but fails to run in Firefox, gives me the following error:
ReferenceError: get_table_filters is not defined
Here is a demo: http://jsfiddle.net/HaXUR/3/
What am i missing here?
Move the get_table_filters out of the if statement
if($('#example').length) {
var oTable = $('#listings').dataTable({
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": ajax_url+'?action=load_table_data',
"fnServerParams": function ( aoData ) {
aoData.push( { "name": "filters", "value": get_table_filters() } );
}
});
var tableFilterArray = {};
}
function get_table_filters() {
return JSON.stringify(tableFilterArray);
}
Related
How do I delete my selected rows from datatables that use a local array for data? This is how I initialised my table:
var selected = Array();
var dataSet = [];
var rowItem = "";
$(document).ready(function () {
var table = $("#table").DataTable({
"data": dataSet,
"filter":false,
"language": {
"search": "",
"searchPlaceholder": " Search"
},
"select": {
"style": 'multi'
},
"ordering": true,
"lengthChange": false,
"columns": [
{ "title": "Name"},
],
"responsive": true,
"processing":true,
}).columns.adjust()
.responsive.recalc();
new $.fn.dataTable.FixedHeader(table);
This is how I'm trying to delete the selected rows from my tables:
$("#roleSection").on("click","#removeRole",function (e) {
selected = table.rows('.selected').data().toArray();
console.log(selected);
$.each(selected, function (id, value) {
console.log(value);
dataSet.splice($.inArray(value, dataSet), 1);
table.row(selected).remove().draw();
});
console.log(dataSet);
return false;
});
For some reason the items that are not deleted are being deleted and the table does not get updated at all.
I think you can find your answer over here
Basically, you have to change your line selected = table.rows('.selected').data().toArray(); to table.rows( '.selected' ).remove().draw();
And remove the additional code.
You also don't have to worry about looping through the list because table.rows('.selected') gets all the rows with the class selected and then remove() deletes them all for you.
Edit: If the dataSet is not updated automatically, then I think this might answer your second query
$("#delete").on("click", function (e) {
let newDataSet = [];
table.rows( '.selected' ).remove().draw();
table.rows().every( function ( rowIdx, tableLoop, rowLoop ) {
let row = this;
newDataSet.push(row.data());
});
dataSet = newDataSet;
});
I'm using datatables and I have to select the first row of table.
The problem is select the first row when the table are reload (the table show the rooms of a building, so user can change the building).
This is my code:
function showRoom(idBuilding){
document.getElementById("roomTable").removeAttribute("style");
if ( ! $.fn.DataTable.isDataTable( '#roomTable' ) ) {
roomTable = $('#roomTable').DataTable({
responsive:true,
select: true,
"autoWidth": false,
"language": {
"emptyTable": "No room available!"
},
"ajax":{
"url": "/buildings/"+ idBuilding + "/rooms/",
"data": function ( d ) {
d.idRoomType = idRoomType;
},
"dataSrc": function ( json ) {
if (typeof json.success == 'undefined')
window.location.href = "/500";
else if (json.success){
return json.result.data;
}else{
notifyMessage(json.result, 'error');
return "";
}
},
"error": function (xhr, error, thrown) {
window.location.href = "/500";
}
},
"columns": [
{ "data": "name" },
{ "data": "capacity"},
{data:null, render: function ( data, type, row ) {
var string ="";
for (index = 0; index < data.accessories.length; ++index){
string = string + '<i aria-hidden="true" class="'+ data.accessories[index].icon+'" data-toggle="tooltip" title="'+data.accessories[index].name+'"style="margin-right:7px;" ></i>';
}
return string;
}
},
],
"fnInitComplete": function(oSettings, json) {
if (roomTable.rows().any()){
roomTable.row(':eq(0)').select();
selectedRoom(0);
}
initializeCalendar();
}
});
}
else {
roomTable.ajax.url("/buildings/"+ idBuilding + "/rooms/?idRoomType=" + idRoomType).load(selectFirstRow());
}
roomTable.off('select')
.on( 'select', function ( e, dt, type, indexes ) {
selectedRoom(indexes);
} );
roomTable.off('deselect').on( 'deselect', function ( e, dt, type, indexes ) {
reservationForm.room = -1;
$('#calendar').fullCalendar('option', 'selectable', false);
$("#calendar").fullCalendar("refetchEvents");
} );
}
function selectFirstRow(){
if (roomTable.rows().any()){
roomTable.row(':eq(0)').select();
selectedRoom(0);
}
initializeCalendar();
}
function selectedRoom(index){
var room = roomTable.rows( index ).data().toArray()[0];
reservationForm.room = room.idRoom;
$('#calendar').fullCalendar('option', 'minTime', room.startTime);
$('#calendar').fullCalendar('option', 'maxTime', room.endTime);
$('#calendar').fullCalendar('option', 'selectable', true);
$("#calendar").fullCalendar("refetchEvents");
}
On the first load all work fine, but when
roomTable.ajax.url("/buildings/"+ idBuilding + "/rooms/?idRoomType=" + idRoomType).load(selectFirstRow());
is called it seems to select the row before reload the table, so I have no row select (keep select the row of first load but now it is not visible).
Do you have idea how can I select on the load after?
UPDATE: the temporary solution is to use destroy: true but I would like a better solution like this:
if ( ! $.fn.DataTable.isDataTable( '#roomTable' ) ) {
roomTable = $('#roomTable').DataTable({
destroy: true, //it is useful because with standard code I have problem with first row selection, now it create the table each time
responsive:true,
select: true,
"autoWidth": false,
"language": {
"emptyTable": "No room available!"
},
"ajax":{
"url": "/buildings/"+ building.idBuilding + "/rooms/",
"data": function ( d ) {
d.idRoomType = idRoomType;
},
"dataSrc": function ( json ) {
if (typeof json.success == 'undefined')
window.location.href = "/500";
else if (json.success){
return json.result.data;
}else{
notifyMessage(json.result, 'error');
return "";
}
},
"error": function (xhr, error, thrown) {
window.location.href = "/500";
}
},
"fnDrawCallback": function(oSettings) {
if (roomTable.rows().any()){
roomTable.row(':eq(0)').select();
selectedRoom(0);
}
},
"fnInitComplete": function() {
initializeCalendar();
},
"columns": [
{ "data": "name" },
{ "data": "capacity"},
{data:null, render: function ( data, type, row ) {
var string ="";
for (index = 0; index < data.accessories.length; ++index){
string = string + '<i aria-hidden="true" class="'+ data.accessories[index].icon+'" data-toggle="tooltip" title="'+data.accessories[index].name+'"style="margin-right:7px;" ></i>';
}
return string;
}
},
],
});
}
else {
roomTable.ajax.url("/buildings/"+ idBuilding + "/rooms/?idRoomType=" + idRoomType).load(selectFirstRow());
}
But fnDrawCallback is called before ajax so I don't have the value, datatables keep on loading...
The fnInitComplete callback is called only when the datatable is initialized, so only once. You can use the fnDrawCallback, which is called every time the datatables redraws itself.
Just change fnInitComplete to fnDrawCallback. More about datatable callbacks (legacy version) here.
I am trying to render my Datatable with Scroller plugin in. Data is loading once but when scrolled further shows loading data only. Am I missing something ? I am trying to implement it in Salesforce Lightning. I have loaded Scroller Library v1.4.2 and DataTable v1.10.11
sessionTable = $j('#table-1').DataTable(
{
"info": true,
"searching": true,
"processing": false,
"dom": '<"div-pg"pi><"div-search"f><"div-tbl">t<"bottom-info"> ', // f search, p :- pagination , l:- page length
paging:true,
"order" : [[2,"asc"]],
"serverSide": true,
//scrollY: "200px",
scrollX : true,
"ajax": function (data, callback, settings) {
var allRecs = component.get("c.runQuery");
allRecs.setParams(
{
"request" : data ,
});
allRecs.setCallback(this, function(response)
{
console.log('in setCallback Populating Data' );
/*console.log(response.getReturnValue());*/
var state = response.getState();
if(state === 'SUCCESS' && response.getReturnValue != null)
{
//callback(JSON.parse(response.getReturnValue()));
//callback(sessionTable.rows.add(JSON.parse(response.getReturnValue())).columns.adjust().draw());
var resp = JSON.parse(response.getReturnValue());
console.log(resp);
setTimeout( function () {
callback( {
draw:resp.draw,
data: JSON.parse(resp.data),
recordsTotal: resp.recordsTotal,
recordsFiltered: resp.recordsTotal
} );
}, 200 );
});
$A.enqueueAction(allRecs);
},
scrollY: "300px",
scroller: {
loadingIndicator: true
},
scrollCollapse: true,
"language":
{
"emptyTable": "Loading Data"
},
The issue was with Salesforce Lightning, it was not returning the response.
Here is walkaround for this, we can force Salesforce to give response by adding following code after enqueuing:-
$A.enqueueAction(allRecs);
window.setTimeout(
$A.getCallback(function() {
console.log('Calling');
}), 200);
I am using DataTables to create a list of selectable phone numbers, my function is as follow:
function search(areacode) {
areacode = typeof areacode !== 'undefined' ? areacode : 239;
$("#did_search").fadeIn();
var table = $('#example').DataTable( {
"bDestroy": true,
"ajax": "/Portal/manage/search_bulkvs/" + areacode,
"columns": [
{ "data": "did" },
{ "data": "city" },
{ "data": "state" },
{ "data": "action" },
],
"columnDefs": [
{ "visible": false, "targets": 3 }
]
} );
$('#example tbody').on( 'click', 'tr', function () {
var row_object = table.row( this ).data();
$("label[for = did_label]").text(row_object.action);
$('input[name="did"]').val(row_object.action);
} );
}
The end of the function $('#example tbody') -- allows me to select the data from the table that I need and set the value of my label/input for form processing. However, after I run this function a second time I am unable to select this data anymore.
My debugging has led to this error: Uncaught TypeError: Cannot read property 'action' of undefined
I thought that row_object would be defined every time that the function is run, but it looks like it isnt.
Does anyone have any suggestions as to how I can retrieve this data from the table after the function has been run more than once?
If the ajax call replaces the tbody element of the table, you will need to attach your delegated event handler to a non-changing ancestor (e.g. $('#example').on or even $('#example').parent().on(.
You also want to avoid repeatedly setting up handlers if search is called multiple times (or call off before on).
e.g.
$('#example tbody').off('click').on( 'click', 'tr', function () {
var row_object = table.row( this ).data();
$("label[for = did_label]").text(row_object.action);
$('input[name="did"]').val(row_object.action);
} );
Since you're using ajax, you need to bind your click object on each draw using DataTables.fnDrawCallback, like this:
function search(areacode) {
areacode = typeof areacode !== 'undefined' ? areacode : 239;
$("#did_search").fadeIn();
var table = $('#example').DataTable( {
"bDestroy": true,
"ajax": "/Portal/manage/search_bulkvs/" + areacode,
"columns": [
{ "data": "did" },
{ "data": "city" },
{ "data": "state" },
{ "data": "action" },
],
"columnDefs": [
{ "visible": false, "targets": 3 }
],
"fnDrawCallback": function(){
$("tbody tr td",$(this)).click(function(e){
.... Your click code here ....
});
}
} );
}
It is not that this becomes undefined. This error message
Uncaught TypeError: Cannot read property 'action' of undefined
usually means that you are calling a function from an undefined object (here is row_object), or the function you are calling (action) is not on the object.
Yes, the definition of variable row_object is fine. But I think you can console.log it to see whether it is assigned to some value correctly every time.
i like to compartmentalize my files and modules. so gist of what's going on with the code below is i'm using an angular directive to create a datatable that will list departments. what i'm trying to get to happen is be able to nest another directive in the datatable for each row that displays some buttons that will get wired up to some events and be fed some parameters. right now doesn't load/respond/do anything. can i accomplish this nesting of directives declared in separate modules? additionally, is the directive going to call forth the template for every row, and is this a bad design?
primary module file. houses the controller
angular.element(document).ready(function () {
"use strict";
var deptApp = angular.module('deptApp', ['possumDatatablesDirective','EditDeleteRowControls']);
function DepartmentCtrl(scope, http) {
scope.depts = [];
scope.columnDefs = [
{ "mData": "Id", "aTargets": [0], "bVisible": false },
{ "mData": "Name", "aTargets": [1] },
{ "mData": "Active", "aTargets": [2] },
{ "mDataProp": "Id", "aTargets": [3], "mRender": function (data, type, full) {
return '<row-controls></row-controls>';
}
}
];
http.get(config.root + 'api/Departments').success(function (result) {
scope.depts = result;
});
};
DepartmentCtrl.$inject = ['$scope', '$http'];
deptApp.controller('DepartmentCtrl', DepartmentCtrl);
angular.bootstrap(document, ['deptApp']);
});
second module
// original code came from here http://stackoverflow.com/questions/14242455/using-jquery-datatable-with-angularjs
// just giving credit where it's due.
var possumDTDirective = angular.module('possumDatatablesDirective', []);
possumDTDirective.directive('possumDatatable', ['$compile', function ($compile) {
"use strict";
function Link(scope, element, attrs) {
// apply DataTable options, use defaults if none specified by user
var options = {};
if (attrs.possumDatatable.length > 0) {
options = scope.$eval(attrs.possumDatatable);
} else {
options = {
"bStateSave": true,
"iCookieDuration": 2419200, /* 1 month */
"bJQueryUI": false,
"bPaginate": true,
"bLengthChange": true,
"bFilter": true,
"bSort": true,
"bInfo": true,
"bDestroy": true,
"bProcessing": true,
"fnRowCallback": function (nRow, aData, iDisplayIndex, iDisplayIndexFull) {
$compile(nRow)(scope);
}
};
}
// Tell the dataTables plugin what columns to use
// We can either derive them from the dom, or use setup from the controller
var explicitColumns = [];
element.find('th').each(function (index, elem) {
explicitColumns.push($(elem).text());
});
if (explicitColumns.length > 0) {
options["aoColumns"] = explicitColumns;
} else if (attrs.aoColumns) {
options["aoColumns"] = scope.$eval(attrs.aoColumns);
}
// aoColumnDefs is dataTables way of providing fine control over column config
if (attrs.aoColumnDefs) {
options["aoColumnDefs"] = scope.$eval(attrs.aoColumnDefs);
}
// apply the plugin
scope.dataTable = element.dataTable(options);
// if there is a custom toolbar, render it. will need to use toolbar in sdom for this to work
if (options["sDom"]) {
if (attrs.toolbar) {
try {
var toolbar = scope.$eval(attrs.toolbar);
var toolbarDiv = angular.element('div.toolbar').html(toolbar);
$compile(toolbarDiv)(scope);
} catch (e) {
console.log(e);
}
}
if (attrs.extraFilters) {
try {
var filterBar = scope.$eval(attrs.extraFilters);
var filterDiv = angular.element('div.extraFilters').html(filterBar);
$compile(filterDiv)(scope);
} catch (e) {
console.log(e);
}
}
}
// this is to fix problem with hiding columns and auto column sizing not working
scope.dataTable.width('100%');
// watch for any changes to our data, rebuild the DataTable
scope.$watch(attrs.aaData, function (value) {
var val = value || null;
if (val) {
scope.dataTable.fnClearTable();
scope.dataTable.fnAddData(scope.$eval(attrs.aaData));
}
}, true);
if (attrs.selectable) {
// respond to click for selecting a row
scope.dataTable.on('click', 'tbody tr', function (e) {
var elem = e.currentTarget;
var classes = foo.className.split(' ');
var isSelected = false;
for (i = 0; i < classes.length; i++) {
if (classes[i] === 'row_selected') {
isSelected = true;
}
};
if (isSelected) {
scope.dataTable.find('tbody tr.row_selected').removeClass('row_selected');
scope.rowSelected = false;
}
else {
scope.dataTable.find('tbody tr.row_selected').removeClass('row_selected');
elem.className = foo.className + ' row_selected';
scope.selectedRow = scope.dataTable.fnGetData(foo);
scope.rowSelected = false;
}
});
}
};
var directiveDefinitionObject = {
link: Link,
scope: true, // isoalte the scope of each instance of the directive.
restrict: 'A'
};
return directiveDefinitionObject;
} ]);
third module
var EditDeleteRowControls = angular.module('EditDeleteRowControls', []);
function EditDeleteRowControlsDirective() {
"use strict";
var ddo = {
templateUrl: config.root + 'AngularTemplate/RowEditDeleteControl',
restrict: 'E'
};
return ddo;
};
EditDeleteRowControls.directive('rowControls', EditDeleteRowControlsDirective);