I have a requirement to allow a user to cancel a jqGrid (Version 4.4.1) paging or sorting operation if they have any selections that they do not want to lose.
I initially attempted to handle this in the beforeRequest event handler but when I call the selarrrow function an empty array is always returned as the selections appear to have already been cleared.
I then tried adding onPaging and onSorting event handlers where the selections were available via the selarrrow function, however, when I return 'stop' from these functions to cancel the request (as specified in the jqGrid documentation) the selections still appear to have been cleared. Note the rows still appear selected in the grid but selarrrow returns an empty array.
I'm guessing this is a jqGrid defect but does anyone know if it has been fixed in a more recent release or if there is a configuration workaround?
I think that there are just a bug in usage of onPaging. If the method return "stop" the selection still cleared. The reason is the order of the lines in the code fragment
clearVals = function(onpaging){
var ret;
if ($.isFunction(ts.p.onPaging) ) { ret = ts.p.onPaging.call(ts,onpaging); }
ts.p.selrow = null;
if(ts.p.multiselect) {ts.p.selarrrow =[]; setHeadCheckBox( false );}
ts.p.savedRow = [];
if(ret==='stop') {return false;}
return true;
};
The correct code should be
clearVals = function(onpaging){
var ret;
if ($.isFunction(ts.p.onPaging) ) { ret = ts.p.onPaging.call(ts,onpaging); }
if(ret==='stop') {return false;}
ts.p.selrow = null;
if(ts.p.multiselect) {ts.p.selarrrow =[]; setHeadCheckBox( false );}
ts.p.savedRow = [];
return true;
};
You can move the line 2045 (with if(ret==='stop') {return false;}) of jquery.jqGrid.src.js of the version 4.5.2 (which corresponds the line 1902 in version 4.4.1) after the 2041 (the line 1898 in version 4.4.1) (after if ($.isFunction(ts.p.onPaging) ) { ret = ts.p.onPaging.call(ts,onpaging); }) to fix the bug.
The usage of onSortCol seems be correct and if the callback returns "stop" string the selection should stay unchanged.
UPDATED: I posted the corresponding bud fix as pull request. It's merged today (see here) to the main code of jqGrid. So the next version (>4.5.2) should not have more the problem which you described.
This is the workaround I have put in place for this problem (note: it requires Underscore.js) but interested in a cleaner solution if anyone has one:
var tempSelections,
myGrid = $("#mygrid"),
checkSelections = function() {
var selections = myGrid.jqGrid("getGridParam", "selarrrow");
if (selections && selections.length > 0) {
tempSelections = selections;
}
};
myGrid.jqGrid({
... //settings
multiselect: true,
onPaging: checkSelections,
onSortCol: checkSelections,
beforeRequest: function() {
if (tempSelections && tempSelections.length > 0) {
if (!confirm("Do you want to clear the selections on this page?")) {
_.forEach(tempSelections, function(selection) {
myGrid.jqGrid("setSelection", selection);
});
tempSelections = null;
return false;
}
tempSelections = null;
}
return true;
}
});
I have written a multiselect jQuery plugin that can be applied to a normal HTML select element.
However, this plugin will parse the select element and its options and then remove the select element from the DOM and insert a combination of divs and checkboxes instead.
I have created a custom binding handler in Knockout as follows:
ko.bindingHandlers.dropdownlist = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
// This will be called when the binding is first applied to an element
// Set up any initial state, event handlers, etc. here
// Retrieve the value accessor
var value = valueAccessor();
// Get the true value of the property
var unwrappedValue = ko.utils.unwrapObservable(value);
// Check if we have specified the value type of the DropDownList items. Defaults to "int"
var ddlValueType = allBindingsAccessor().dropDownListValueType ? allBindingsAccessor().dropDownListValueType : 'int';
// Check if we have specified the INIMultiSelect options otherwise we will use our defaults.
var elementOptions = allBindingsAccessor().iniMultiSelectOptions ? allBindingsAccessor().iniMultiSelectOptions :
{
multiple: false,
onItemSelectedChanged: function (control, item) {
var val = item.value;
if (ddlValueType === "int") {
value(parseInt(val));
}
else if (ddlValueType == "float") {
value(parseFloat(val));
} else {
value(val);
}
}
};
// Retrieve the attr: {} binding
var attribs = allBindingsAccessor().attr;
// Check if we specified the attr binding
if (attribs != null && attribs != undefined) {
// Check if we specified the attr ID binding
if (attribs.hasOwnProperty('id')) {
var id = attribs.id;
$(element).attr('id', id);
}
if (bindingContext.hasOwnProperty('$index')) {
var idx = bindingContext.$index();
$(element).attr('name', 'ddl' + idx);
}
}
if ($(element).attr('id') == undefined || $(element).attr('id') == '') {
var id = "ko_ddl_id_" + (ko.bindingHandlers['dropdownlist'].currentIndex);
$(element).attr('id', id);
}
if ($(element).attr('name') == undefined || $(element).attr('name') == '') {
var name = "ko_ddl_name_" + (ko.bindingHandlers['dropdownlist'].currentIndex);
$(element).attr('name', name);
}
var options = $('option', element);
$.each(options, function (index) {
if ($(this).val() == unwrappedValue) {
$(this).attr('selected', 'selected');
}
});
if (!$(element).hasClass('INIMultiSelect')) {
$(element).addClass('INIMultiSelect');
}
$(element).iniMultiSelect(elementOptions);
ko.bindingHandlers['dropdownlist'].currentIndex++;
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var unwrappedValue = ko.utils.unwrapObservable(valueAccessor());
var id = $(element).attr('id').replace(/\[/gm, '\\[').replace(/\]/gm, '\\]');
var iniMultiSelect = $('#' + id);
if (iniMultiSelect != null) {
iniMultiSelect.SetValue(unwrappedValue, true);
}
}};
ko.bindingHandlers.dropdownlist.currentIndex = 0;
This will transform the original HTML select element into my custom multiselect.
However, when the update function is called the first time, after the init, the "element" variable will still be the original select element, and not my wrapper div that holds my custom html together.
And after the page has been completely loaded and I change the value of the observable that I am binding to, the update function is not triggered at all!
Somehow I have a feeling that knockout no longer "knows" what to do because the original DOM element that I'm binding to is gone...
Any ideas what might be the issue here?
There is clean up code in Knockout that will dispose of the computed observables that are used to trigger bindings when it determines that the element is no longer part of the document.
You could potentially find a way to just hide the original element, or place the binding on a container of the original select (probably would be a good option), or reapply a binding to one of the new elements.
I ran into a similar problem today, and here's how I solved it. In my update handler, I added the following line:
$(element).attr("dummy-attribute", ko.unwrap(valueAccessor()));
This suffices to prevent the handler from being disposed-of by Knockout's garbage collector.
JSFiddle (broken): http://jsfiddle.net/padfv0u9/
JSFiddle (fixed): http://jsfiddle.net/padfv0u9/2/
is there an example of using jqgrid's getChangedCells
method to determine if data has changed?
I grepped getChangedCells in the downloadable demos for
jqgrid, and could only find the function definition, not
example usages of getChangedCells.
What I want to do is save the edits that a user's
made if the user clicks on another row. But, I only
want to submit the save if the row is dirty.
Thanks in advance,
--Nate
There are no safe dirty flag on the row. You can use the fact that at the beginning of row editing (at the start of the inline editing mode) the method editRow add editable="1" attribute to the grid row (<tr> element). Later the methods saveRow and restoreRow changes the attribute value to editable="0". So the rows of the current page which was at least once in the inline editing mode will have the editable attribute. If the id of the table element is "list" you can find the edited rows with
$("#list tr[editable]")
The ids of the elements of the set are the rowids of the rows.
If you use paging in the grid you should be careful and save the ids of the edited rows on the current page before the changing of the page. The onPaging event would help you here.
In my opinion the best and the most safe way to do what you need is to use aftersavefunc parameter of the editRow or saveRow methods (probably you use directly only editRow). Inside of your aftersavefunc function you can save the id of the modified row in an array/map. This will solve your problem and will safe work.
Finally, I managed to bring a piece of code to detect what we want ;)
Hopefully any jqgrid gurus there (like Oleg), have enough time to review this code and improve it.
The example code will work for detect data changed in a grid with an editable field named "name". If you want to check for changed data in more columns, you have to add the variables after_edit and before_edit asociated with that columns.
To get the previous cell data inside the onSelectRow function, I don't used the getCell method because in the documentation says in red:
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
By disgrace I could check that the documentation was right :(.
However the getCell function works properly with the current cell data.
And here is the code:
// Declare variables used for inline edit functionality.
var last_selected;
var before_edit_value;
var after_edit_value;
$('#grid-id').jqGrid({
...
onSelectRow: function(row_id){
if(row_id && row_id !== last_selected) {
/*
* Determine if the value was changed, if not there is no need to save to server.
*/
if (typeof(last_selected) != 'undefined') {
after_edit_value = $('#grid-id tr#' + last_selected + ' .name_column input').val();
}
if (before_edit_value != after_edit_value) {
/*
* Save row.
*/
$('#grid-id').jqGrid(
'saveRow',
last_selected,
function(response){
/* SuccessFunction: Do something with the server response */
return true;
},
'http://url.to.server-side.script.com/server-side-script.php',
{
additional_data: 'example: additional string',
});
}
else {
/*
* Restore the row.
*/
$('#grid-id').jqGrid('restoreRow', last_selected);
}
before_edit_value = $('#grid-id').jqGrid('getCell', row_id, 'name');
}
last_selected = row_id;
/*
* Edit row.
*/
$('#grid-id').jqGrid(
'editRow',
row_id,
true,
function() {/* OnEditFunction */},
function(response) {
/* SuccessFunction: Do something with the server response */
return true;
},
'http://url.to.server-side.script.com/server-side-script.php',
{
additional_data: 'example: additional string',
});
},
...
});
In one of my projects I did the following: before editing the row I remember row data in global variable and after editing is done just check if row data was changed. Something like this (edit mode activated by double click):
var beforeEditData;
function onGridDblClickRow(id) {
if (isRowEditable(id)) {
beforeEditData = grid.getRowData(id);
grid.editRow(id, true, null, null, 'clientArray', null, onRowAfterEdit);
...
}
}
function onRowAfterEdit(row) {
var data = grid.getRowData(row);
if (!isDataChanged(beforeEditData, data)) {
return; // No changes
}
... // Save data here
}
function isDataChanged(before, after){
... // Allows tricky logic for dirty data, e.g. one may trim spaces etc.
}
Using MVC4 and JQuery this is what I did
In the View
<script type="text/javascript">
var $grid = $("#Grid");
var lastSelection;
var datachanged = false;
function gridInitialised() {
var headers = $('th>div>:input');
for (var h = 0; h < headers.length; headers[h++].onclick = (function () { if (datachanged) { $grid.saveRow(lastSelection); datachanged = false; } }));
}
function editRow(id) {
if (id && id !== lastSelection) {
if (datachanged) { $grid.saveRow(lastSelection); datachanged = false; }
$grid.restoreRow(lastSelection);
$grid.editRow(id, true);
var inputs = $('#'+id+'>td>:input[class="editable"]');
for (var i = 0; i < inputs.length; inputs[i++].onchange = (function () { datachanged = true; }));
lastSelection = id;
}
}
</script>
#Html.Trirand().JQGrid(Model.Grid, "Grid")
in the Model
Grid.ClientSideEvents.RowSelect = "editRow";
Grid.ClientSideEvents.GridInitialized = "gridInitialised";
The gridInitialised code is to handle changes to the search filter.
Dave
As Oleg mentioned 5 (wow) years ago - I used the saveRow function and passed the flag as extraparam.
something like this, assuming your "model" or a hidden column IsDirty in my case:
onSelectRow: function(id) {
if (id && id !== lastgridsel) {
$("#myGrid").saveRow(lastgridsel, false, "clientArray", { IsDirty: "True" });
$("#myGrid").editRow(id, true, null, null, "clientArray");
lastgridsel = id;
}
},
and then loop through the rows on Save click (external button in my case), something along the lines of:
$("#gridSaveBtn").on("click", function() {
var batch = new Array();
var dataIds = $("#myGrid").jqGrid("getDataIDs");
for (var i = 0; i < dataIds.length; i++) {
try {
$("#myGrid").jqGrid("saveRow", dataIds[i], false, "clientArray");
//get row data
var data = $("#myGrid").jqGrid("getRowData", dataIds[i]);
if (data["IsDirty"] === "True") {
batch.push(data);
}
} catch (ex) {
alert(ex.Message);
$("#myGrid").jqGrid("restoreRow", dataIds[i]);
}
}
});
How to get a jqGrid cell value when in-line editing (getcell and getRowData returns the cell content and not the actuall value of the input element).
General function to get value of cell with given row id and cell id
Create in your js code function:
function getCellValue(rowId, cellId) {
var cell = jQuery('#' + rowId + '_' + cellId);
var val = cell.val();
return val;
}
Example of use:
var clientId = getCellValue(15, 'clientId');
Dodgy, but works.
Here is an example of basic solution with a user function.
ondblClickRow: function(rowid) {
var cont = $('#grid').getCell(rowid, 'MyCol');
var val = getCellValue(cont);
}
...
function getCellValue(content) {
var k1 = content.indexOf(' value=', 0);
var k2 = content.indexOf(' name=', k1);
var val = '';
if (k1 > 0) {
val = content.substr(k1 + 7, k2 - k1 - 6);
}
return val;
}
After many hours grief I found this to be the simplest solution. Call this before fetching the row data:
$('#yourgrid').jqGrid("editCell", 0, 0, false);
It will save any current edit and will not throw if there are no rows in the grid.
As you stated, according to the jqGrid documentation for getCell and getRowData:
Do not use this method when you editing the row or cell. This will return the cell content and not the actual value of the input element
Since neither of these methods will return your data directly, you would have to use them to return the cell content itself and then parse it, perhaps using jQuery. It would be nice if a future version of jqGrid could provide a means to do some of this parsing itself, and/or provide an API to make it more straightforward. But on the other hand is this really a use case that comes up that often?
Alternatively, if you can explain your original problem in more detail there may be other options.
Try this, it will give you particular column's value
onSelectRow: function(id) {
var rowData = jQuery(this).getRowData(id);
var temp= rowData['name'];//replace name with you column
alert(temp);
}
Basically, you have to save the row before you access the cell contents.
If you do, then you get the value for the cell instead of the markup that comes when the cell is in edit mode.
jQuery.each(selectedRows, function(index, foodId) {
// save the row on the grid in 'client array', I.E. without a server post
$("#favoritesTable").saveRow(foodId, false, 'clientArray');
// longhand, get grid row based on the id
var gridRow = $("#favoritesTable").getRowData(foodId);
// reference the value from the editable cell
foodData += foodId + ":" + gridRow['ServingsConsumed'] + ',';
});
Hi, I met this problem too. Finally I solved this problem by jQuery. But the answer is related to the grid itself, not a common one. Hope it helps.
My solution like this:
var userIDContent = $("#grid").getCell(id,"userID"); // Use getCell to get the content
//alert("userID:" +userID); // you can see the content here.
//Use jQuery to create this element and then get the required value.
var userID = $(userIDContent).val(); // var userID = $(userIDContent).attr('attrName');
you can use this directly....
onCellSelect: function(rowid,iCol,cellcontent,e) {
alert(cellcontent);
}
This is my solution:
function getDataLine(grida, rowid){ //vykradeno z inineeditu a vohackovano
if(grida.lastIndexOf("#", 0) === 0){
grida = $(grida);
}else{
grida = $("#"+grida);
}
var nm, tmp={}, tmp2={}, tmp3= {}, editable, fr, cv, ind;
ind = grida.jqGrid("getInd",rowid,true);
if(ind === false) {return success;}
editable = $(ind).attr("editable");
if (editable==="1") {
var cm;
var colModel = grida.jqGrid("getGridParam","colModel") ;
$("td",ind).each(function(i) {
// cm = $('#mygrid').p.colModel[i];
cm = colModel[i];
nm = cm.name;
if ( nm != 'cb' && nm != 'subgrid' && cm.editable===true && nm != 'rn' && !$(this).hasClass('not-editable-cell')) {
switch (cm.edittype) {
case "checkbox":
var cbv = ["Yes","No"];
if(cm.editoptions ) {
cbv = cm.editoptions.value.split(":");
}
tmp[nm]= $("input",this).is(":checked") ? cbv[0] : cbv[1];
break;
case 'text':
case 'password':
case 'textarea':
case "button" :
tmp[nm]=$("input, textarea",this).val();
break;
case 'select':
if(!cm.editoptions.multiple) {
tmp[nm] = $("select option:selected",this).val();
tmp2[nm] = $("select option:selected", this).text();
} else {
var sel = $("select",this), selectedText = [];
tmp[nm] = $(sel).val();
if(tmp[nm]) { tmp[nm]= tmp[nm].join(","); } else { tmp[nm] =""; }
$("select option:selected",this).each(
function(i,selected){
selectedText[i] = $(selected).text();
}
);
tmp2[nm] = selectedText.join(",");
}
if(cm.formatter && cm.formatter == 'select') { tmp2={}; }
break;
}
}
});
}
return tmp;
}
I have a solution:
1. Using this.value to get the current editing value in the editing row.
2. Save the cell value to a hidden field when the cell lost its focus.
3. Read the hidden field when you need.
The code:
colModel="[
{ name: 'Net', index: 'Net', editable:true, editoptions: { dataEvents: [ { type: 'focusout', fn: function(e) {$('#HiddenNet').val(this.value);} }] }, editrules:{custom:true,}},
{ name: 'Tax', index: 'Tax', editable:true, editoptions: { dataEvents: [ { type: 'focus', fn: function(e) {this.value=$('#HiddenNet').val(); } }] }, editrules:{custom:true}}
]"
Good Luck
You can get it from the following way...!!
var rowId =$("#list").jqGrid('getGridParam','selrow');
var rowData = jQuery("#list").getRowData(rowId);
var colData = rowData['UserId']; // perticuler Column name of jqgrid that you want to access
In my case the contents of my cell is HTML as result of a formatter. I want the value inside anchor tag. By fetching the cell contents and then creating an element out of the html via jQuery I am able to then access the raw value by calling .text() on my newly created element.
var cellContents = grid.getCell(rowid, 'ColNameHere');
console.log($(cellContents));
//in my case logs <h3>The Value I'm After</h3>
var cellRawValue = $(cellContents).text();
console.log(cellRawValue); //outputs "The Value I'm After!"
my answer is based on #LLQ answer, but since in my case my cellContents isn't an input I needed to use .text() instead of .val() to access the raw value so I thought I'd post this in case anyone else is looking for a way to access the raw value of a formatted jqGrid cell.
its very simple write code in you grid.php and pass the value to an other page.php
in this way you can get other column cell vaue
but any one can make a like window.open(path to pass value....) in fancy box or clor box?
$custom = <<<CUSTOM
jQuery("#getselected").click(function(){
var selr = jQuery('#grid').jqGrid('getGridParam','selrow');
var kelr = jQuery('#grid').jqGrid('getCell', selr, 'stu_regno');
var belr = jQuery('#grid').jqGrid('getCell', selr, 'stu_school');
if(selr)
window.open('editcustomer.php?id='+(selr), '_Self');
else alert("No selected row");
return false;
});
CUSTOM;
$grid->setJSCode($custom);
I think an extension of this would get it for you.
retrieving-original-row-data-from-jqgrid
I think a better solution than using getCell which as you know returns some html when in edit mode is to use jquery to access the fields directly. The problem with trying to parse like you are doing is that it will only work for input fields (not things like select), and it won't work if you have done some customizations to the input fields. The following will work with inputs and select elements and is only one line of code.
ondblClickRow: function(rowid) {
var val = $('#' + rowid + '_MyCol').val();
}
I've got a rather indirect way. Your data should have an unique id.
First, setting a formatter
$.extend(true, $.fn.fmatter, {
numdata: function(cellvalue, options, rowdata){
return '<span class="numData" data-num="'+rowdata.num+'">'+rowdata.num+'</span>';
}
});
Use this formatter in ColModel. To retrieve ID (e.g. selected row)
var grid = $("#grid"),
rowId = grid.getGridPara('selrow'),
num = grid.find("#"+rowId+" span.numData").attr("data-num");
(or you can directly use .data() for latest jquery 1.4.4)
In order to get the cell value when in-line editing you need to capture this event(or another similar event, check documentation):
beforeSaveCell: function (rowid, celname, value, iRow, iCol) { }
In the value parameter you have the 'value' of the cell that was currently edited.
To get the the rest of the values in the row use getRowData()
I lost a lot of time with this, hope this helps.
My workaround is to attach an object containing orignal values to each tr element in the grid. I've used afterAddRecord callback to get my hands on the values before jqGrid throws them away and jQuery's "data" method to store them in the work.
Example:
afterInsertRow: function( rowid, rowdata, rowelem ) {
var tr = $("#"+rowid);
$(tr).data("jqgrid.record_data", rowelem);
},
“rowelem” is the array of cell values from our JSON data feed or [jsonReader] (http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#jsonreader_as_function)
Then at any point I can fetch those attributes using:
$(tr).data(“jqgrid.record_data”).
More at: http://wojciech.oxos.pl/post/9423083837/fetching-original-record-values-in-jqgrid
I think that Aidan's answer is by far the best.
$('#yourgrid').jqGrid("editCell", 0, 0, false);
This commits any current edits, giving you access to the real value. I prefer it because:
You don't have to hard-code any cell references in.
It is particularly well suited to using getRowData() to get the entire grid, as it doesn't care which cell you've just been editing.
You're not trying to parse some markup generated by jqGrid which may change in future.
If the user is saving, then ending the edit session is likely the behaviour they would want anyway.
Before i was getting :
html tag of the textbox something like
but Here is the solution to get the value from that particular column, working and tested
function getValue(rowId, cellId) {
var val = $("[rowId='"+rowId+"'][name='"+cellId+"']").val();
return val;
}
var values = getValue(rowId, 'cellid');
I obtain edit value using javascript:
document.getElementById('idCell').value
I hope this info useful for someone.
I needed the original value before the formatter, so this is what I did:
{
name: 'Slot', title: false, formatter: function (cellValue, options, rowObject) {
rowObject['SlotID'] = cellValue; // <--- This saves the original ID
if (somelogic) {
return someString;
} else {
return someOtherString;
}
}
},
{ name: 'SlotID', hidden: true }
Now SlotID contains the original ID. Also, you don't need to have SlotID property on your original model.
try subscribing to afterEditCell event it will receive (rowid, cellname, value, iRow, iCol) where value is your a new value of your cell
You can use getCol to get the column values as an array then index into it by the row you are interested in.
var col = $('#grid').jqGrid('getCol', 'Sales', false);
var val = col[row];