How to loop through all rows in DataTables jQuery? - javascript

I am using jquery plugin DataTables for building nice table
var table = $('#example').DataTable({
"data": source
});
I would like that make an each for all rows in table
Unfortunately this way may be out of date and does't work with new version (it launchs an error)
$(table.fnGetNodes()).each(function () {
});
And this way only works only for visibles rows (10 first rows because other rows are paginated)
table.each( function ( value, index ) {
console.log( 'Data in index: '+index+' is: '+value );
} );
Do you known how to loop to all rows please?

I finally found:
var data = table.rows().data();
data.each(function (value, index) {
console.log(`For index ${index}, data value is ${value}`);
});

Datatables have an iterator for each row rows().every() with this referring to the context of the current row being iterated.
tableName.rows().every(function(){
console.log(this.data());
});

If you are using the legacy DataTables then you can get all the rows even the paginated ones, as shown below...
table.fnGetNodes(); // table is the datatables object.
So we can loop through the rows by using .each() method provided by jQuery.
jQuery(table.fnGetNodes()).each(function () {
// You can use `jQuery(this).` to access each row, and process it further.
});

for example, this data has three fields UserID, UserName and isActive and we want to show only active users
The following code will return all the rows.
var data = $('#myDataTable').DataTable().rows().data();
We will print only active users
data.each(function (value, index) {
if (value.isActive)
{
console.log(value.UserID);
console.log(value.UserName);
}
});

Related

flitering multiple Datatables without using regex

I'm using Datatables 1.10.19 though I would happily upgrade if that will help.
I have an application with several tables on the same page. For one of those tables I want to offer the user the option to do a negative search. They enter a value and see all the rows that don't have that value.
So far as I can see the search() API allows simple text or regex criteria. I've seen examples such as this.
var allTables = $('table.dataTable').DataTable();
allTables.column( 0 ).search( 'mySearchTerm', true, false ).draw();
Some regex dialects support negative look ahead so regex such as those described in this answer would allow me to specify negation, but it appears that that the regex engine in use in Datatables does not work with such expressions.
My alternative is to use a filter function which I can establish with this:
$.fn.dataTable.ext.search.push()
However that seems to be a global construct affecting all tables, which I really don't want.
Any suggestions please?
You can use $.fn.dataTable.ext.search.push() - but it requires some additional work, to handle the fact (as you point out) that this is a global function, affecting all tables.
The following is not a full implementation, but shows the main points:
The Approach
My example uses 2 tables, with hard-coded data in each HTML table.
Each table is initialized as follows:
$(document).ready(function() {
// ---- first table with custom search ---------//
var table_a = $('#example_a').DataTable( {
pageLength: 10
} );
// remove the default DT search events - otherwise
// they will always fire before our custom event:
$( "#example_a_filter input" ).unbind();
// add our custom filter event for table_a:
$('#example_a_filter input').keyup( function( e ) {
table_a.draw();
} );
// ---- second table with DT default search ----//
var table_b = $('#example_b').DataTable( {
pageLength: 10
} );
} );
For my custom search function, I make use of the fact that the function includes a settings parameter which we can use to see which table is being searched:
$.fn.dataTable.ext.search.push (
function( settings, searchData, index, rowData, counter ) {
var tableID = settings.nTable.id;
var searchTerm = $('#' + tableID + '_filter input').val()
//console.log( tableID );
//console.log( searchTerm );
//console.log( searchData );
switch(tableID) {
case 'example_a':
if (searchTerm === '') {
return true;
} else {
show_me = true;
searchData.forEach(function (item, index) {
if (show_me && item.includes(searchTerm)) {
show_me = false;
}
});
return show_me;
}
break;
default:
// for all other tables, pass through the rows
// already filtered by the default DT filter:
return true;
}
}
);
The following line is where we ID which table is being filtered:
var tableID = settings.nTable.id;
After that, I can use a switch statement to handle each table's search separately.
In the default case (for example_b), I'm just passing through what was already filtered by the DT default search:
default: return true;
The above filter looks like this when I search each table for the letter x:
Incomplete Implementation
This logic is incomplete for the custom search logic. It assumes the search term is a single string. If I enter "x y" in the input field, that will exclude all records where a field contains "x y" - which is probably not what you want.
You probably want the exact negation of the standard search - so the input term would need to be split on spaces and each sub-term (x and y) would need to be checked separately across each row of data.

Filter one ag-grid based on event from another one

I want to select one row in my first grid grid1 and the event function would then filter my other grid grid2 based on the values found in the selected row. I am using the pure javascript version of the library.
Something like
gridOptions:{
onRowSelected:my_event_filter_func,
rowData: [...],
columnDefs:[...]
}
grid1 = new agGrid.Grid(document.querySelector("#the_place"),gridOptions)
(grid2 is defined the same way based on different data and w/o the event function)
where my_event_filter_func is
my_event_filter_func = function(event) {
let my_name = event.data.name
// filter grid2 to show only the rows where the 'name' column matches my_name
}
Any help is appreciated.
I can't give you a line by line answer, and I am assuming that you are able to get your selected rows. But what I can suggest is, first, you create a copy of your the data that is on your grid2.
function copyData() {
rowData = [];
gridApi.forEachNode(node => rowData.push(node.data));
// temp is the copy of your full data in grid2
temp = [...rowData];
}
Next, on your my_event_filter_func, you can filter out the rows to be shown on grid2, based on the filtered value from grid1.
function my_event_filter_func(event) {
let my_name = event.data.name
// get the rows that do not have the matching value
const rowsToBeRemoved = temp.filter(row => row['name'] !== my_name);
// remove the rows from grid2 that do not have the matching names
gridOptions.api.updateRowData({remove: rowsToBeRemoved});
}
The source for the 2 grids is the underlying data for grid1 so it made my life easier. If that is not the case, you do need to save your base data for grid2 somewhere so that you can access it when the event gets triggered.
I ended up declaring my 2 grids as global variables and using the function below as event function :
var onSelectionChanged = function(event) {
let name = grid1.gridOptions.api.getSelectedRows()[0].name; // we know there is only one
let newRowData = grid1.gridOptions.rowData
.filter(x => x.name===name)
.map(x => {
return {
'name': x.name
// other fields...
}
})
// this overwrites grid2 data so need to save original data somewhere.
grid2.gridOptions.api.setRowData(newRowData);
grid2.gridOptions.api.refreshCells({force:true});
};

DataTables loop through the table and delete all rows that contain certain string in certain column

Been trying to work this out for a while:
In column under index 6 in my DataTable, I have a boolean on Croatian language -> DA for 1 and NE for 0. At one point I want to fire a procedure that will delete all rows that contain "DA" in the column under index 6, however, after the following procedure:
function deleteSelectedDiscountedProducts() {
tableSelectedProducts.rows().every( function ( rowIdx, tableLoop, rowLoop ) {
var currentData = this.data();
if (currentData[6].indexOf("DA") >= 0) {
tableSelectedProducts.row(rowIdx).remove().draw(false);
} else {
}
} );
}
I get only one row deleted (probably the first one detected) and the following in the console:
Uncaught TypeError: Cannot read property '6' of undefined
Also, I tried switching tableSelectedProducts.row(rowIdx).remove().draw(false); with this.remove().draw(false); and it does absolutely the same error deleting only the first row it detects.
What is happening in the background and how to solve this? It seems to me that after deleting one row all the data from the datatable doesn't exist anymore (column under index 6 is undefined) and when I tried to console.log(this) for each of the rows detected, I don't get any output after the first detected row is deleted, but an error above.
It is bad practice to delete array items by their indexes in a loop. Once you have deleted one item all indexes may have been changed. It is better to pick up a list of the row dom nodes you want to delete, and then delete them. Here is an example :
$('#delete').on('click', function() {
var nodes = [];
table.rows().every(function(rowIdx, tableLoop, rowLoop) {
if (this.data()[3] == 'Edinburgh') nodes.push(this.node())
})
nodes.forEach(function(node) {
table.row(node).remove().draw()
})
})
demo -> http://jsfiddle.net/LqzLzxon/

How to show the actual item's index in datatacle?

In my app, I need to show the index of the data entry in the first datatable column and it must work after DnD (so I suppose the column should be dynamically refreshed). But how is it possible in Webix datatable?
For now, I am able to get the index manually using getIndexById, but this method doesn't work in the column template. For instance:
/* inside the config */
drag:true,
columns:[
{ id:"index", template:function(obj){
console.log(obj.id);
// doesn't work:
// console.log(datatable.getIdByIndex(obj.id));
} },
{ id:"id" },
{
id:"title", fillspace:true, sort:"string"
}
],
ready:function(){
this.eachRow(
function (row){
console.log( this.getIndexById(row) ) // works
}
)
}
});
/* somewhere else */
console.log(datatable.getIdByIndex(4));
Code sample.
Is this possible at all? Thanks.
To get the index of row (data entry) you must define your index template as:
template: function(obj){
return $$("dt").getIndexById(obj.id); }
where "dt" is the id of your datatable. It automatically changes the index when you perform any DnD operation. Further, check the snippet here.

Get Devexpress Gridview Sort By and Sort Order in Javascript

I am implementing Devexpress Grid Control in MVC. I was stuck at a point where i need the current Sorted By column and Sort Order (asc/desc) in javascript. I also tried the clientSide Event OnColumnSortingChanged(s , e) , it is only providing the name of the column at click event not from the gridview javascript object.
Got the answer after research...
Have to add CustomJsProperty to the control in the partial view as below
settings.CustomJSProperties = (s, e) =>
{
var Grid = s as MVCxGridView;
var result = new System.Collections.Hashtable();
foreach (var col in Grid.AllColumns)
{
var dataCol = col as GridViewDataColumn;
if (dataCol != null)
{
if (dataCol.SortIndex == 0)
{
e.Properties["cpColumnsProp"] = new Dictionary<string, object>()
{
{ "sortcolumn", dataCol.FieldName },
{ "sortorder", ((Convert.ToString(dataCol.SortOrder).Equals("Ascending")) ? "asc" : "desc")}
};
}
}
}
};
Handle the ColumnSortingChange event as follows
function gvChartList_OnColumnSortingChanged(s, e) {
$("#hdsortname").val(e.column.fieldName); // contains the sort column name
$("#hdsortorder").val(((s.cpColumnsProp.sortcolumn == e.column.fieldName) ? "desc" : "asc")); // contains the sort column order
}
Last but not the least, One must have to define the default sort index and sort order for the column
settings.Columns.Add(col =>
{
// column details
col.SortIndex = 0;
col.SortAscending();
});
I recently needed similar, where I wanted to save the column order, sort order, and filter information; such that a user could create saved views of a grid, and not have to keep re-entering all these preferences.
I found that in an event CustomJSPropeties I could interact with a sender being an ASPxGridView, such that I could grab a needed value from ASPxGridView.SaveClientLayout(). Also useful here can be the FilterExpression, and the VisibileRowCount - if you want to use the filter expression for exporting, but only when the VisibleRowCount is less than a certain threshold (this is the number of rows shown in the bottom pager area)
settings.CustomJSProperties = (s, e) =>
{
ASPxGridView gridView = (ASPxGridView)s;
e.Properties["cpGridFilterExpression"] = gridView.FilterExpression; //Make Filter Expressions Availabe to JavaScript
e.Properties["cpVisibleRowCount"] = gridView.VisibleRowCount; //Make Visible Row Count Availabe to JavaScript
e.Properties["cpLayout"] = gridView.SaveClientLayout(); //Get Layout String and make it available to JavaScript
};
So what does this do? Properties defined in this event are available as properties of the javascript grid view object. So here we grab these values when we can, and place them in a place where we normally cannot access them.
And then, right from JavaScript we can now access GridView.cpLayout (where GridView is the name/id supplied to your grid.)
<script type="text/javascript">
$(document).ready(function () {
$('#saveButton').click(
function () {
var layout = GridView.cpLayout;
//Perform Save...
}
);
});
</script>
To be clear, this "layout" contains sort order, visible column info, and filter information.
Layout:
https://documentation.devexpress.com/#AspNet/CustomDocument4342
https://documentation.devexpress.com/#AspNet/DevExpressWebASPxGridViewASPxGridView_SaveClientLayouttopic
CustomJSProperties:
https://documentation.devexpress.com/#AspNet/DevExpressWebMvcGridViewSettings_CustomJSPropertiestopic
Note: I add this solution here because this is what I found when I was searching for my issue. As one can see, these are similar topics of accessing the AspxGridView (base of) or MVCGridView within a CustomJSProperties event handler.

Categories

Resources