So I have a JsonRest store with a dgrid attached to it.
I use php and the yii framework.
If I fire a PUT I get a response formatted like this:
[{id: 1, abbreviation: 'FL' }]
Is that the correct form for the row to be updated?
Or should I get only {id: 1, abbreviation: 'FL' } as a response?
Thanks!
Update #1:
<div
data-dojo-type="dijit.MenuBar"
data-dojo-props="region:'top', layoutPriority:2, style:'margin-top: 10px'">
<div
id="OrderButton"
data-dojo-type="dijit.form.Button">
<span>Submit Order</span>
<script type="dojo/on" data-dojo-event="Click">
handleFinalizeOrder();
</script>
</div>
<span class="right">Package Price: 20$ + 1$/pic</span><span id="results"></span>
</div>
<div id="imageList"></div>
<?php $this->beginDojoScript() ?>
<script type="text/javascript">
require([
'dojo/parser',
'dojo/dom-construct',
'dojo/dom-style',
'dojo/_base/declare',
'dojo/_base/xhr',
'dojo/_base/loader',
'dojo/_base/Deferred',
'dojo/data/ItemFileWriteStore',
'dojo/store/util/QueryResults',
'dijit/Toolbar',
'dijit/Tree',
'dijit/TooltipDialog',
'dijit/layout/StackContainer',
'dijit/layout/ContentPane',
'dijit/form/Button',
'dijit/tree/ForestStoreModel',
'dijit/form/Form',
'dijit/form/ValidationTextBox',
'dijit/form/DropDownButton',
'dijit/form/CheckBox',
'dojox/form/Uploader',
'dojox/form/uploader/plugins/IFrame',
'dgrid/OnDemandGrid',
'dgrid/Selection',
'dojo/on',
'dgrid/editor',
'dgrid/List',
'dgrid/tree',
'dgrid/Keyboard',
'dijit/form/HorizontalSlider',
'dijit/form/NumberSpinner',
'dgrid/OnDemandGrid',
'dojo/store/Memory',
'dojo/store/Observable',
'dijit/form/FilteringSelect',
'dojo/data/ObjectStore',
'dijit/Dialog',
'dojo/store/Cache',
'dojo/store/JsonRest',
'dojo/domReady!'
], function(parser, domConstruct, domStyle, declare, xhr,
loader, Deferred,ItemFileWriteStore, QueryResults, Toolbar, Tree, TooltipDialog,
StackContainer, ContentPane, Button,
ForestStoreModel, Form, ValidationTextBox, DropDownButton, CheckBox,
Uploader, UploaderIFramePlugin, OndemandGrid, Selection, on, editor,
List, tree, Keyboard, Slider, NumberSpinner, Grid, Memory,
Observable, FilteringSelect, ObjectStore, Dialog, Cache, JsonRest) {
/* Declaration */
filetypeStore = Observable(new Memory({
idProperty: "pictype",
labelProperty: "name",
data: [
{ "pictype": "1", "name": "Paperpic" },
{ "pictype": "3", "name": "DVD" }
]
}));
filesubtypeStore = Observable(new Memory({
idProperty: "picsubtype",
labelProperty: "name",
data: [
{ "picsubtype": "1", "pictype": "1", "name": "10x15" },
{ "picsubtype": "2", "pictype": "1", "name": "13x18" },
{ "picsubtype": "3", "pictype": "1", "name": "20x30" },
{ "picsubtype": "4", "pictype": "1", "name": "30x45" },
{ "picsubtype": "10", "pictype": "3", "name": "DVD" }
]
}));
var columns = [
{
label: 'Picture',
field: 'filename',
formatter: function(filename){
return '<div class="icon" style="background-image:url(<?php echo Yii::app()->baseUrl ?>/images/client/thumbnails/' + filename + ');"><a class="iconlink" href="<?php echo Yii::app()->baseUrl ?>/images/client/' + filename + '"> </a></div>';
}
},
editor({
label: 'Type of pic', autoSave: false, field: 'pictype',
widgetArgs: {
store: filetypeStore, autoComplete: true, required: true, maxHeight: 150, style: "height: 20px; width: 120px;"
},
}, FilteringSelect),
editor({
label: 'Size of pic', autoSave: true, field: 'picsubtype',
widgetArgs: {
store: filesubtypeStore, autoComplete: true, required: true, maxHeight: 150, style: "height: 20px; width: 120px;"
},
}, FilteringSelect),
{
label: 'Price/pcs',
field: 'picprice',
formatter: function(picprice){
return '<span class="pic_price">' + picprice + '</span>';
}
},
editor({
label: 'Number of pics',
autoSave: true,
field: 'piccount',
widgetArgs: {
class: 'pic_count',
style: 'width: 4em;',
constraints: {
min:1,
max:100,
places:0
}
},
}, NumberSpinner),
];
/* Model */
collectionId = <?php echo $colID; ?>;
var userMemoryStore = Memory();
var userJsonRestStore = JsonRest({idProperty: "id", target: "<?php echo $this->createUrl('/orderCollectionOrder/handleOrderedImages') ?>?id=" + collectionId + "&picid="});
var imageStore = Cache(userJsonRestStore, userMemoryStore);
window.grid = new (declare([editor, ObjectStore, OndemandGrid, Selection]))({
store: imageStore,
getBeforePut: false,
columns: columns
}, "imageList");
parser.parse();
grid.on(".dgrid-content .iconlink:click", function (evt) {
evt.preventDefault();
var data = dojo.getAttr(this, "href");
var dlg = new Dialog({
title: "Pic: " + data.substr(15),
className:"dialogclass",
content: '<img src="' + data + '">'
});
dlg.show();
});
});
</script>
<?php $this->endDojoScript() ?>
So, if I change the second filteringselect, the put fires correctly.
Contents of put in firebug:
{"id":"1","categoryId":"2","collectionId":"146","fileid":"20737","pictype":"3","picsubtype":"2","filename":"pic_143_resize.jpg","filetype":"DVD","filesubtype":"30x45","picprice":"2000","piccount":"2"}
Response:
{"id":"1","categoryId":"2","collectionId":"146","fileid":"20737","pictype":"3","picsubtype":"2","filename":"pic_143_resize.jpg","filetype":"DVD","filesubtype":"13x18","picprice":"300","piccount":"2"}
So I get the response, but the dgrid does not get updated...
Should I add an Observable store as well?
Thanks!
This actually comes down to logic in dojo/store/Observable in this case. Observable will do one of two things in response to put calls:
If the server request resolves to an object, this object will be passed to notify (which the grid will pick up)
Otherwise, the object originally passed to put will be passed through to notify
You're falling into the first case, since arrays are objects - in which case, as you suspected, you'll want just the object itself, not an array. The array doesn't make much sense anyway, since put operates on a single item.
Related
Context
I want to use cytoscape.js for visualizing graphs. While I am capable with a myriad of languages (C++, Mathematica, R, etc), I am new to Javascript, JSON, HTML, and CSS. Thus it would be favorable to learn these languages through this use case (implementing graphs with cytoscape.js). Please keep this in mind in your answer.
I have previously asked how to [remotely load cytoscape.js and how to get graphs display (requires a div). Since then I have created a script that turns a graph as represented in one of the other languages I use, into the JSON format indicated here. While I can just copy-paste all of this directly into my program, for large networks that is clearly a poor way to implement it. An example of my script's output is at the bottom of this.
Question
Given a JSON object/file(?) how can I do the following:
load it into cytoscape.js without copy-pasting the code.
referencing it once loaded. (e.g. basic explanation of how JSON syntax for use in cytoscape.js)
Script Output
cytoscape({
container: document.getElementById('cy'),
elements: [
{// node Node 1
group: 'nodes',
data: {
id: 'Node 1'
},
selected: false,
selectable: true,
locked: false,
grabbable: true,
selectable: true,
},
{// node Node 2
group: 'nodes',
data: {
id: 'Node 2'
},
selected: false,
selectable: true,
locked: false,
grabbable: true,
selectable: true,
},
{// node Node 3
group: 'nodes',
data: {
id: 'Node 3'
},
selected: false,
selectable: true,
locked: false,
grabbable: true,
selectable: true,
},
{// edge 1_2
group: 'edges',
data: {
id: '1_2',
source: '1',
target: '2'
}
},
{// edge 2_3
group: 'edges',
data: {
id: '2_3',
source: '2',
target: '3'
}
},
{// edge 3_1
group: 'edges',
data: {
id: '3_1',
source: '3',
target: '1'
}
}
],
style: [
{
selector: 'node',
style: {
'content': 'data(id)'
}
}
]
});
<head>
<title></title>
<script src="js/vendor/cytoscape.min.js"></script>
<script src="js/vendor/jquery.min.js"></script>
</head>
<style>
#cy {
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
}
</style>
<body>
<div id="cy"></div>
<script>
$.getJSON("cyto.js", function (data) {
//console.log(data);
var cy = cytoscape({
container: document.getElementById('cy'),
elements: data,
style: [
{
selector: 'node',
style: {
'label': 'data(label)',
'width': '60px',
'height': '60px',
'color': 'blue',
'background-fit': 'contain',
'background-clip': 'none'
}
}, {
selector: 'edge',
style: {
'text-background-color': 'yellow',
'text-background-opacity': 0.4,
'width': '6px',
'target-arrow-shape': 'triangle',
'control-point-step-size': '140px'
}
}
],
layout: {
name: 'circle'
}
});
});
</script>
</body>
in cyto.js you can input valid JSON data, for example
{
"nodes": [
{
"data": {"id": "a", "label": "Gene1"}
},
{
"data": {"id": "b", "label": "Gene2"}
},
{
"data": {"id": "c", "label": "Gene3"}
},
{
"data": {"id": "d", "label": "Gene4"}
},
{
"data": {"id": "e", "label": "Gene5"}
},
{
"data": {"id": "f", "label": "Gene6"}
}
],
"edges": [
{
"data": {
"id": "ab",
"source": "a",
"target": "b"
}
},
{
"data": {
"id": "cd",
"source": "c",
"target": "d"
}
},
{
"data": {
"id": "ef",
"source": "e",
"target": "f"
}
},
{
"data": {
"id": "ac",
"source": "a",
"target": "d"
}
},
{
"data": {
"id": "be",
"source": "b",
"target": "e"
}
}]
}
Let's presume you have a json file in the same folder as your 'index.html', and your server is running. First request the json file via a http request (using plain javascript or jquery ).
If your json file has the same format as the elements properties, you can just parse it to a javascript object and set it. E.g.
var myObject = {};
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myObject = JSON.parse(this.responseText);
initCytoscape();
}
};
xhttp.open("GET", "myJson.json", true);
xhttp.send();
function initCytoscape() {
cytoscape({
container: document.getElementById('cy'),
elements: myObject
});
}
if the json property is different than cytoscape's format, then you have to programatically convert it.
How to get Kendo Grid to sort by a specific field if using k-data-source?
Here is my HTML:
Here is my Controller:
getBusinessUnits();
function getBusinessUnits() {
operatorService.getBusinessUnits()
.success(function (data) {
$scope.businessUnits = data;
});
};
$scope.gridOptions = {
batch: false,
reorderable: true,
sortable: true,
editable: "inline",
columns: [
{ template: '<i class="fa fa-chevron-circle-up" style="cursor:pointer" ng-click="MoveUp(#=OperatorBusinessUnitID#)"></i> <i class="fa fa-chevron-circle-down" style="cursor:pointer"></i>', title: "List Order" },
{ field: "OperatorBusinessUnitID", title: "Business Unit ID" },
{ field: "vchDescription", title: "Business Unit Name" },
{ field: "vchOperatorSystemID", title: "Operator System ID"},
{
command: [
{ name: "edit", text: " " },
{ name: "destroy", text: " " },
], title: "Action"
}
]
};
The data returned by the service from the SQL database is returned by the SQL stored procedure in the order that I need it. However, the grid automatically defaults to sorting it my the ID column. Is there any way to tell it which field to sort by default if I am not "creating" a datasource object in my Angular Controller?
I'm having a terrible time trying to get a simple jQWidget treegrid working with Angular.
The example using an Angular SPA I'm referring to is here: https://www.jqwidgets.com/jquery-widgets-documentation/documentation/angularjs/angularjs-directives/angularjs-jquery-treegrid.htm
And the initial tutorial page is here: https://www.jqwidgets.com/jquery-widgets-documentation/documentation/angularjs/angularjs-directives.htm
The front end error I'm getting is:
`ReferenceError: dataAdapter is not defined
at eval (eval at link (localhost:49479/app/services/directives.js:234:59), <anonymous>:1:27)
at link (localhost:49479/app/services/directives.js:234:28)`
[app] [HT Error] dataAdapter is not defined
Object {exception: ReferenceError, cause: "<span id="jqxTreeGrid" ng-jqwidgets="jqxTreeGrid" …pageable, columns: columns, disabled: disabled}">"}
cause: "<span id="jqxTreeGrid" ng-jqwidgets="jqxTreeGrid" ng-jqxsettings="{theme: 'metro', source: dataAdapter, width: 850, sortable: sortable, pageable: pageable, columns: columns, disabled: disabled}">"
exception: ReferenceError
and dataAdapter is binded in ng-jqxsettings="{theme: 'metro', source: dataAdapter ...}".
I also noticed as I debug in chorme f12, that my $scope.dataAdapater is empty of the data I have in the source var. In other words, 'source' contains valid data but never gets assigned to dataApapter :
$scope.dataAdapter = new $.jqx.dataAdapter(source);
My dashboard.html contains the <span id="jqxTreeGrid" ...> , which is giving me trouble :
<section id="dashboard-view" class="mainbar" data-ng-controller="dashboard as vm">
<section class="matter">
<div class="container-fluid">
<div class="row-fluid">
<div class="col-md-12"> <!-- HIERARCHY GRID -->
<div class="widget wlightblue">
<div data-cc-widget-header title="{{'Hierarchy'}}" subtitle="" allow-collapse="true"></div>
<div class="widget-content text-left text-info" style="float:left; border:none;">
<span>THIS IS A TEST</span>
<span id="jqxTreeGrid" ng-jqwidgets="jqxTreeGrid"
ng-jqxsettings="{theme: 'metro', source: dataAdapter, width: 850, sortable: sortable, pageable: pageable, columns: columns, disabled: disabled}">
</span>
<div class="widget-foot">
<div class="clearfix"></div>
</div>
</div>
</div>
</div>
</div>
and my controller is :
(function () {
'use strict';
var controllerId = 'dashboard';
angular.module('app').controller(controllerId, ['common', 'datacontext', '$scope', dashboard ]);
function dashboard(common, datacontext, $scope) {
var getLogFn = common.logger.getLogFn;
var log = getLogFn(controllerId);
var vm = this;
vm.news = {
title: 'Test Online',
description: 'queries to dynamically aggregate data. .'
};
activate();
function activate($scope) {
var promises = [getMessageCount(), getCountries(), getMemberMtm(), initJqTreeGrid()];
common.activateController(promises, controllerId)
.then(function () { log('Activated Dashboard View'); });
}
///jQWidgets treegrid settings
function initJqTreeGrid() {
var source =
{
dataType: "array",
dataFields: [
{ name: "name", type: "string" },
{ name: "quantity", type: "number" },
{ name: "id", type: "string" },
{ name: "parentid", type: "number" },
{ name: "price", type: "number" },
{ name: "date", type: "date" },
{ name: "customer", type: "string" }
],
hierarchy:
{
keyDataField: { name: 'id' },
parentDataField: { name: 'parentid' }
},
id: 'id',
localData: generateordersdata()
};
$scope.dataAdapter = new $.jqx.dataAdapter(source);
$scope.theme = "metro";
$scope.sortable = true;
$scope.pageable = true;
$scope.disabled = false;
$scope.columns = [
{ text: 'Order Name', dataField: "name", align: 'center', width: 200 },
{ text: 'Customer', dataField: "customer", align: 'center', width: 200 },
{ text: 'Price', dataField: "price", cellsFormat: "c2", align: 'center', cellsAlign: 'right', width: 80 },
{
text: 'Order Date', dataField: "date", align: 'center', cellsFormat: "dd-MMMM-yyyy hh:mm", cellsRenderer: function (rowKey, column, cellValue, rowData, cellText) {
if (rowData.level === 0) {
return $scope.dataAdapter.formatDate(cellValue, "dd-MMMM-yyyy");
}
return cellText;
}
}
];
}
Your advice will be greatly appreciate by me.
regards,
Bob
I used a different example from their tutorial and was able to get it running. Slight difference, I am having my settings within controller definition, rather then inline. I had better luck with that. Loading order makes all the difference as well. Here is my code for the grid example.
JavaScript:
<script type="text/javascript">
var demoApp = angular.module("demoApp", ["jqwidgets"]);
demoApp.controller("demoController", function ($scope) {
// Grid data.
var data = new Array();
var firstNames = ["Nancy", "Andrew", "Janet", "Margaret", "Steven", "Michael", "Robert", "Laura", "Anne"];
var lastNames = ["Davolio", "Fuller", "Leverling", "Peacock", "Buchanan", "Suyama", "King", "Callahan", "Dodsworth"];
var titles = ["Sales Representative", "Vice President, Sales", "Sales Representative", "Sales Representative", "Sales Manager", "Sales Representative", "Sales Representative", "Inside Sales Coordinator", "Sales Representative"];
var city = ["Seattle", "Tacoma", "Kirkland", "Redmond", "London", "London", "London", "Seattle", "London"];
var country = ["USA", "USA", "USA", "USA", "UK", "UK", "UK", "USA", "UK"];
for (var i = 0; i < firstNames.length; i++) {
var row = {};
row["firstname"] = firstNames[i];
row["lastname"] = lastNames[i];
row["title"] = titles[i];
row["city"] = city[i];
row["country"] = country[i];
data[i] = row;
}
$scope.people = data;
$scope.bindingCompleted = "";
$scope.settings =
{
altrows: true,
width: 800,
height: 200,
editable: true,
ready: function()
{
$scope.settings.apply('selectrow', 1);
},
sortable: true,
source: $scope.people,
selectionmode: 'multiplecellsadvanced',
columns: [
{ text: 'First Name', datafield: 'firstname', width: 150 },
{ text: 'Last Name', datafield: 'lastname', width: 150 },
{ text: 'Title', datafield: 'title', width: 150 },
{ text: 'City', datafield: 'city', width: 150 },
{ text: 'Country', datafield: 'country' }
],
bindingcomplete: function (event) {
$scope.bindingCompleted = "binding is completed";
}
}
});
</script>
HTML:
<div ng-app="demoApp" ng-controller="demoController">
<jqx-grid jqx-settings="settings"></jqx-grid>
</div>
I have a php-script, which returns the following JSON
[
{
"Code":0,
"Message":"No problem"
},
{
"name":"o016561",
"status":1,
"locks":[
{
"ztn":"155320",
"dtn":"20131111",
"idn":"78"
},
{
"ztn":"155320",
"dtn":"20131111",
"idn":"91"
}
]
},
{
"name":"o011111",
"status":1,
"locks":[
{
"ztn":"155320",
"dtn":"20131111",
"idn":"91"
}
]
},
{
"name":"o019999",
"status":0,
"locks":[
]
},
{
"name":"o020000",
"status":0,
"locks":[
]
},
{
"name":"o020001",
"status":0,
"locks":[
]
}
]
Edit:
The grid should look something like this:
I've been able to load name and status into my grid - so far so good. But the more important part is, that I need the nested data in the locks-array being loaded into my grid, but I just can't get my code working. Any help would be appreciated.
I'm using ExtJS 4.2 if that matters.
Edit 2:
I tried
Ext.define("Locks", {
extend: 'Ext.data.Model',
fields: [
'ztn',
'dtn',
'idn'
]
});
Ext.define("ConnectionModel", {
extend: 'Ext.data.Model',
fields: ['name', 'status'],
hasMany: [{
model: 'Locks',
name: 'locks'
}]
});
var store = Ext.create('Ext.data.Store', {
model: "ConnectionModel",
autoLoad: true,
proxy: {
type: 'ajax',
reader: {
type: 'json',
root: 'name'
}
}
});
but it seemed to be wrong in multiple ways...
and it would be awesome if ztn and dtn could be displayed just seperated with a whitespace in the same column
You can add a renderer to the column. In that renderer you can do anything with the record...
Here's a working fiddle:
http://jsfiddle.net/Vandeplas/MWeGa/3/
Ext.create('Ext.grid.Panel', {
title: 'test',
store: store,
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Status',
dataIndex: 'status'
}, {
text: 'idn',
renderer: function (value, metaData, record, rowIdx, colIdx, store, view) {
values = [];
record.locks().each(function(lock){
values.push(lock.get('idn'));
});
return values.join('<br\>');
}
}, {
text: 'ztn + dtn',
renderer: function (value, metaData, record, rowIdx, colIdx, store, view) {
values = [];
record.locks().each(function(lock){
values.push(lock.get('ztn') + ' ' + lock.get('dtn'));
});
return values.join('<br\>');
}
}],
height: 200,
width: 600,
renderTo: Ext.getBody()
});
Note
If you have control over your backend you better change the form of your data more like this:
{
"code": 0,
"message": "No problem",
"success": true,
"data": [
{
"name": "o016561",
"status": 1,
"locks": [
{
"ztn": "155320",
"dtn": "20131111",
"idn": "78"
},
{
"ztn": "155320",
"dtn": "20131111",
"idn": "91"
}
]
},
{
"name": "o011111",
"status": 1,
"locks": [
{
"ztn": "155320",
"dtn": "20131111",
"idn": "91"
}
]
}
]
}
That way you don't mix your control data (success, message, code,...) with your data and the proxy picks it up correctly (it can be a cause of the problems your experiencing). I added a success boolean => Ext picks it up and goes to the failure handler. It helps a lot with your exception handling.
Here is the proxy for it:
proxy: {
type: 'ajax',
api: {
read: ___URL____
},
reader: {
type: 'json',
root: 'data',
messageProperty: 'message'
}
}
I need some idea, about how to implement a subgrid in the following sceaniro.
The following is the json data that I want to display in the JQuery Grid and Subgrid.
Basically I am getting an object called "Contact" that has a collection called "actionSet".
{
"total" : "10",
"page" : "1",
"records" : "78",
"rows" : [ {
"comment" : null,
"givenName" : "Contact A",
"familyName" : "A",
"actionSet" : [ {
"actionID" : 1,
"actionDueDate" : "2012-12-08",
"actionNote" : "Action 1"
}, {
"actionID" : 2,
"actionDueDate" : "2012-12-08",
"actionNote" : "Action 2"
} ]
} ...]
}
I want eache Grid row to display the "Contact" and the subgris associated with the grid should display "actionSet" collection.
When a particular row in the Grid is selected, I do not want to make a server call to get the associated actions, as they are allready present in the "actionSet".
I have got the Grid working, displaying the "Contacts" nicely, but I get confused while implement the subgrid, as how to get the data for it, as its allready available in json.
jq(function() {
jq("#grid").jqGrid({
url:'/smallworks/project/getall.do',
datatype: 'json',
mtype: 'GET',
colNames:['Id', 'First Name', 'Last Name'],
colModel:[
{name:'id',index:'id', width:55,editable:false,editoptions: {readonly:true,size:10},hidden:true},
{name:'givenName',index:'givenName', width:100,editable:true, editrules:{required:true}, editoptions:{size:10}},
{name:'familyName',index:'familyName', width:100,editable:true, editrules:{required:true}, editoptions:{size:10}}
],
postData: {
},
rowNum:20,
rowList:[20,40,60],
height: 200,
autowidth: true,
rownumbers: true,
pager: '#pager',
sortname: 'id',
viewrecords: true,
sortorder: "asc",
caption:"Contacts",
emptyrecords: "Empty records",
loadonce: false,
loadComplete: function() {
},
Is this achievable?
Do I need to parse JSON data specially for the subgrid?
How can this be achieved?
I suggest that you save information from actionSet in an object which you can easy access later. For example you can use userData parameter and fill the userdata part of JSON data inside of beforeProcessing. The create subgrid you can follow the answer or another one.
The demo demonstrate the implementation approach:
It uses the following code
var mainGridPrefix = "s_";
$("#grid").jqGrid({
url: "Adofo.json",
datatype: "json",
colNames: ["First Name", "Last Name"],
colModel: [
{ name: "givenName" },
{ name: "familyName" }
],
cmTemplate: {width: 100, editable: true, editrules: {required: true},
editoptions: {size: 10}},
rowNum: 20,
rowList: [20, 40, 60],
pager: "#pager",
gridview: true,
caption: "Contacts",
rownumbers: true,
autoencode: true,
height: "100%",
idPrefix: mainGridPrefix,
subGrid: true,
jsonReader: { repeatitems: false },
beforeProcessing: function (data) {
var rows = data.rows, l = rows.length, i, item, subgrids = {};
for (i = 0; i < l; i++) {
item = rows[i];
if (item.actionSet) {
subgrids[item.id] = item.actionSet;
}
}
data.userdata = subgrids;
},
subGridRowExpanded: function (subgridDivId, rowId) {
var $subgrid = $("<table id='" + subgridDivId + "_t'></table>"),
pureRowId = $.jgrid.stripPref(mainGridPrefix, rowId),
subgrids = $(this).jqGrid("getGridParam", "userData");
$subgrid.appendTo("#" + $.jgrid.jqID(subgridDivId));
$subgrid.jqGrid({
datatype: "local",
data: subgrids[pureRowId],
colNames: ["Due Date", "Note"],
colModel: [
{ name: "actionDueDate", formatter: "date", sorttype: "date" },
{ name: "actionNote" }
],
sortname: "actionDueDate",
height: "100%",
rowNum: 10000,
autoencode: true,
autowidth: true,
jsonReader: { repeatitems: false, id: "actionID" },
gridview: true,
idPrefix: rowId + "_"
});
}
});
UPDATED: The JSON data used in the demo one can see below. I added id property which is required for jqGrid. I used actionID as the id of the subgrids:
{
"total": "10",
"page": "1",
"records": "78",
"rows": [
{
"id": 10,
"comment": null,
"givenName": "Contact A",
"familyName": "A",
"actionSet": [
{
"actionID": 1,
"actionDueDate": "2012-12-08",
"actionNote": "Action 1"
},
{
"actionID": 2,
"actionDueDate": "2012-12-09",
"actionNote": "Action 2"
}
]
},
{
"id": 20,
"comment": null,
"givenName": "Contact B",
"familyName": "B",
"actionSet": [
{
"actionID": 3,
"actionDueDate": "2012-12-11",
"actionNote": "Action 3"
},
{
"actionID": 4,
"actionDueDate": "2012-12-10",
"actionNote": "Action 4"
}
]
}
]
}