jqGrid: update a row AND have its formatters updated as well - jqgrid

Ideally I would call setRowData and have my cell formatters and rowattr function re-run, but cell formatters and rowattr functions don't re-run when calling setRowData (I don't know why but that's another question maybe), so setRowData isn't really helpful for me.
It seems the next easiest thing to do would be to remove a row and re-add a new one at the same position with the same model. To do that I need to get the rowid of the row above the selected row so that I can call addRowData and specify the ID of the row above in srcrowid and use 'after' for the position. This is what I'm thinking:
$.jgrid.extend({
updateRow: function(rowid, model){
// get index from id
var index = this.jqGrid('getInd', rowid);
// note: my first row's index is 1 (is that normal?)
if ( index == 1 ){
position = 'first';
srcrowid = 'n/a';
}
else{
position = 'after';
srcrowid = _____ how to get rowid of row above selected row _____???
}
// delete row
this.jqGrid('delRowData', rowid);
// insert at index
this.jqGrid('addRowData', rowid, model.attributes, position, srcrowid);
}
});
How can I get the rowid of the row above the selected row? (Is there an easier way? Is this a bad strategy?)
Note: I'm using backbone.js collections and models

I find the best way to change the row is to use setRowData instead of usage delRowData and addRowData. If you know rowid then you can use $("#" + rowid); (or if rowis have special characters like :, . an so on then $("#" + $.jgrid.jqID(rowid));) to get the <tr> element. Then you can use jQuery.addClass, jQuery.css, jQuery.attr to change the attributes of the row.
It's important to understand that jqGrid uses the same methods internally it it's required to modify element of the grid. The main goal of rowattr is another one. During filling of the grid data there are many scenarios. One can create DOM elements for <td> and <td> and insert there in the grid. The main problem is performance in case of working with DOM. It's much slowly as building of strings. Moreover DOM is even much more slowly if the elements are exist on the the HTML page (in opposite to disconnected elements). If one modify one element only from the grid having 500 rows then the position of elements of all other rows need be recalculated.
Because of the problem jqGrid construct the whole body of the grid first in string format and then assign all <tr> and <td> elements using one set of innerHTML. It improves dramatically the performance of filling of the grid. See the answer for additional information. The formatters and callbacks cellattr and rowattr are introduced to allow to customize cell and row attributes during building of grid body in string format. It gives you customization possibilities without reducing of performance.
On the other side if you need to modify the row which are attached already on HTML page then you will have no advantage with working with strings instead of DOM. Because of that I recommend you just use jQuery.addClass, jQuery.css, jQuery.attr directly. If you need to change multiple classes, assign multiple css rules or multiple attributes then you should use one call of above functions. You can use object form of jQuery.css, jQuery.attr for it.

The updateRow extension below works, BUT I ended up not using it. Not so much for the reasons Oleg talked about (which I assume are valid and something you should definitely consider), but because I had a filter provider that was too difficult to sync with (e.g. after soft deleting a row, I need to now determine if new deleted status agrees with current filter...and that's a pretty simple example). So I just defer to the data the filter provider gives me and repopulate the grid each time, which I'm not fond of, but I don't see other easy options.
As far as the extension below goes, here are pros/cons as I see them:
Pros:
easy to use
You just rely on the rowattr functions and cell formatters you already defined. You don't have to write those twice.
Cons:
possibly performance--see Oleg's answer
please add any you see
Unknowns:
performance? I have no idea how much worse it performs. It would be interesting to do benchmarks with different browsers. I saw no problems, but I only have maybe 20 rows. Let's say we're working with 500 rows and adding/removing classes and calling .css() took 30 ms but using the extension took 300 ms on a 'typical' machine/browser. That would be 10 times slower, but for me it would probably be worth it because I don't have to write something twice.
here's the extension:
$.jgrid.extend({
updateRow: function(rowid, data){
// get index from id
var index = this.jqGrid('getInd', rowid);
// note: my first row's index is 1 (is that normal?)
if ( index == 1 ){
position = 'first';
}
else{
position = 'after';
srcrowid = $(this).find('tr#' + rowid).prev()[0].id;
}
// delete row
this.jqGrid('delRowData', rowid);
// insert at index
this.jqGrid('addRowData', rowid, data, position, srcrowid);
}
});

Related

Access html-element from grid in loadComplete

So what I'm trying to accomplish is when the grid is fully loaded, I loop over a certain column that contains checkboxes. Depending on the value of the checkbox I should be able to disable it.
Problem is that I can't access the html element that's there. Am i doing something wrong or overlooking something?
What i've tried:
loadComplete: function() {
// Fetch all the ID's of the rows
var rows = $("#table").getDataIDs();
// Loop over the rows
if(rows.length != 0){
for(i=0; i < rows.length; i++) {
// Get the data so we test on a certain condition
var row = $("#table").jqGrid("getRowData", rows[i]);
if (row.gridCheckbox == 1) {
//disable the element
row.prop("disabled", "disabled");
}
}
}
}
It's important to understand that changing one element on the page follow in the most cases to web browser reflow: validation whether some property (position for example) need be changed in all other elements on the page. If you do changes in the loop then your JavaScript code can be really slow.
Thus it's strictly recommended to reduce the number of changes of the DOM. Especially to reduce the number of changes jqGrid provides rowattr, cellattr and custom formatters. If you need for example to set disabled attribute on some rows then you should now do this in loadComplete, but to use rowattr instead to inform jqGrid that some additional attributes (disabled="disabled") should be set on some rows. jqGrid collect first the string representation of the whole table body and it use one assignment of innerHTML to fill the whole body of the grid in one DOM operation. It improves essentially the performance. See code example in the old answer.

Hiding columns of handsontable from javascript

Is there any way i can hide HOT columns from javascript?
The requirement is such that the column to hide will come as a parameter in javascript and based on that the respective column will show hide accordingly.
The HOT has rowHeaders and colHeaders and the data with 20 columns.
Please advise.
OUTDATED SOLUTION
Ok I founnd a possible solution. I tested it out on my own system but it's actually quite simple.
You should be using a customRenderer in your columns option. Read up about this if you aren't already. The idea is that you're giving each cell its own renderer. In this custom function, you can do something like this:
var colsToHide = [3,4,6]; // hide the fourth, fifth, and seventh columns
function getCustomRenderer() {
return function(instance, td, row, col, prop, value, cellProperties) {
if (colsToHide.indexOf(col) > -1) {
td.hidden = true;
} else {
td.hidden = false;
}
}
}
What this renderer does is hide the cells that the var colsToHide specify. All you do now is add a DOM element that lets the user pick which and so every time the table gets rendered (which happens basically after any change, or manually triggered need be), the cells in the columns specified will be hidden, keeping the data array intact like you described. And when not in colsToHide they are re-rendered so make sure you get that working as well.
Here I implemented it with very basic functionality. Just enter the index of a column into the input fields and watch the magic happen.
http://jsfiddle.net/zekedroid/LkLkd405/2/
Better Solution: handsontable: hide some columns without changing data array/object

How to select a row in kendo grid by data item ID?

I need to select a specific row in kendoGrid but NOT by data-uid (as data-uid is changed when the grid dataSource is loaded again) but by the row itemID. I saw posts but they only select the row by uid which is not what I needed, I actually need to restart the HTML5 application and when grid is loaded, a specific item should be selected. This is what I've been seeing
Demo: jsfiddle.net/rusev/qvKRk/3/
e.g. the object has OrderID as ID, and every time the grid is loaded, it will be the same, unlike uid, I want to know how will I be able to select a row with OrderID, instead of uid.
You cam mix row itemID and data.uid, I guess.
var grid = $("#Grid").data("kendoGrid");
var dataItem = $("#Grid").data("kendoGrid").dataSource.get(itemID);
var row = $("#Grid").data("kendoGrid").tbody.find("tr[data-uid='" + dataItem.uid + "']");
Going along with what umais has mentioned, the better approach, since there is no built in functionality for this as of yet, would be to iterate through all the records to find the one you need. The function that I built will work even if there are pages of data. The only other way that I can think of doing this would be do do a secondary ajax call; But this works well. Note that i haven't tested it with more than 2000 records.
var dataGrid = $("#GATIPS").data("kendoGrid").dataSource;
var numOfRows = dataGrid.total();
var currentPageSize = dataGrid.pageSize();
dataGrid.pageSize(numOfRows);
var dataGridData = dataGrid.data();
for (var i = 0; i < numOfRows; i++) {
if (dataGridData[i].uid == e)
return dataGridData[i];
}
dataGrid.pageSize(currentPageSize); // reset the view
e is the UID. However this can be substituted for what ever variable you need just replace the check.
a work around that I managed to have, was to go through all rows and check which row model has that ID equal to the parameter, and then get that row data-uid and select the item through data-uid. It's working fine for me, since there were no suggestion, it's the better answer for now.
Well, accordingly to what I have done (and worked for me), and even though the work around isn't the prettiest, set one more Column, with your model id and with ClientTemplate then create any html object (div in my case) inside it give it a html id of your id, so when ever you need it, you just have to go and look with something like:
grid.dataItem($("td div#id").closest("tr"));
Because remember that the dataItem method is waiting for a selector then you get your selectedItem as regular one.
EDIT:
I forgot to say, that you should (or could) use the style property
display:none
If you don't want to display that col.

Dynamically adding subgrid to identical parent grid

I need the ability to add a random amount of subgrids to a jqgrid. Basically the subgrid is idential to the parent jqgrid apart from having their column headings hidden. Is there a way where I can define the grid once in say a js file method and have the grid id and data url passed in as a parameter and then append different versions of itself into its subGridRowExpand after its defined. It just seems very laborious to have to define multiple versions of the same jqgrid one inside the other.
Could I do something like
var i = 0;
var maxsubgrids = 5;
function CreateGrid(gridId, dataUrl) {
$(gridId).grid(
...... Grid definition
subGridRowExpand: function(subgrid_id, row_id) {
if (subgridcount < maxsubgrids){
CreateGrid('#subgridId' + i++, subgridDataURL);
}
}
......... continue with grid definition
}
I know the above isn't correct but just an idea, but I think it would be better if the grid could be just created once in a method and then find a way to insert the subGridRowExpand section afterwards. Is this even possible?
You should consider to use TreeGrid instead of Subgrids. It's important to understand that subitems of TreeGrid have always the same number of columns like it's parent elements. So I suppose it corresponds to requirements which you have. Of extending of tree node nodeid, parentid and n_level will be automatically added to the list of parameters of the URL (see the documentation).

jqgrid: How to format master/detail grids?

I have a jqgrid with a subgrid.
I am attempting to apply different colors to master and detail grids. I have two rules: the first one is to alternate odd and pair colors and the other one is to apply specific CSS to the row, based on values of a specific field.
Both master & details grid, contains the following gridComplete functions, where obviously childnodes index varies cause tables contains different fields:
gridComplete: function () {
var _rows = $(".jqgrow");
for (var i = 0; i < _rows.length; i++) {
_rows[i].attributes["class"].value += " " + _rows[i].childNodes[4].textContent;
_rows[i].attributes["class"].value += " " + _rows[i].childNodes[4].innerText;
}
applyZebra("jqTicketgrid");
}
applyZebra function provides to alternate odd/pair colours and has already been tested on another grid which not contains a subgrid.
For the record, I found above solutions in other solved questions of this forum, and both works with "simple" jqgrids (not master/detail).
PROBLEM
The master grid is formatted only when I click to expand the detail rows, while detail subgrid never alternate colours, neither apply format based on cell contents...
Where I am wrong? Pheraps I must intercept another event which is not gridComplete? Otherwise with grid&subgrids it's impossible to use _rows[x] & childNodes[y] attributes?
Please ask for clarifications, if needed, thx.
Thanks in advance!
I suppose the error in your code is that you use $(".jqgrow") instead of $(".jqgrow", this) where this inside of gridComplete will be either DOM element of the <table> of the grid or the subgid (I suppose you use grid as subgrid).
Additionally I would not recommend you to use you current code at all. It's much more effective and simple to to use cellattr. The rawObject parameter allow you access all other cells of the current row. In the answer you will find an example of implementation.

Resources