How to show subgrid in jqgrid in ASP.NET MVC 5? - model-view-controller

My jqgrid is working perfectly but now i am implementing the subgrid. It shows the + sign and when i click on it the blank row displayed with loading.... this is the client side code
$(document).ready(function () {
$("#Grid").jqGrid({
url: '/Home/GetDetails',
datatype: 'json',
myType: 'GET',
colNames: ['id','Name', 'Designation', 'Address', 'Salary'],
colModel: [
{ key: false, name: 'Id', index: 'Id', },
{ key: false, name: 'Name', index: 'Name', editable: true },
{ key: false, name: 'Designation', index: 'Designation', editable: true },
{ key: false, name: 'Address', index: 'Address', editable: true },
{ key: false, name: 'Salary', index: 'Salary', editable: true }
],
jsonReader: {
root: 'rows',
page: 'page',
total: 'total',
records: 'records',
id: '0',
repeatitems: true
},
pager: $('#pager'),
rowNum: 10,
rowList: [10, 20, 30],
width: 600,
viewrecords: true,
multiselect: true,
sortname: 'Id',
sortorder: "desc",
caption: 'Employee Records',
loadonce: true,
gridview: true,
autoencode: true,
subGrid: true,
subGridUrl: '/Home/Subgrid',
subGridModel: [{
name: ['No', 'Item','Quantity'],
width: [55, 55,55]
}
],
}).navGrid('#pager', { edit: true, add: true, del: true },
{
zIndex: 100,
url: '/Home/Edit',
closeOnEscape: true,
closeAfterEdit: true,
recreateForm: true,
afterComplete: function (response) {
if (response.responseText)
{
alert(response.responseText);
}
}
},
{
zIndex: 10,
url: '/Home/Add',
closeOnEscape: true,
closeAfterEdit: true,
recreateForm: true,
afterComplete: function (response) {
if (response.responseText) {
alert(response.responseText);
}
}
},
{
zIndex: 100,
url: '/Home/Delete',
closeOnEscape: true,
closeAfterEdit: true,
recreateForm: true,
afterComplete: function (response) {
if (response.responseText) {
alert(response.responseText);
}
}
}
);
});
Subgrid url action method is as below:
public JsonResult Subgrid(String id)
{
Database1Entities db = new Database1Entities();
Product p= new Product {No=1,Item="Juice",Quantity=23};
var jsondata = new { rows=2,
cell = new string[] { p.No.ToString(),
p.Item,p.Quantity.ToString()}.ToArray()
};
return Json(jsondata, JsonRequestBehavior.AllowGet);
}
I am doing this first time. What is the mistake?Thanks in advance

I don't recommend you to use subGridModel. Instead of that it's much more flexible to use Subgrid as Grid. If the user clicks "+" icon (expand subgrid) then jqGrid just inserts empty row under selected with simple structure described in the answer for example. The id of the <div> where some custom "subgrid" information need be displayed will be the first parameter of subGridRowExpanded callback which you need to implement. The second parameter is the rowid of the expending row. By implementing the corresponding callback you can create any custom "subgrid". See the old answer for very simple demo.
So what you need to do is just write the code which creates grid which will be placed in subgrid row. It's only strictly recommended to use idPrefix parameter which used any values which depends from subgriddivid or parent rowid. Additionally you can consider to use autowidth: true option for subgrid, which will make the width of subgrid be exact correspond to the width of the main grid. Of cause to have rowid of the parent row send as id parameter to '/Home/Subgrid' you need use postData: { id: rowid }. See the code from the answer for example which I referenced previously.

Related

JqGrid: Autocomplete in form fields

I am using free version (latest) of jqgrid with MVC c#.
I have form fields setup. When the user clicks add in the footer button (add) it shows a modal popup with all the form fields.
I want my first textbox in the form field to autocomplete, ie when they start typing their empployee number in the textbox, I should query my mvc controller and fetch the data and then prefill if there is a match. Once that prefills I also want to update 2 more label on the form, firstname & lastname. Also the button should be disabled until the correct id is fetched in the employee textbox.
Not sure how should I go about this. I can share my sample grid that I have used.
Thanks
<script type="text/javascript">
$(function () {
"use strict";
var $grid = $("#list");
$grid.jqGrid({
url: '#Url.Action("GetData", "Home")',
datatype: "json",
mtype: 'Get',
colNames: ['Id', 'Name', 'Sex', 'Address'],
loadonce: true,
height: '100%',
autowidth: true,
colModel: [
{ name: 'empid', index: 'empid', editable: true, editrules: { required: true}},
{ name: 'fname', index: 'fname', editable: true, editrules: { required: true}}, //currently these are texbox, but I want this to be label which gets filled based on the empid
{ name: 'lname', index: 'lname', editable: true, editrules: { required: true}},
{ name: 'address', index: 'address', editable: true, editrules: { required: true}}
],
cmTemplate: { autoResizable: true, editable: true },
autoResizing: { compact: true, resetWidthOrg: true },
iconSet: "fontAwesome",
rowNum: 10,
rowList: [5, 10, 20, "10000:All"],
viewrecords: true,
autoencode: true,
sortable: true,
pager: true,
rownumbers: true,
sortname: "uid",
sortorder: "desc",
pagerRightWidth: 150,
inlineEditing: {
keys: true
},
formEditing: {
reloadGridOptions: { fromServer: true },
reloadAfterSubmit: true,
width: 310,
closeOnEscape: true,
closeAfterEdit: true,
closeAfterAdd: true,
closeAfterDelete: true,
savekey: [true, 13]
}
caption: "MyData"
}).jqGrid("navGrid")
.editGridRow("new", properties);
});
Updated:
If there is also option to use onkeyup, mouseover etc on the textbox so that I can validate whats entered in the textbox and then also update other textbox based on this value
I have done this by using keyup event instead of using autocomplete.
Relevant code as below:
colModel: [
{
name: 'empid', index: 'empid', editable: true, , editrules: { required: true },
editoptions:
{
dataEvents: [
{
type: 'keyup',
fn: function (e) {
$.ajax({
url: //call to my method in my mvc controller,
data: "empid=" + $(this).val(),
type: "GET",
success: function (data) {
//validate and populate other fields here
}
else {
}
},
error: function (passParams) {
// code here
}
});
}
}
]
}
]

jqgrid v5.2.1 with subgrid and local data CRUD operations

Here is my scenario. My jqgrid v5.2.1 doesn't display any data when a page loads up. It is by design. Users will either have to enter all the data for the grid and subgrid manually or click a button to load a default data from the server in the json format via
$("#jqGrid").jqGrid('setGridParam', { datatype: 'local', data: dataResponse.groups }).trigger("reloadGrid");
Users perform CRUD operations locally until the data is right in which case a button is clicked and the grids data goes to the server via $("#jqGrid").jqGrid('getGridParam', 'data').
Edit/Delete operations work fine with the default data loaded but I have a problem with adding new records.
Id's of new rows are always _empty(which is fine because the server side will generated it), but the new rows from the subgrids are not transferred to the server. The question is how to establish the relationship between the newly created rows in the main grid and associated rows in the subgrid and then transfer everything to the server for processing?
Here is the code:
var mainGridPrefix = "s_";
$("#jqGrid").jqGrid({
styleUI: 'Bootstrap',
datatype: 'local',
editurl: 'clientArray',
postData: {},
colNames: ['Id', 'Group', 'Group Description', 'Markets', 'Group sort order'],
colModel: [
{ name: 'id', key: true, hidden: true },
{ name: 'name', width: 300, sortable: false, editable: true, editrules: { required: true }, editoptions: { maxlength: 50 } },
{ name: 'description', width: 700, sortable: false, editable: true, editoptions: { maxlength: 256 } },
{ name: 'market', width: 200, sortable: false, editable: true, editrules: { required: true }, editoptions: { maxlength: 50 } },
{ name: 'sortOrder', width: 130, sortable: false, editable: true, formatter: 'number', formatoptions: { decimalSeparator: ".", thousandsSeparator: ',', decimalPlaces: 2 } }
],
sortname: 'Id',
sortorder: 'asc',
idPrefix: mainGridPrefix,
subGrid: true,
//localReader: { repeatitems: true },
jsonReader: { repeatitems: false},
autowidth: true,
shrinkToFit: true,
loadonce: true,
viewrecords: true,
rowNum: 5000,
pgbuttons: false,
pginput: false,
pager: "#jqGridPager",
caption: "Group Template",
altRows: true,
altclass: 'myAltRowClass',
beforeProcessing: function (data) {
var rows = data.rows, l = rows.length, i, item, subgrids = {};
for (i = 0; i < l; i++) {
item = rows[i];
if (item.groupItems) {
subgrids[item.id] = item.groupItems;
}
}
data.userdata = subgrids;
},
subGridRowExpanded: function (subgridDivId, rowId) {
var $subgrid = $("<table id='" + subgridDivId + "_t'></table>"),
pureRowId = $.jgrid.stripPref(mainGridPrefix, rowId),
subgrids = $(this).jqGrid("getGridParam", "userData"),
subgridPagerId = subgridDivId + "_p";
$("#" + $.jgrid.jqID(subgridDivId)).append($subgrid).append('<div id=' + subgridPagerId + '></div>');
$subgrid.jqGrid({
datatype: "local",
styleUI: 'Bootstrap',
data: subgrids[pureRowId],
editurl: 'clientArray',
colNames: ['Item', 'Item Description', 'Health Standard', 'Sort order', 'Statuses', 'Risks', 'Solutions', 'Budgets'],
colModel: [
{ name: 'itemName', width: '200', sortable: false, editable: true, editrules: { required: true }, editoptions: { maxlength: 50 } },
{ name: 'itemDescription', width: '400', sortable: false, editable: true, editoptions: { maxlength: 500 } },
{ name: 'healthStandard', width: '400', sortable: false, editable: true, editoptions: { maxlength: 500 } },
{ name: 'itemSortOrder', width: '200', sortable: false, editable: true, formatter: 'number', formatoptions: { decimalSeparator: ".", thousandsSeparator: ',', decimalPlaces: 2 } },
{ name: 'statuses', width: '400', sortable: false, editable: true, editoptions: { maxlength: 500 } },
{ name: 'risks', width: '400', sortable: false, editable: true, editoptions: { maxlength: 500 } },
{ name: 'solutions', width: '400', sortable: false, editable: true, editoptions: { maxlength: 500 } },
{ name: 'budgets', width: '400', sortable: false, editable: true, editoptions: { maxlength: 100 } }
],
//rownumbers: true,
rowNum: 5000,
autoencode: true,
autowidth: true,
pgbuttons: false,
viewrecords: true,
pginput: false,
jsonReader: { repeatitems: false, id: "groupId" },
gridview: true,
altRows: true,
altclass: 'myAltRowClass',
idPrefix: rowId + "_",
pager: "#" + subgridPagerId
});
$subgrid.jqGrid('navGrid', "#" + subgridPagerId, { edit: true, add: false, del: true, search: true, refresh: false, view: false }, // options
{ closeAfterEdit: true }, // edit options //recreateForm: true
{ closeAfterAdd: true }, // add options
{}, //del options
{} // search options
);
}
});
$('#jqGrid').navGrid('#jqGridPager', { edit: true, add: false, del: true, search: true, refresh: false, view: false }, // options
// options for Edit Dialog
{
editCaption: "Edit Group",
beforeShowForm: function (form) {
form.closest('.ui-jqdialog').center();
},
bottominfo: "<br/>",
recreateForm: true,
closeOnEscape: true,
closeAfterEdit: true
},
// options for Add Dialog
{
//url:'clientArray',
addCaption: "Add Group",
beforeShowForm: function (form) {
form.closest('.ui-jqdialog').center();
},
bottominfo: "<br/>",
recreateForm: true,
closeOnEscape: true,
closeAfterAdd: true
},
// options for Delete Dailog
{
caption: "Delete Group",
beforeShowForm: function (form) {
form.closest('.ui-jqdialog').center();
},
msg: "Are you sure you want to delete?",
recreateForm: true,
closeOnEscape: true,
closeAfterDelete: true
},
// options for Search Dailog
{
caption: "Search Group",
beforeShowForm: function (form) {
form.closest('.ui-jqdialog').center();
},
recreateForm: true,
closeOnEscape: true,
closeAfterDelete: true
}
);
There was a small bug in the form editing which is fixed now. Thank you for help us to find them.
Now to the problem.
When you add data in main grid it is natural to add a unique id of every row. Since of the bug instead of inserting a row with the Guriddo id Generator there was a wrong insertion with id = s_empty. This causes every inserted row in main grid to have same id, which is not correct.
The fix is published in GitHub and you can try it.
We have updated your demo in order to insert correct the data in the subgrid. The only small addition is in afterSubmit event in add mode, where the needed item is created.
Hope this will solve the problem
Here is the demo with the fixed version
Edited
At server you can analyze the id column if contain string 'jqg', which will point you that this is a new row. The corresponding id for the subgrid is in userData module which will connect the main grid id with the subgrid data
EDIT 2
One possible solution to what you want to achieve is to get the main data and the to get the subgrid data using userData property. After this make a loop to main data and update it like this
var maindata = $("#jqGrid").jqGrid('getGridParam', 'data');
var subgrids = $("#jqGrid").jqGrid('getGridParam', 'userData');
for(var i= 0;i < maindata.length;i++) {
var key = maindata[i].id;
if(subgrids.hasOwnProperty(key) ) {
if(!maindata[i].hasOwnProperty(groupItems) ) {
maindata[i].groupItems = [];
}
maindata[i].groupItems = subgrids[key];
}
}
The code is not tested, but I think you got the idea.
The other way is to update the groupitems on every CRUD of subgrid, which I think is not so difficult to achieve.

In jqgrid, How to Edit row using dialog?

How to do edit on popup dialog in jqgrid.
Below is jqgrid stuff. I dont' need inline editing. I want to popup dialog.
To popup dialog, we already have dialog which can be popup.
To achieve this, I need to call - javascript function which can allow to popup dialog.
please guide me how I could call javascript function on click of edit icon ?
$('#CategoriesGrdList').jqGrid({
ajaxGridOptions: {
error: function () {
$('#CategoriesGrdList')[0].grid.hDiv.loading = false;
alert('An error has occurred.');
}
},
url: '#Url.Action("GetAllCategoriesList", "Categories")/' + 0,
gridview: true,
autoencode: true,
postData: { categoryId: 1 },
datatype: 'json',
jsonReader: { root: 'List', page: 'Page', total: 'TotalPages', records: 'TotalCount', repeatitems: false, id: 'Id' },
mtype: 'GET',
colNames: ['Id', 'Code', 'Description', 'IsActive', "actions"],
colModel: [
{ name: 'Id', index: 'Id', hidden: false, key: true },
{ name: 'Code', index: 'Code', width: 170},
{ name: 'Description', index: 'Description', width: 170},
{ name: 'IsActive', index: 'IsActive', width: 170 },
{
name: 'actions', index: 'actions', formatter: 'actions',
formatoptions: {
keys: true,
editbutton: true,
delOptions: { url: '#Url.Action("DeleteCategory", "Categories")' }
}
}
],
pager: $('#CategoriesGrdPager'),
sortname: 'Code',
rowNum: 3,
rowList: [3, 6, 9],
width: '500',
height: '100%',
viewrecords: true,
multiselect: false,
caption: "Categories",
loadComplete: function () {
$("tr.jqgrow:odd").css("background", "#E0E0E0");
},
beforeSelectRow: function (rowid, e) {
return false;
},
sortorder: 'desc'
}).navGrid('#CategoriesGrdPager', { edit: true, add: false, del: false, search: false, refresh: true });
Pleae guide me.
To Make your own Edit actions/buttons in JQGrid, you need to set the default Edit navGrid buttons/actions to false, then add custom buttons to the navigation grid.
Here is an example below - remember to remove the navGrid setup in jqgrid chained functions above:
$('#CategoriesGrdList').jqGrid('navGrid', '#CategoriesGrdPager', { edit: false, add: false, del: false, search: false, refresh: true})
.navButtonAdd('#CategoriesGrdPager', {
title: "Edit",
caption: "Edit",
buttonicon: "ui-icon-pencil", // JQuery UI Icon
onClickButton: function () { /*CALL YOUR FUNCTION HERE*/ },
position: "last" // Position of the button on Nav
})'

JQGrid, Edit Url

I am new to jQuery, and I need to use jqGrid in my project.
I have one problem with edit/delete/insert; I have only one URL, editurl, then in the controller I am using the oper property to decide whether it is an insert or delete operation.
But I want to have a separate URL for the edit, delete and insert operations in jqGrid. Could you please let me know how to achieve that?
Client side code:
$(document).ready(function () {
var lastsel2;
var grid = jQuery("#list5").jqGrid({
url: '/home1/GetUserData',
datatype: "json",
mtype: "POST",
colNames: ['Code', 'LoginID', 'Emailid', 'CreateDate'],
colModel: [
// { name: 'act', index: 'act', width: 75, sortable: false },
{name: 'Code', index: 'Code', width: 55, editable: true },
{ name: 'LoginID', index: 'LoginID', width: 90, editable: true },
{ name: 'Emailid', index: 'Emailid', width: 100, editable: true },
{ name: 'CreateDate', index: 'CreateDate', width: 100, editable: true }
],
rowNum: 10,
width: 700,
height: 300,
rowList: 10,
pager: $("#pager2"),
editurl: "/home1/EditUserData",
onSelectRow: function (id) {
if (id && id !== lastsel2) {
if (id == "new_row") {
grid.setGridParam({ editurl: "/home1/InsertUserData" });
}
else {
grid.setGridParam({ editurl: "/home1/EditUserData" });
}
jQuery('#list5').restoreRow(lastsel2);
$("#list5_ilsave").addClass("ui-state-disabled");
$("#list5_ilcancel").addClass("ui-state-disabled");
$("#list5_iladd").removeClass("ui-state-disabled");
$("#list5_iledit").removeClass("ui-state-disabled");
lastsel2 = id;
}
},
caption: "Simple data manipulation"
});
jQuery("#list5").jqGrid('navGrid', '#pager2', { edit: false, add: false, del: true, search: false, refresh: false }, {}, {}, { url: '/home1/DeleteUserData' });
jQuery("#list5").jqGrid('inlineNav', "#pager2", { edit: true, add: true, del: true, search: false, refresh: false });
});
You can pass options for all the actions with navGrid method like this:
jQuery('#list5').jqGrid('navGrid', '#pager2', { edit: true, add: true, del: true },
//edit options
{ url: '/home1/EditUserData' },
//add options
{ url: '/home1/AddUserData' },
//delete options
{ url: '/home1/DeleteUserData' }
);
Please read more here and here.
UPDATE
In case of inlineNav method jqGrid is always passing the same set of parameters (editParams) to saveRow method. As the effect the edit/add request will be made to the same URL. You are sticked with checking oper to distinguish edit for add.
In the subject of reloading the grid you can use editParams to set aftersavefunc to trigger realoadGrid like this:
jQuery('#list5').jqGrid('inlineNav', '#pager2', { edit: true, add: true, editParams: {
aftersavefunc: function(rowId, response) { jQuery('#list5').trigger('reloadGrid'); }
}});
But you should remember that it will also cause a refresh after edit (because of the same reason as described above) - you may try to use response parameter to distinguish those two. I have also removed del, search and refresh from the code as inlineNav doesn't have those options.

JQGrid DataUrl usage with ASP.net (MVC 2.0)

I want to display a combobox with add/edit dialog on Jqgrid. I could do it with hardcoded values. But now I want to populate data from database (controller action). Can anyone help me writting the controller code for DataUrl. (Does it need Json formatted string of Value & Text?). My Grid definition is as below.
My other url actions are working fine.
jQuery("#myGrid").jqGrid({
pager: jQuery('#myGridPager'),
sortname: 'Name',
rowNum: 10,
rowList: [10, 20, 50],
sortorder: "asc",
height: "auto",
autowidth: true,
colNames: ['Id', 'Name', 'Dept', 'Status', 'ParentNodeName'],
colModel: [
{ name: 'Id', index: 'Id', hidden: true, key : true },
{ name: 'Name', index: 'Name', width: 200, editable: true, edittype: "text", editrules: { required: true} },
{ name: 'Dept', index: 'Dept', width: 90, editable: true, editrules: { required: true} },
{ name: 'Status', index: 'Status', width: 25, editable: true, edittype: "select", editoptions: { value: "A:Active;I:Inactive"} },
{ name: 'ParentNodeName',
index: 'ParentNodeName',
editable: true,
edittype: "select",
editoptions: { dataUrl: "/MyEntity/GetMyEntitys" }
},
],
datatype: 'json',
viewrecords: true,
mtype: 'GET',
jsonReader: {
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
userdata: "userdata"
},
url: "/MyEntity/GetMyEntitysData",
multiselect: false,
editurl: "/MyEntity/EditMyEntity?__SESSIONKEY=<%=Model.SessionKey %>",
caption: "Data Entry"
})
.navGrid('#myGridPager', { view: true, del: true, add: true, edit: true },
{ height: 150, reloadAfterSubmit: false, modal: true }, // default settings for edit
{ height: 150, reloadAfterSubmit: true, modal: true, url: "/MyEntity/AddMyEntity?__SESSIONKEY=<%=Model.SessionKey %>" }, // settings for add
{ height: "auto", reloadAfterSubmit: false, modal: true, url: "/MyEntity/DeleteMyEntity?__SESSIONKEY=<%=Model.SessionKey %>" }, // delete
{ closeOnEscape: true, multipleSearch: true, closeAfterSearch: true }, // search options
{} /* view parameters*/
);
Call controller code in dataUrl using edit options as below:
.aspx/js code:
editoptions: { dataUrl: "/YourControllerName/TheFunction" }
The controller code here:
public string TheFunction()
{
return ConstructSelect(Model.YourList);
}
public string ConstructSelect(SelectList collection)
{
string result = "<select>";
foreach (var item in collection)
{
result = result + "<option value = '" + item.Value + "'>" + item.Text + "</option>";
}
result = result + "</select>";
return result;
}
jqGrid wait for HTML code fragment (a valid HTML <select> element with the desired <options>: <select><option value='1'>One</option>…</select>) as the data returned from the dataUrl: "/MyEntity/GetMyEntitys". Because you return the data in JSON format you have to convert the data returned from the server with respect of the editoptions buildSelect. You can see the corresponding code example in my old answer.
One more small remark. Look at the jqGrid documentation and verify which parameters which you use are default. For example multiselect: false is default parameter. If you remove the default parameters from the grid definition the code wil be easier to read and it will work a litle bit quickly. In more complex parameters like jsonReader you could include only the properties which you want to change. For example you can use jsonReader in the form jsonReader : { repeatitems: true} because repeatitems is the only property of jsonReader which you want to change from the default settings. In the same way you can reduce { view: true, del: true, add: true, edit: true } to { view: true }.

Resources