Reputation: 1995
I am trying to loop through a DataTable to pick up the value of two columns, the first contains and ID and the second the amount so I can create an array to be passed to update the ID with the amount on the database. My code returns "undefined". How do I return the value in column 'x' for each row please?
function disperse() {
memDispTable.rows().every(function() {
var row = this.data();
console.log(row[0]);
// Create array to send for updating
});
}
In the DataTable column 0 is:
{data: 'cdId',
visible: false,
searchable: false},
Column 6 (the amount to update) is an input field:
{data: null,
className: "center",
defaultContent: '<input class="ilValue" type="number" min="0" max="99999.99" step=".01" placeholder="0.00">'
},
The result of:
var row = this.data();
console.log(row);
Is:
cdFirstName: "Tendon"
cdId: "MTQ5"
cdSurname: "Achilles"
grpId: "MQ=="
section: "Cub"
__proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()
I am now iterating through the rows. The first row contains an amount:
However, when I iterate through the Total is returned for a different row:
And when I sort the Total is returned for a different row again:
The Total on the page stays with the correct row when sorted (i.e., Glyn Bartlett).
My code is:
function postDispersements() {
//Disperse the amounts to each person
//Iterate through each row
memDispTable.rows().data().each( function ( rowData, index ) {
var scoutNo = rowData.scoutNumber;
var surname = rowData.cdSurname;
var firstName = rowData.cdFirstName;
var amtNode = memDispTable.cells(index, 7).nodes().to$()[0];//Total column
var amt = parseFloat($('input', amtNode ).val());
if (isNaN(amt)) {
amt = 0.0;
}
amt = (Math.floor((amt + Number.EPSILON) * 100) / 100).toFixed(2);
//There are a large number of records so only log the rows with an amount
if (amt > 0) {
console.log("scoutNo: " + scoutNo + " surname: " + surname + " firstName: " + firstName + " amt: " + amt);
}
});
}
Upvotes: 1
Views: 4668
Reputation: 1995
Just to make it clear in case someone else is in a similar situation. If your are using:
tablename.rows().data().each( function ( rowData, index ) {
Then, within the loop, do not use:
var surname = rowData.surname;
As the value returned may not be in the same row as:
var amtNode = memDispTable.cells(index, 7).nodes().to$()[0];//Total column
var amt = parseFloat($('input', amtNode ).val());// Returns the value in the
Use this instead:
var surname = memDispTable.cell( index, 3 ).data();
And all values returned will be in the same row.
In full:
function postDispersements() {
//Disperse the amounts to each person
//Iterate through each row
memDispTable.rows().data().each( function ( rowData, index ) {
//var surname = rowData.surname; //Do not use this it will return a value; however, may not the the same row as your <input>
var surname = memDispTable.cell( index, 3 ).data(); // Use this
var amtNode = memDispTable.cells(index, 7).nodes().to$()[0];//Total column
var amt = parseFloat($('input', amtNode ).val());// Returns the value in the <input>
});
}
Upvotes: 1
Reputation: 21907
Revised answer:
Your function for iterating over row data memDispTable.rows().every(function() {...})
looks good.
However, the structure of the data in each row can be either an array:
[ "value 1", "value2", "value3", ... ]
or an object:
{ field1: "value1", field2: "value2", field3: "value3", ... }
If you are not able to access values in the row data using an array index, such as row[0]
, then that suggests you need to access the data using field names: row.field1
.
You can double-check the structure of a row by printing the entire row to the console:
memDispTable.rows().every(function() {
var row = this.data();
console.log(row);
});
That will show you the row structure - and, if it's an object, you will also see the field names you need to use.
Whether you have row data as arrays or objects depends on how the data was provided to DataTables in the first place. Typically, it's via JSON data - so it depends on the structure of that JSON.
Revised Approach
Based on the updated info in the question, you have data which looks like the following sample (for two rows of test data):
[
{ "cdFirstName": "Tendon",
"cdId": "MTQ5",
"cdSurname": "Achilles",
"grpId": "MQ==",
"section": "Cub"
},
{ "cdFirstName": "John",
"cdId": "MTQ6",
"cdSurname": "Smith",
"grpId": "MQ==",
"section": "Cub"
}
]
This means you can access values in each row using the following:
memDispTable.rows().every(function() {
var row = this.data();
console.log(row.cdId);
});
So, you were very close in your comment this.row.cdId
- you just did not need the "this" part.
However, you also want to get the entered money amount from each row - and that requires a different approach. Because the amount is entered manually by a user into a field, that data is not directly visible to DataTables - it's part of the HTML table, but not part of the DataTables object.
We can combine the above row()
iterator with the same technique used previously to keep track of the grand total assigned amount, to get what you need.
That would be something like this:
function disperse() {
memDispTable.rows().data().each( function ( rowData, index ) {
var amtNode = memDispTable.cells(index, 5).nodes().to$()[0];
var amt = parseFloat($('input', amtNode ).val());
if (isNaN(amt)) {
amt = 0.0;
}
console.log( "ID: " + rowData.cdId + ", amount: " + amt );
} );
}
This iterates over each table row to get the cdId
value - which is in DataTables.
We also use a cells(index, 5)
function to get a specific cell (5) in the current row. And then we use the nodes()
function to help DataTables get access to the user-entered value in that specific cell.
Putting it all together, we have something like this - which should work as a stand-alone test file, if you want to try it (and then adapt to your specific code):
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.21/css/jquery.dataTables.min.css">
<link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/big-integer/1.6.48/BigInteger.min.js"></script>
</head>
<body>
<div style="margin: 20px;">
<div id="showsum">Grand Total: $0.00</div>
<br><br>
<table id="demo" class="display dataTable cell-border" style="width:100%">
</table>
</div>
<script type="text/javascript">
var dataSet = [
{ "cdFirstName": "Tendon",
"cdId": "MTQ5",
"cdSurname": "Achilles",
"grpId": "MQ==",
"section": "Cub"
},
{ "cdFirstName": "John",
"cdId": "MTQ6",
"cdSurname": "Smith",
"grpId": "MQ==",
"section": "Cub"
}
];
var table;
function doSum() {
var sum = 0.0;
memDispTable.columns(5).nodes().to$()[0].forEach(function (item) {
var amt = parseFloat($('input', item ).val());
if (!isNaN(amt)) {
sum += amt;
}
});
sum = (Math.round((sum + Number.EPSILON) * 100) / 100).toFixed(2);
$('#showsum').text("Grand Total: $" + sum);
disperse();
}
function disperse() {
memDispTable.rows().data().each( function ( rowData, index ) {
var amtNode = memDispTable.cells(index, 5).nodes().to$()[0];
var amt = parseFloat($('input', amtNode ).val());
if (isNaN(amt)) {
amt = 0.0;
}
console.log( "ID: " + rowData.cdId + ", amount: " + amt );
} );
}
$(document).ready(function() {
memDispTable = $('#demo').DataTable( {
"data": dataSet,
"columns": [
{ title: "ID", "data": "cdId", "visible": false, "searchable": false },
{ title: "First Name", "data": "cdFirstName" },
{ title: "Surname", "data": "cdSurname" },
{ title: "Group", "data": "grpId" },
{ title: "Section", "data": "section" },
{ title: "Amount" }
],
"columnDefs": [ {
"targets": 5,
"name": "amt",
"data": function ( row, type, val, meta ) {
return '<input type="number" min="0" max="99999.99" step=".01" placeholder="0.00" onchange="doSum()">';
}
} ]
} );
disperse();
} );
</script>
</body>
</html>
This demo prints the following to the console:
ID: MTQ5, amount: 0
ID: MTQ6, amount: 0
And as the amounts are changed, the print-out shows the changes:
ID: MTQ5, amount: 1.23
ID: MTQ6, amount: 456.78
Upvotes: 1