jqGrid Custom Formatter Set Cell wont work with options.rowId - jqgrid

Ive been through all the posts, finally got setCell to work with hardcoded values, but not using the options.rowId.
function StatusFormatter(cellvalue, options, rowObject) {
if (cellvalue == 'C'){
jQuery("#list").setCell(options.rowId , 'SOORDLINE', '', { color: 'red' });
jQuery("#list").setCell("[2.000]", 'SOORDLINE', '', { color: 'red' });
jQuery("#list").setCell('[2.000]', 'SOREQDATE', '', { color: 'red' });
jQuery("#list").setCell(options.rowId, 'SOPRICE', '', { color: 'red' });
}
return cellvalue;
};
The FIRST and LAST lines dont work, but the 2 with the hardcoded rowId DO work. I inspected what comes back in the option.rowId and they are the same as the hardcoded values, (just different depending on the row of course. What am I missing? Please help. I dont see any difference between the lines, or values.
EDITED-
I tried the answer, and it seems to be what I need. I tried the following
{ name: 'SOORDLINE', index: 'SOORDLINE', width: 25, search: false ,celattr: function () { return ' style="color: red"'; }
},
To aleast make them all red before I dove into the logic, and it didnt do anything for me.

Sorry, but you use custom formatter in absolute wrong way. The goal of the custom formatter to to provide HTML fragment to fill the content of the cells in the corresponding column. So the StatusFormatter will be called before the row with the id equal to options.rowId will be created. Moreover for performance purpose one use typically gridview: true. in the case the whole content of the grid (the whole body of the grid) will be constructed first as string and only after that will be placed in the grid body in one operation. It improve the performance because after placing of any element web browser have to recalculate position of all other elements on the page.
If you want to set text color on the SOORDLINE cell you should cellattr instead:
celattr: function () { return ' style="color: red"'; }
The celattr can be used also in the form celattr: function (rowId, cellValue, rawObject) {...} and you can test the property of rawObject which represent of the values for any column and return the cell style based on the cell value.
Alternatively you can enumerate the rows inside of loadComplete and set the style on <tr> element instead of setting the same styles for every row. See the answer as an example.

Related

Jqgrid using cellattr to toggle a class on seperate cell

in my col model i have two cells 'Status' and 'HiddenStatus'. The reason for this is 'Status' is translatable so this way is better rather than checking the value for each language. As you can see below i am attempting to set the class of the 'Status' cell based on the value of the 'HiddenStatus' cell. However this is not working as i hoped since the class is not being set correctly.
I believe the issue i am having is, 'getCell' is used to return the value rather than an object. How can i get the cell as an object so i can then manage what class i add or remove.
{name: 'Status', width: 70, index: 'Status'},
{name: 'HiddenStatus', width: 70, hidden: true, cellattr : function(rowId, cellValue, rawObject, cm, rdata){
var statusCell = $(this).jqGrid('getCell',rowId,'Status');
if(cellValue != "Assigned"){
$(statusCell).removeClass('status-assigned');
return '';
}
if(cellValue == "Assigned"){
$(statusCell).addClass('status-assigned');
return '';
}
}},
First of all, it's important to understand what cellattr do. Any changes on the existing page are expensive. Thus jqGrid try to build the whole HTML fragment with the table body as one long string. Every column will be used to build the cells (<td> elements) of the corresponding columns of the grid. The callback cellattr will be called during building the cell and can be used to set attributes on the cell. The cellattr callback have to return the string. If it returns, for example, " class='status-assigned'" then the <td> will have the class (<td class='status-assigned'>...</td>).
The callback cellattr will be called before the grid will be created. Thus one can't access to the grid using $(this).jqGrid('getCell',rowId,'Status'), for example.
If you need to set class status-assigned conditionally on the cells of the column Status then you should define cellattr callback in the column Status. Inside the callback you can use rawObject.HiddenStatus or rdata.HiddenStatus. One don't need typically to create hidden columns like HiddenStatus. Instead of that, it's enough to use include all properties of input data, which one need, in additionalProperties option of jqGrid. For example, additionalProperties: ["HiddenStatus"].
Your original code could be modified to the following:
{
name: 'Status', width: 70,
cellattr: function (rowId, cellValue, item) {
if (item.HiddenStatus === "Assigned") {
return " class='status-assigned'";
}
}
}
See the old answer for an example of usage cellattr.

JqGrid Performance - setRowData lags

setRowData takes almost 5 seconds when the grid has 300 rows, 30 cols, and 4 frozen cols.
$("#tbl").jqGrid({
gridview: true,
url: '../controller/GetData',
datatype: "json",
rowNum: pageSize,
viewrecords: true,
loadtext: '',
loadui: 'disable',
rowList: [1000, 2000, 3000],
width: $(window).width() - LeftMargin,
shrinkToFit: false,
pager: '#dvPager',
pagerpos: 'left',
colNames: GetColNames(selectedViewName, viewCols),
colModel: GetColModel(selectedViewName, viewCols),
cmTemplate: {
title: false
},
recordtext: "Displaying {0} - {1} of {2}",
rowattr: function (rowData) {
},
//onCellSelect: function (rowid, iCol, cellcontent, e) {
// e.stopPropagation();
// proto.editcell(rowid, iCol, cellcontent, e);
//},
loadComplete: function (data) {..},
onPaging: function (data) {..},
serializeGridData: function (postData) {..}
});
Can you please guide me with the performance tuning tips?
In GetColModel we are binding columns as follows -
'Discount': {
name: 'Discount', index: 'Discount', width: colModelWidthDict['Discount'], title: false, sortable: false, resizable: colResizable, hidden: !bReadCalculationSellInfo,
formatter: function (cellValue, option, rowObject) {
if (rowObject.level == 0 || (rowObject.Flag == 0 && (rowObject.Discountable && rowObject.Discountable.toLowerCase() == 'no')))
return '';
else {
if (!proto.IsReadOnly(rowObject) && ((rowObject.Flag == 0 && (rowObject.Discountable && rowObject.Discountable.toLowerCase() == 'yes')) || rowObject.Flag > 0))
return proto.GetControls("Discount", option.rowId, "Numeric", rowObject.Discount, 6, 90)
else
return '<span class="amt">' + cellValue + '</span>';
}
},
unformat: function (cellValue, option) {
return cellValue;
},
cellattr: function (rowId, val, rowObject, cm, rdata) {
if (parseInt(rowObject.PPPChngDisc) == 1)
return ' style="color:red"';
}
}
//code for colModel - 1 column above
In general you should prefer to modify only small number of rows. If you modify one row then the web browser have to recalculate position of all other rows (500 rows) of the grid. In the case modifying 300 rows means 300*500 operations for the web browser.
If you fill the whole grid and you use gridview: true option then jqGrid places at the beginning all the data for the grid body in array of strings. After preparing of all information in string format jqGrid place the whole body of the grid as one operation. It's just one assigning innerHTML property of tbody. Thus it's more effective to reload the whole grid as to make modification of many rows of the grid in the loop using setRowData.
So I would recommend you to reload the grid in your case.
Moreover you should consider to reduce the number of rows in the page of grid. If you use rowNum: 500 you just reduce the performance of your page tin many times without any advantage for the user. The user can see about 20 rows of the data only. Only if the user scrolls he/she is able to see another information. In the same way the user could click next page button. Holding 500 rows force web browser make a lot of unneeded work. Modifying of the first row from 500 the web browser have to recalculate position of all 500 rows. Even if the user move the mouse over a row the web browser change the class of the hovering row and it have to recalculate position of all other from 500 rows event the rows are not visible.
One more remark. The implementation of frozen columns in jqGrid 4.6 is slow. Starting with the end of 2014 and publishing 4.7.1 with changing Lisanse and making jqGrid commercial I develop free jqGrid as fork based on jqGrid 4.7 (see the readme for more details). I implemented a lot of changes and new features in the fork. The recent changes includes many improvement of frozen columns feature. If you loads free jqGrid or just try it directly from GitHub by including the corresponding URLs (see the wiki) you will see that the performance of frozen columns is dramatically improved. Additionally frozen columns supports now row and cell editing in all editing modes. I plan to publish free jqGrid 4.9 soon. So I recommend you to try it.
UPDATED: You posted the code, which you use in comments below. I see the main problem in the implementation of Process function which will be called on change in the <input> fields on the grid. I recommend you to try something like this one:
function Process(contrl) {
var $cntrl = $(contrl),
$td = $cntrl.closest("tr.jqgrow>td"),
$tr = $td.parent(),
rowId = $tr.attr("id"),
newValue = $cntrl.val(),
$grid = $("#list"),
p = $grid[0].p,
colModel = p.colModel,
columnName = colModel[$td[0].cellIndex].name, // name of column of edited cell
localRowData = $grid.jqGrid("getLocalRow", rowId),
iColTotal = p.iColByName.total;
// modify local data
localRowData[columnName] = newValue;
localRowData.total = parseInt(localRowData.quantity) * parseFloat(localRowData.unit);
// modify the cell in the cell (in DOM)
//$grid.jqGrid("setCell", rowId, "total", localRowData.total);
$($tr[0].cells[iColTotal]).text(localRowData.total);
return false;
}
One can event improve the code and not use setCell at all. It's important to understand that local grid hold the data in the form of JavaScript object. The access to the data is very quickly. You can modify the data without any side effects existing with DOM elements. In the above code I use only relative search inside of the DOM of the row using closest and parent. It works very quickly. I recommend to save $("#list") in the variable outside of the Process (move var $grid = $("#list") in the outer function) and just use $grid variable. It will make access to the DOM of page very quickly. The line localRowData = $grid.jqGrid("getLocalRow", rowId) get the reference to internal JavaScript data object which represent the internal data of the row. By modifying the data by localRowData[columnName] = newValue; or localRowData.total = ... we make the half of job. One need only to change the value in the DOM on the cell Total. I used iColByName which exist in the latest sources of free jqGrid on GitHub. It get just the column index in colModel by column name. One can find the same information alternatively if one use more old jqGrid. The line $($tr[0].cells[iColTotal]).text(localRowData.total); shows how to assign manually the data in the cell. It's the most quick way to do this, but one assign the data without the usage formatter. For more common case (for example in case of frozen "total" column) one can use the commented row above: $grid.jqGrid("setCell", rowId, "total", localRowData.total);.

JqGrid setCell properties lost when sorting column

Just after editing a row (mode inline) I try to change some css properties of cells according the new value.
Typically : After editing of one row all cell of this row that contains the letter "D" I update the cell with a new css property : background-color: grey (using setCell method)
For that I use inline editing :
grid.jqGrid('navGrid',"#pager",{edit:false, add:false, del:false});
grid.jqGrid('inlineNav',"#pager",{edit:true, add:false, del:false, editParams: myEditParam});
For change the background after editing I use the method aftersavefunc
myEditParam :
...
aftersavefunc: function(rowId, dataFromServer)
{
var rowData = $("#list").jqGrid("getRowData", rowId);
for (var key in rowData)
{
if (rowData[key] == "D")
{
key++;
$("#list").jqGrid("setCell",rowId, key, "", {"background-color": "#ECECEC"} );
}
}
},
...
This code works but unfortunatly, when I sort one column of the grid the setCell method is not perserved ! (the cell lost it's background-color: grey)
Does it exist a better method for change the background after editing in function of the new value ?
Thx for your help ;)
I would suggest removing the Style from that event and rather move it to the more general function below. If the style isn't applied you can always trigger a refresh on the jqGrid as part of your after edit code.
The following function will examine each column cell value and if the TestValue is matching add the class to the row.
rowattr: function (rd) {
if (rd.ColumnName == TestValue) { return {"class": "RowBoldClass"}; }//if
},
and the matching class
RowBoldClass { font-weight:bold; .....
My answer from Making a row bold, changing background color - dwr
If you really need to change the format/color/style of the cell in the column which can the value "D" then you should use cellattr (see the answer or this one).
If you need to change the format/color/style of the row then you should use rowattr (see the answer).
One thing is important to understand: neither cellattr nor rowattr will be called at the end of row editing. So you will still have to use aftersavefunc callback.
The current code of aftersavefunc seems me a little strange. First of all I never had requirements to mark the value in any column of the grid based on the value ("D" in your case). Typically one need to test only specific column or columns for the value and then mark the cell or mark some other cell in the row.
In any way one need typically not just add the class in the value will be "D", but remove the class if the value is not "D".
I modified the demo from the answer to support inline editing (one should use double-click to start editing and press Enter to stop editing). The modified demo uses the following code of aftersavefunc additionally to cellattr used in the old demo:
aftersavefunc: function (rowId) {
var closed = $(this).jqGrid("getCell", rowId, "closed"), indexOfColumn;
if (closed === "Yes") {
// add CSS classes to the cell used to mark
$(this).jqGrid("setCell", rowId, "name", "",
"ui-state-error ui-state-error-text");
} else {
// remove CSS classes from the cell used to mark
indexOfColumn = getColumnIndexByName.call(this, "name");
$(this.rows.namedItem(rowId).cells[indexOfColumn])
.removeClass("ui-state-error ui-state-error-text");
}
}

Get the client side value of a grid cell containing a <select>

I am trying to write a jquery function that scans the whole of a jqrid to check if any of its cells have a value.
The issue I am having is that there does not seem to be a way of retrieving the selected value of a cell that contains a select box. The jqgrid docs clearly states the following for the getCell and getRowData methods.
Do not use this method when you
editing the row or cell. This will
return the cell content and not the
actuall value of the input element
Which is fair enough, but given that, how do I actually get the value?
Its not possible to parse the html that is returned from the select content, as none of the options are flagged as selected, even if they appear to be selected in the browser.
For reference here is a snippet of my code:
var colModels = this.grid.jqGrid('getGridParam', 'colModel');
for (i = 1; i < colModels.length; i++) {
var colModel = colModels[i];
if (colModel.edittype == 'select') {
var colData = this.grid.jqGrid('getCol', colModel.name, false);
for (j = 0; j < colData.length; j++) {
if (colData[j] != 0) {
//alert("select change: " + colData[j]);
//alert(j+' GridName_' + colModel.name)
//alert("select change: " + $('#GridName_' + colModel.name).val());
//return has value?;
}
}
}
}
Column definiton:
{ name: "AppleId", index: "Appled", width: 150, align: "left", resizable: false, editable: true, edittype: "select", editoptions: { value: function() { return xxx.buildAppleSelect(); } }, formatter: function(cellvalue, options, rowObject, action) { return xxx.buildAppleSelectHtml(cellvalue); } };
I also experimented with afterEditCell and other similar events - but the problem with these is that - clicking the select box does not put the sell in edit mode - you have to click the cell first and then the select.
In short - how do I get the selected value, client side - can it be done?
There are simular questions here, here and here. But none seem to tackle the issue (client side).
No. Here is some HTML that I obtained from a test grid using getRowData:
<select class="editable" size="1" name="test" id="5_test">
<option value="0">Zero</option>
<option value="1">One</option>
<option value="3">Three</option>
<option value="4">Four</option>
</select>
You are right - there is not enough information in the markup to determine which value is selected. In order to get the selected value you will have to bring the row out of edit mode, for example by using grid method saveRow.
It seems to me Dan that you thy to go in a wrong way. I am not really understand why you do want to have grid cell containing of <select>, but if you'll explain me what do you want I am sure I'll find a solution of you problem.
First I explain what I find strange in your question. If you define edittype: "select", then jqGid has typically a string and not a <select> element inside. If you are in en edit mode (for example in inline edit mode), then all other rows excepting selected row has also a string and not a <select> element inside. If user make a chose and press enter, the edit mode will be ended and the modified data will be saved (or send to the server). So it is also not important which values were displayed before.
It seems to me you have some problems because of some custom building of values in buildAppleSelect and custom formatting in buildAppleSelectHtml.
If you be want see intermediate values from select you can use dataEvents with 'change' in the editoptions.
I hope now you understand what I find strange in your question. If you explain me what is your problem and why you do have more then one <select> element and want to read intermediate select values I'll try to find a solution for you.
UPDATED: I posted a code which shows how use dataEvents with 'change' in JQGrid Inline Editing : Filter subcategory dropdown list based on another category dropdown. Probably it will help you.

jqgrid change pointer to hand

I want to change the pointer to hand when hovering over jqgrid's rows
Is there an API for that?
This can be done more easily using the classes colModel property as below:
{ name: 'Email', index: 'Email', classes: 'pointer' }
From the wiki:
This option allow to add classes to the column. If more than one class will be used a space should be set. By example classes:'class1 class2' will set a class1 and class2 to every cell on that column. In the grid css there is a predefined class ui-ellipsis which allow to attach ellipsis to a particular row. Also this will work in FireFox too.
I just add this into my css file
#mygrid .jqgrow{
cursor:pointer;
}
Use a custom formatter on any cell in the grid. For more info on these, see http://www.trirand.com/jqgridwiki/doku.php?id=wiki:custom_formatter
Here's how I did it. I wanted the first column in my grid to appear like it is a clickable link (but really it triggers a custom jqgrid event, onCellSelect).
Snippet of my grid object:
colModel :[
{name:'ticket', index:'IMINDT', width:125, formatter: pointercursor},
pointercursor is a function name. The code for it is defined like this:
// Custom formatter for a cell in a jqgrid row.
function pointercursor(cellvalue, options, rowObject)
{
var new_formatted_cellvalue = '<span class="pointer">' + cellvalue + '</span>';
return new_formatted_cellvalue;
}
My CSS class of "pointer" is:
.pointer {
cursor: pointer;
text-decoration: underline;
}
That's it!
in css file put this:
.ui-jqgrid .ui-jqgrid-btable { cursor : pointer; }
It seems to me that you have not a jqgrid question, but pure CSS or javascript question. Look at How to get cursor to change before mouse moves when changing the cursor style dynamically for example. It shows how can one change cursor style of a html element. See also in http://www.quirksmode.org/css/cursor.html, that 'hand' is supported not in all browsers.

Resources