I am trying to iterate over all cells in a column (column index 1) in a DataTable and change the background color based on cell value using the following code:
var table = $('#my_table').DataTable( {...});
console.log("next, iterate over rows in table: "+table);
table.rows().every( function ( rowIdx, tableLoop, rowLoop ) {
console.log("looping over rows");
var cell = table.cell({ row: rowIdx, column: 1 }).node();
if (cell.data() == 'mouse'){
$(cell).css('background-color', 'orange');
}
});
console.log("finished iterating over rows ");
The table is displaying the data fine.
However the console log prints:
>>next, iterate over rows, table: [object Object]
>>finished iterating over rows
ie the
table.rows().every( function (...){...}
is not entered. I copied and pasted from DataTables examples and I have no idea why it is not being executed.
The only thing I can think of is that the DataTables docs here: https://datatables.net/reference/api/rows().every() mention- Iterate over each selected row. None of the rows in the table are selected, I just want to loop through every row (and change cell color) regardles if it is selected or not.
Note I also tried:
table.rows().eq(0).each( function ( index ) {
var row = table.row( index );
var data = row.data();
console.log(data)
});
And this is not executed either (console.log doesn't print anything from inside the function).
You can iterate over the table's td elements and capture the text content of each cell.
Apply some logic to these and you can easily assign each cell's background colour.
I have used arr.map() as it's ES6 JavaScript, but .each() works too.
$('table td').map(function(i, cell) {
var cellContent = $(cell).text();
console.log(i,cellContent); // for demonstration
if (cellContent === 'pending') $(cell).css('background-color', '#ccc');
});
This can be easily changed to get the cell element's data, class, or id too.
Related
I'm currently using the DataTables plugin for my project.
I have an AJAX sourced datatable where you can only ever have one row selected, now because my datatable is done server-side I need to keep track of which one is selected when changing pages.
Therefore I have been using this solution but this only seems to work for multiple row selection
Now essentially what I want to happen is, when you select a new row it should add the new row id to the array but also remove the previously added row id from the array, so there should only ever be one result in the array at a time.
Visually for better understanding:
var selected = []
Click Row 1 after loading table = [row_1]
Click Row 2 removing row_1 and adding row_2 = [row_2]
var selected = [];
$("#example").DataTable({
"processing": true,
"serverSide": true,
"ajax": "scripts/ids-arrays.php",
"rowCallback": function( row, data ) {
if ( $.inArray(data.DT_RowId, selected) !== -1 ) {
$(row).addClass('selected');
}
}
});
$('#example tbody').on('click', 'tr', function () {
var id = this.id;
var index = $.inArray(id, selected);
if ( index === -1 ) {
selected.push( id );
} else {
selected.splice( index, 1 );
}
$(this).toggleClass('selected');
} );
Instead of adding an element to the array, you could replace the whole array. It seems a bit wasteful to use an array to store a single element, but there you go.
selected.push( id );
becomes
selected = [id];
I have a table in which I can edit and modify each cell.
I would like to highlight the cell that I modified.
At the moment I can only highlight the entire row but I don't have what I want to do.
I use createdRow to make the cells editable and get the modified row.
How can I do to highlight that modified cell?
var table = $("#deploymentMap_table").DataTable({
data: constructRaws(dataSet),//tbody
paging: false,
searching: false,
info: false,
fixedHeader: true,
scrollY: false,
scrollX: false,
responsive: false,
dom: 't', //display only the table
order: [[ 0, 'asc' ]],//order by 'service' col
columnDefs:[
{
targets:'_all',
render:function(data){
if(data == null) {return ""
} else {return data;}
}
},
{ targets: [0,1], "width" : "200px"},
],
columns: constructColumns(dataSet),//thead
dom: 'Bfrtip',
// attribute classname (background color) for services
rowCallback: function(row, data, index){
if ( data.code == 1 ) {
$('td', row).each( function ( value, index ) {
if($(this).contents().first().text()){
$(this).addClass('td_colorCD');
}
} );
}
$(row).find('td:eq(0)').css('background-color', '#7f7f7f').css('color', '#fff').css('text-align', 'left');
$(row).find('td:eq(1)').css('background-color', '#7f7f7f').css('color', '#fff').css('text-align', 'left');
$.each(row.childNodes, function(i,value){
if(value.innerText == "NoUP"){
$(value).addClass('td_colorBSF');
}
else if(value.innerText){
$(value).addClass('td_color');
}
})
},
// Make all cell editable
createdRow: function(row, data, dataIndex, cells) {
console.log(cells);
let original
row.setAttribute('contenteditable', true)
row.setAttribute('spellcheck', false)
row.addEventListener('focus', function(e) {
original = e.target.textContent
})
row.addEventListener('blur', function(e) {
if (original !== e.target.textContent) {
$('td', row).removeClass();
$('td', row).addClass('td_color_change');
const r = table.row(e.target.parentElement)
r.invalidate();
var lign = e.target.innerText;
lign = lign.split('\t');
var nRow = $('#deploymentMap_table thead tr')[0].innerText;
head = nRow.split('\n\t\n');
var newAR = mergeArrayObjects(head, lign);
console.log("newAR", newAR);
$(dataSet).each(function( index, values ) {
if(newAR.service[0].Services == values.service_name){
delete values.regions;
values.regions = newAR.region;
console.log(values);
}
})
console.log("dataset", dataSet);
}
})
}
});
I think the easiest way to handle this is to replace your rowCallback with a DataTables delegated event.
Below is a simple example which would change the color of a specific cell when you leave that cell:
Step 1) The onblur event requires the cell to have a tabindex attribute. You can add this however you wish - but here is one way, in your existing code:
$.each(row.childNodes, function(i,value){
$(value).attr('tabindex', i); // this line is new
// your existing code goes here
})
Note - this could be improved as it repeats tab indexes across rows. But it illustrates the approach.
Step 2: Add a new onblur event listener, after the end of your DataTable definition:
$('#deploymentMap_table td').on('blur', function () {
this.classList.remove("td_color");
this.classList.add("td_color_change");
} );
Step 3: The above code would need to be enhanced to include your edit-checking logic, which checks for an actual cell value change.
You can get the "before" cell values using this:
table.cell( this ).data();
And the "after" cell values using this - which gets the value from the HTML table (the DOM node), not from DataTables:
table.cell( this ).node().textContent;
The updated listener would be something like this:
$('#deploymentMap_table td').on('blur', function () {
var cellValueStart = table.cell( this ).data();
var cellValueEnd = table.cell( this ).node().textContent;
//console.log( cellValueStart );
//console.log( cellValueEnd );
if (cellValueEnd !== cellValueStart) {
table.cell( this ).data(cellValueEnd);
this.classList.remove("td_color");
this.classList.add("td_color_change");
}
} );
The table.cell( this ).data(cellValueEnd) command updates the cell in DataTables so that it matches the value you typed into the HTML cell. If you do not do this, then the data in the DataTables object (behind the scenes) will be out-of-sync with the data in the HTML table (what you see on your screen).
Warning: This approach is basic. It does not cover the case where a user may do the following:
Edit a cell from "A" to "B".
Leave the cell, so it is highlighted.
Return to the cell and edit it back from "B" to "A".
Leave the cell again.
In this case, the cell will remain highlighted.
One way around this is to capture the original state of every cell when you first load the table - and then check each edit against the value in the original data. This can be done, if needed - but is outside the scope of this question. But it also depends on what you need to do with the data, after you have finished editing it. If this is important to you, then it may be worth asking a new question for that specific problem.
I'm using the DataTables library to create a table with extra functionality. What I'd like to achieve, is that the user can select rows and then press a button. This will call the server, do some stuff and the rows should be updated accordingly.
However, after I'm done iterating over the rows to be changed and setting its values, re-drawing the table does not actually update its values. I update the data object, invalidate the cache and call table.draw(). It's very similar to the last example on this page.
I have created a JSFiddle of this issue. The button updates the date objects of the selected rows and the table is re-drawn, but the data inside the table is not updated. The core JS code:
$('#updateRow').click(function() {
//Get the table
var table = $('#example').DataTable();
//Iterate over selected rows
var rowData = table.rows({
selected: true
}).every(function() {
//For every selected row, update startDate
var d = this.data();
d.startDate = "01/01/2017";
console.log('Set startDate of ' + d.name + ' to ' + d.startDate);
//Invalidate the cache
this.invalidate();
});
//Re-draw the table
table.draw();
});
I forked and did the solution from your JsFiddle. Here's the relevant snippet from fiddle https://jsfiddle.net/k38r9be5/1/
var rowData = table.rows({
selected: true
}).every(function(rowIdx) {
var colIdx = 4; // startDate is the fifth column, or "4" from 0-base (0,1,2,3,4...)
table.cell( rowIdx, colIdx).data('01/01/2017').draw();
});
Basically, via the API you can get the cell object itself, and modify the contents with .data(). In your version you weren't actually getting a particular cell object and instead just copied the data contents of the row to a variable, and modified that.
I'm working on making a dynamic HTML table using jQuery. In a table, my user has two interactions:
Append a row
Remove a specific row
The problem with numbering the rows is that if a user removes a specific row, all of the rows following that row need to be renumbered. I would have to select all rows following the removed row and subtract their number by 1.
Is there a better way to go about this?
EDIT: Here's a JSFiddle demonstrating the problem: http://jsfiddle.net/LNXae/2/
I'm aware that an ordered-list would automatically renumber my rows, but I'd rather use a table since the example I'm giving now is pretty boiled-down.
http://jsfiddle.net/mblase75/LNXae/1/
First, wrap the counter number in a <span> with a class for easy finding later:
$new_row.children('td').prepend('Row #<span class="num">' + ($new_row.index() + 1) + "</span>");
Then update all these spans with an .each loop after you remove the desired row. The first argument passed into .each's callback function is a zero-based index number, and the second is the HTML element:
var $row = $(this).closest('tr'),
$table = $row.closest('table');
$row.remove();
$table.find('tr').each(function(i, v) {
$(v).find('span.num').text(i + 1);
});
After the user has appended a row, or deleted one, you just need to iterate over the "number" cells. If we assume that you have a <td> element, we:
1) give them a nice ID, e.g. row_0, row_1, etc...
2) write a function to iterate over them:
function updateRows(){
$('[id*="row_"]').each(function(index){
$(this).html(index + 1); // add +1 to prevent 0 index.
};
};
I have written a jquery plugin which does exactly this, and you shouldnt need to "number" the rows per-se. All you need to do when deleting a row is to pass the index of the row being deleted.
eg, if you have a delete button in a row:
<table>
<tr>
<td> <input type="button" class="delete" value="delete this row" /></td>
</tr>
</table>
The jQuery might look like
$('.delete').click(function(){
var index = $(this).parents('tr').index();
// tell your plugin to delete row "index"
});
The method from my plugin which does this looks something like:
removeRow: function (index) {
return this.each(function () {
var $this = $(this);
var $tbody = $('tbody', $this);
var $tr = $('tr', $tbody).eq(index);
$this.trigger('rowRemoved', [$tr]);
$tr.remove();
});
}
I have a dynamically created (when I click on the cell) <input type=date> inside a cell of a DataTable.
I can select the date and looks good, now I get all the data in the table iterating each row because I process the data for every row, that works fine too, the problem is when I want to get the value from those inputs.
I tried with data() and node() but the value isn't shown on the HTML which I found out that was the way it's supposed to be, so I can't get it from the HTML, so I tried with the following code and it says it's undefined.
table.rows().every( function ( rowIdx, tableLoop, rowLoop ) {
// Tried this - return undefined
var node = this.node();
alert(node.cells[0].value);// The typeof(node.cells[0]) is object HTMLTableCellElement
// also this - here shows the HTML without the updated date
var data = this.data();
alert(data);
});
Any ideas?
SOLUTION
Use the code below to access value of input inside the cell in the first column (column: 0).
var table = $('#example').DataTable();
table.rows().every( function ( rowIdx, tableLoop, rowLoop ) {
var cell = table.cell({ row: rowIdx, column: 0 }).node();
console.log($('input', cell).val());
});
DEMO
See this jsFiddle for code and demonstration.