jqGrid method setGridParam on event subGridRowExpanded causes error - jqgrid

I successfully configured a subgrid including the subGridRowExpanded callback in my grid.
This means the callback and config values are valid.
I want to remove the subgrid configuration now in order to add it programmatically.
First step - set subgrid to true:
jQuery('#s3list').jqGrid('setGridParam', {
subGrid: true
});
This causes the following error:
TypeError: this.p.subGridOptions is undefined.
Second step - adding required subGridOptions:
jQuery('#s3list').jqGrid('setGridParam', {subGridOptions: {
reloadOnExpand: false
}});
This causes the following error:
TypeError: b.p.colModel[(((n + x) + C) + H)] is undefined
Adding my valid callback for subGridRowExpanded has no effect - the error stays the same:
jQuery('#s3list').jqGrid('setGridParam', {
subGridRowExpanded: function(subgrid_id, row_id) {
/* lots of valid code */
}
});
Is it possible at all?
Using jqGrid 4.5.2.
Related issues / questions:
https://github.com/tonytomov/jqGrid/issues/478
jqGrid dynamic event
How to programatically add an event handler on a JQGrid?
How to reload JQuery grid keeping scroll position and collapse elements open
Add an event handler to jqGrid after instantiation

I suppose that there are misunderstanding what subGrid: true option do. jqGrid add column with the namse subgrid if you create grid with the option. Because you can't add new column dynamically in jqGrid you can't switch on subGrid option in the grid without recreating of it with respect of GridUnload method (see the answer).
The method setGridParam is stupid. It just use $.extend to extend the internal option of jqGrid (see the source code). Usage of the method without taking in consideration the specific of the option can break functionality of the grid.
There are some scenarios when one can create grid with subgrid and hide the column with (see the answer and this one). You should consider in details whether such approach is acceptable for your requirements.

Related

Pass RowData to Custom_func in Jqgrid

I have a jqgrid with certain columns. I am trying to call a custom_function to validate the cell value.
I am also getting a regular expression from the database into rowData, which I want to use to validate the cell value.
var ret = jQuery("#settingsListGrid").jqGrid('getRowData', id);
cm.editrules = {
required: true,
custom: true,
custom_func: ValidateData,
custom_value:ret.RegX
};
So I need to pass rowData to a custom function.
ValidateData = function (value, colname, customValue) {
return customValue.test(value) ?
[true] :
[false, "Invalid Data"];
}
I want to pass the rowData using customValue
Please help?
The answer depend on the fork of jqGrid, which you use. I understand the problem which you wrote, but one have to change the code of jqGrid (the implementation of custom validation) to implement the requirement.
I develop free jqGrid fork of jqGrid after Tony Tomov changed the license agreement of jqGrid, renamed his product in version 4.7.1 to Guriddo jqGrid JS (see the post) and made it commercial (see the prices here). After starting the development based on the last free 4.7 version I made a lot of changes and improvements in the code and have implemented many new features. The feature which you need is implemented starting with version 4.12.1 (see here). Thus you can easy solve your problem after updating to the current free jqGrid 4.13.2.
The new feature works as following:
editrules: {
required: true,
custom: ValidateData,
custom_value: ret.RegX
}
It's important that one should specify the custom validation function as the value of custom property instead of usage custom_func. It allows free jqGrid to hold compatibility to old versions (via custom: true and custom_func), but providing new parameters of the validation callback via function as the value of custom property.
The new style ValidateData will look like
var ValidateData = function (options) {
return customValue.test(options.newValue) ?
[true] :
[false, "Invalid Data"];
}
with only one options parameter, which have many properties which you could use. Such style allows to provide many helpful information without the requirement to have a lot of unneeded parameters. Moreover the style of callback options allows to extend the options object in the future versions without breaking compatibility to previous versions.
The options parameter have the following properties
newValue - the current (modified) value which need be validated
oldValue - the previous value (the old value) of the cell before the modification
cmName - the column name. It could be practical if you use one callback function in many columns and you want to implement a little different behavior for different columns. It could be additionally helpful for producing readable error message in case of validation error.
iCol - the index in the current colModel which corresponds the column (the column cmName)
cm - the element of colModel, which represent the currently validating column.
rowid - the rowid of the current editing row. One can use getLocalRow for example to get the content of other columns before editing. It's important to remark that getLocalRow works only in case of usage datatype: "local" or loadonce: true. The method getRowData or getCell can be safe used to get data in form editing mode or to access the data, which are not currently editing (in cell or inline editing mode).
iRow - numeric index of the current editing row from the top of the grid (from the top of HTML <table>)
oldRowData - will be set only in case of usage inline editing or cell editing. It's not defined in form editing mode. It represent the values
mode - shows which editing mode is used now. It can be "addForm", "editForm" (in case of usage form editing), "cell" (cell editing), "add" or "edit" (inline editing). In some other callback function the property could have two other values: "filter" (field from the filter toolbar) or "search" (for validation of the field of the searching dialog)
tr and td - the DOM elements of the row and cell of the grid which will be edited using form editing mode. The properties will be set only in case of form editing.
I hope that the large set of properties of options parameter allows you easy implement your requirements on any custom validation.

customize jqGrid edit button inside row to open new view

So the default behavior for the edit button inside each row of jqGrid is to open the form in the same page, right?
I need it to open another view, another URL.
I've managed to do this with the edit button that is located in the grid-pager, using the .navButtonAdd method. But I can't figure out how to do the same for the row buttons.
Can anyone help me, please?
jqGrid don't provide currently any simple way to replace the call of editing to another method or to include custom button. What you can do alternatively is "subclassing" $.fn.fmatter.rowactions function like I describe it in the answer. The $.fn.fmatter.rowactions function will be called on click on any from action buttons. So you can test whether the act parameter is "edit" or not. In case of non "edit" button you can forward the call to original $.fn.fmatter.rowactions function. In case of "edit" button you can do any your custom action instead.
UPDATED: The exact implementation depends a little from the version of jqGrid which you use because parameters and the value of this of the function $.fn.fmatter.rowactions are different for different versions of jqGrid. I created for you the demo which uses free jqGrid 4.8 (see readme and wiki). I used the following code for subclassing
var orgRowActions = $.fn.fmatter.rowactions;
$.fn.fmatter.rowactions = function (e, act) {
var $grid = $(this).closest("table.ui-jqgrid-btable"),
rowid = $(this).closest("tr.jqgrow").attr("id");
if (act === "edit") {
$grid.jqGrid("viewGridRow", rowid);
return false;
}
return orgRowActions.call(this, e, act);
}
As the result the "Edit" button starts "View" instead of edit form.
I plan to include more customization possibilities in the next version of free jqGrid. So one will be able to create custom inline icon without the tricks with subclassing.

Redirect to jqGrid edit form directly without displaying the grid

Often I need to edit a single record in a database without the need to display the grid at all. I can hide the grid using CSS or jQuery. What I couldn't figure out is to directly go to the edit form from another webpage while hiding the grid.
I know it's kind of defeating the purpose of having a grid, but it's one of those cases where only a single record should be view and modified by the users similar to the Access single record mode. Is it even possible?
In general you can just hide so named "gbox" created over the grid and then call editGridRow method with the options which you like to have. As the result you will have the form which close to what you want. I am sure that you have to make some other small problems, but the first look can be like you want. Moreover you can scroll over the rows during editing.
The demo demonstrate what I mean. It displays the following form
The demo uses the following code
$("#list").jqGrid({
...
loadComplete: function (data) {
$(this).jqGrid("editGridRow", data.rows[0].id, {
modal: true,
overlay: 0, // create no overlay
onClose: function () {
return false; // don't allow to close the form
}
});
}
}).closest(".ui-jqgrid").hide();
This is one of the reasons I like to use my own custom edit forms, instead of the one built into jqGrid. Then you can just open it like you would from the jqGrid handler (with appropriate parameters of course), no grid required.

How can I hide rows in jqGrid treegrid, triggered after the expandNode event?

I have a basic treegrid with 2 levels, and I want some rows hidden and others visible; I do this with $("#" + rowId).hide() and $("#" + rowId).show() programatically, as which rows are visible is dependent on data outside the grid. That part works fine.
However, when I collapse a node and then expand it, all children are visible, even those I hid. Evidently, jqGrid is pretty much just doing .hide() and .show() on the rows, which negates my settings. So my thought is to add a hidden field in each row that stores whether it should be visible or not, and then re-hide/show after the expand event. The problem is, I'm not sure how to catch the event and execute code immediately after it.
Oleg shows a method for catching the events here: jqGrid treeGrid catch expand collaps events
Unfortunately, that doesn't work for me because it will just override whatever hide/show I do there. I need to execute code after the jqGrid functions. Any ideas on how to do this?
The solution seems very easy for me. One need just make small modification from the code from the answer which you reference. You can do something like the following
var orgExpandNode = $.fn.jqGrid.expandNode;
$.jgrid.extend({
expandNode: function (rc) {
// here you can insert the code which will be executed
// before the original expandNode
var res = orgExpandNode.call(this, rc);
// now you can execute some code after the original expandNode
// for example the next line hide the node in the grid
$("#1_1_1").hide(); // hide some row of the grid
return res; // return the value from expandNode
}
});
see the demo. The demo has one node in the TreeGrid which has id="1_1_1", but it stay hidden all the time.
UPDATED: Free jqGrid have beforeExpandRow, afterExpandRow, beforeExpandNode and afterExpandNode callbacks and "jqGridTreeGridBeforeExpandRow", "jqGridTreeGridAfterExpandRow", "jqGridTreeGridBeforeExpandNode", "jqGridTreeGridAfterExpandNode" events. Thus subclassing of TreeGrid methods described above is not required in case of usage free jqGrid.

Referencing a subgrid in onSelectRow?

I have a multiselect jqGrid with a multiselect grid-as-subgrid. In the onSelectRow event for the parent grid, how can I grab a reference to the child grid?
Essentially, I need to do the following:
Expand the subgrid (so as to load its data from the server)
Get a reference to that subgrid
With the reference, loop through the rows and set each one to selected (For rows which have a nested subgrid of their own, this will trigger their onSelectRow and repeat the process. Don't worry, the grid is no more than 3 nestings deep.)
I'm looking through the various documentation this morning, but so far haven't spotted what I need to make this happen. Maybe I'm just missing the obvious? Or maybe this would require a bit more cleverness?
I see how Step 3 above can be accomplished starting with getRowData() and looping through the results with setSelection(). I use those elsewhere in code and they work great. But Steps 1 and 2 above are where I'm stuck at the moment.
Edit: Following #Oleg's answer below, I looked a bit more into synchronizing efforts between a parent grid's onSelectRow event and subGridRowExpanded event. Here's a boiled down version of what I'm testing right now:
onSelectRow: function(id, status) {
// Automatically expand the sub-grid (to load the data) and select the rows in that grid
autoSelecting = true; // autoSelecting is a global variable normally set to false
$('#mainGrid').expandSubGridRow(id);
}
subGridRowExpanded: function(subgrid_id, row_id) {
//... build the sub-grid, works fine (an artifact of which is a subgrid_table_id)
// If this grid was auto-expanded to be auto-selected, select all its rows
if (autoSelecting) {
var sdata = $('#' + subgrid_table_id).getRowData();
for (var i = 0; i < sdata.length; i++) {
$('#' + subgrid_table_id).setSelection(sdata[i].Id);
}
autoSelecting = false;
}
}
A few things are happening here as I tinker with this:
If I'm stepping through FireBug to debug this, selections and sub-selections work correctly. However, if I take out breakpoints and try it in real-time, sub-selections don't happen. The sub-grid expands, but its rows don't get selected. I figure there's a timing issue in there somewhere.
I haven't accounted for cascading de-selects yet, clearly.
If the sub-grid is already expanded, the selecting doesn't cascade.
Inside of loadComplete event handler the grid is loaded and you can do some additional actions like expanding of some rows.
You can expand the subgrid with respect of expandSubGridRow method.
To get the reference to the subgrid the subgrid should be created first. So the best place to reference of the grid is subGridRowExpanded event. You don't posted the JavaScript code which you use, so it is difficult to describe all more exactly.
To select all rows you can use setSelection in the loop or use code like $('.cbox', myGrid[0]).trigger('click'); There are different other variation how to do the same. If you will see that you have performance bottleneck here then I could describe how you can do the step more effective.
I can repeat, that the most important that you expand or select the rows after the grid data (or the subgrid data) is loaded.

Resources