DataTable does not re-draw after updating rows - javascript

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.

Related

jQuery DataTables iterate over rows and change cell background

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.

Kendo UI Grid update only changed cell/column

When performing an update on the grid it sends all column data.
I have something where updates are performed after the cell is closed:
change: function (e) {
if (e.action == "itemchange") {
this.sync();
}
}
Instead of sending all the data for every column, how can I get it to only send the data that was changed?
You can check for Isdirty flag.When cell data is modified the respective model item is marked as Isdirty=true.
var data = grid.dataSource.data();
var dirty = $.grep(data, function(item) {
return item.dirty
});
// Dirty array contains those elements modified
console.log("dirty", dirty);
Here I'm doing for the entire grid data.You can do the same for single row.

SAPUI5 dynamic binding of table cells

I have the following Problem:
I want to dynamically create table rows and cells with different settings.
The Solution mentioned here: Dynamic binding of table column and rows
was a good starting point for my problem, but I still could not get it to work.
The table should display each object of the model in a new row with the binding for the given attributes of that object.
The checked attribute should be displayed in/as a checkbox that is either checked or unchecked depending on the value (true or false) of checked.
Now, this works perfectly fine if I define the bindings and columns as they are in the SAPUI5 Table Example
The Problem:
Depending on value (true or false) of the objects existsLocal attribute I want the checkbox of that row to be either enabled or disabled. Further that row should get a new class - called existsLocalClass wich sets its background to grey if existsLocal is true.
I was thinking that this can be solved with a factory function that creates my rows and its cells. Unfortunately my factory does not work as intended.
Here is my code:
Model definition:
var model = [
{name: "name1", description: "description1", checked: true, existsLocal: true},
{name: "name2", description: "description2", checked: false, existsLocal: false}
]
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData({modelData: model});
Table plus factory function:
var oTable = new sap.ui.table.Table({
visibleRowCount: 7,
firstVisibleRow: 3,
selectionMode: sap.ui.table.SelectionMode.None
});
var tableRowFactory = function (sId, oContext) {
console.log("row factory");
var exists = oContext.getProperty("existsLocal");
if(exists){
return new sap.ui.table.Row(sId)
.addCell(new sap.ui.commons.TextView()
.bindProperty("text", oContext.sPath + "/name"))
.addCell(new sap.ui.commons.TextView()
.bindProperty("text", oContext.sPath+ "/description"))
.addCell(new sap.ui.commons.CheckBox()
.bindProperty("checked", oContext.sPath+ "/checked").setEnabled(false))
.addStyleClass("existsLocal");
}else{
return new sap.ui.table.Row(sId)
.addCell(new sap.ui.commons.TextView()
.bindProperty("text", oContext.sPath + "/name"))
.addCell(new sap.ui.commons.TextView()
.bindProperty("text", oContext.sPath+ "/description"))
.addCell(new sap.ui.commons.CheckBox()
.bindProperty("checked", oContext.sPath+ "/checked"))
}
};
oTable.setModel(oModel);
oTable.bindRows("/modelData",tableRowFactory); // does not work
oTable.bindAggregation("rows", "/modelData", tableRowFactory); //doesn't work either
The browser does not show any errors and the table stays empty. I think the function does not even get called but I could not manage to fix it.
Maybe my entire approach is wrong - I don't really understand sapui5's binding and context thingy.
I hope that you can help me with this.
Edit:
I found a kinda hacky solution for this:
var model = oTable.getModel();
var rows = oTable.getRows();
var indicesOfRows = [];
$.each(rows, function (index, row){
indicesOfRows.push(oTable.indexOfRow(row));
});
$.each(rows, function(index, row){
var rowIndex = indicesOfRows[index];
var exists = model.getProperty("existsLocal", oTable.getContextByIndex(rowIndex));
var cells = row.getCells();
if(exists){
$.each(cells, function(index, cell){
if(cell instanceof sap.ui.commons.CheckBox){
row.$().toggleClass("existsLocal", true);
cell.setEnabled(false);
}
})
}
})
Instead you could bind to column with template. You have only rows binding and table does not know the columns.
BTW, You can define "enable" property of the checkbox with formatters. You need factory only for addStyleClass when necessary
So something like that: http://jsbin.com/poyetoqa/1/edit
See my edited solution in the original question. If you have a better working solution feel free to answer. Meanwhile I'll mark the question as answered.

jqgrid get hidden column value with getRowData

I've checked the jqgrid documentation page, and also here, here and here but none of them answers my problem.
I have a jqgrid with the inline navigator (the buttons at the bottom left of the grid that allow adding/editing rows) displayed.
The grid has a hidden column, with the name hidden_col.
I would like to make the following - When the user selects a row and tries to delete it, the javascript makes an alert - which shows the value of hidden_col for the selected row.
For this, I have the following code
$("#myjqgrid").jqGrid('navGrid',"#myjqgrid_pager",
{}, //options
{}, // edit options
{}, // add options
{ mtype:"POST",
reloadAfterSubmit:true, //Reload data after deleting
onclickSubmit: function(rowid)
{
var rowData = $('#broadcast_table').jqGrid('getRowData', rowid);
alert(rowData);
}
}, // del options
{} // search options);
);
The alert returns "[Object object]". How can I get the value of hidden_col?
I tried adding
var col_value = rowData.hidden_col;
And
var col_value = rowData['hidden_col'];
But both return undefined.
I checked the value in rowid - it is correct. I also know that hidden_col has a value for each row.
What can I be doing wrong?
Turns out I was not using the parameter "rowid" as I should.
Here is the code, which I replaced in the first post, that does what I want:
onclickSubmit: function(){
var selected_row = $('#myjqgrid').jqGrid('getGridParam', 'selrow');
var rowdata = $('#myjqgrid').getRowData(selected_row);
alert(rowdata.hidden_col);
}

Javascript placing table rows between rows with greater and smaller ID

I'm building a system which outputs a list of cars on a screen(in a table element). The page loads the updates automatically with an HTTP call to the server.
Every car has an ID, a status and some irrelevant things.
Now when the user loads the page, the cars without the statuses 'maintenance' and 'wrecked' are shown and every five seconds new JSON data will be loaded from the server. If there comes a car out of the maintenance this one should be added to the table. The table is sorted by the car id and here comes the problem.
I have written a bit of pseudo code to clarify my problem:
if (row_with_greater_id_exits && row_with_lower_id_exists) {
place_row_between_firstRowWithGreaterId_and_FirstRowWithLowerId();
} else if (is_row_with_greater_id) {
jQuery('table#cars tbody').append(generatedHtml);
} else if (is_row_with_lower_id) {
jQuery('table#cars tbody').prepend(generatedHtml);
}
The problem is I don't know how to find the first row with a greater id or the first row with a smaller ID. The ID's are not always succeeding because some cars are wrecked and have the status wrecked.
I hope someone here has had a similar problem and can help me on my way to the solution.
Many thanks in advance!
You need to loop over the rows, and compare the ids. When your new row has and ID less than the current row in the loop, insert the new row before the current row, and break the loop.
rows.each(function(i, el) {
if (+newrow.id < +el.id) {
$(el).before(newrow);
return false;
}
})
if (!newrow.parentNode)
rows.parent().append(newrow);
This code assumes rows is a jQuery object that has a collection of all the rows, and newrow is a DOM element representing the new row.
Also assumes that the IDs are simple numbers. Note that numeric IDs are only valid in HTML5.
Personally, I'd just use the native API for this:
var tbody = document.querySelector("tbody");
tbody.insertBefore(newrow, [].reduce.call(tbody.rows, function(bef, el) {
return bef || +newrow.id > +el.id ? bef : el;
}, null));
No need to test for the isFirstLoad. When the tbody is empty, it'll still work. But you'll need a .reduce() shim for older browsers.
I have this: id="car-1" data-id="1"
I'll assume that data attribute is on the tr elements. Obviously you can adapt the following if it is on a cell within a row.
Loop through the table checking each row's id, and insert the new row immediately before the first row that has an id greater than the new one:
// assume newId is the new ID, somehow set from your JSON
var rowInserted = false;
jQuery('#invoices-outstanding tbody tr').each(function() {
var $row = $(this);
if (+$row.attr("data-id") > newId) {
$row.before(generatedHtml);
rowInserted = true;
// break out of each loop
return false;
}
});
if (!rowInserted)
jQuery('#invoices-outstanding tbody').append(generatedHtml);

Categories

Resources