Placing JSON response elements into a store- Ext JS - json

I'm wondering what the best way would be to load elements of a JSON response into a store.
What I have:
jQuery ajax request
var foodRequest = $.ajax({
url: "MyServlet",
type: "post",
cache: false,
dataType: "json",
data: JSON.stringify(searchquery),
error : function() {
alert ('ERROR!! Please re-enter the search criteria and try again.');
}
});
ajax response
{
"Foods":[
{
"Food":{
"name":"Spaghetti",
"id":"001",
"attributes":[
{
"attrname":"Price",
"attrvalue":"18.99"
},
{
"attrname":"Description",
"attrvalue":"Spaghetti is delicious, don't argue with me"
},
etc...
What I want:
(each element has 4 attributes)
var grid = Ext.define('Myapp.view.Grid' ,{
extend: 'Ext.grid.Panel',
id: 'mygrid',',
initComponent: function(columns) {
this.columns = [
{header: 'attrname', dataIndex: 'attrvalue', flex: 2 },
{header: 'attrname', dataIndex: 'attrvalue', flex: 2 },
{header: 'attrname', dataIndex: 'attrvalue', flex: 2 },
{header: 'attrname', dataIndex: 'attrvalue', flex: 2 },
etc...
How can I take the attributes from the json response and place them into a store my grid can use, as seen above?
Cheers!

The data you are returning looks like a tree. A normal grid works with fixed columns. In short:
a grid uses a store
the Store uses a number of fields or a Model.
a grid has a number of predefined columns, each column references a store(model) field by means of a dataIndex.
Now when the store loads data (either through a proxy or by manually dumping records in it). it creates a record internally. The fields on the record that are available are the fields you defined on the store or the fields you defined on the model the store uses.
Long story short, the normal setup of a grid and store is with a fixed number of columns and fields. In your case it would probably be better to use a TreePanel and store. Look at the treepanel example for this.
http://docs.sencha.com/extjs/4.0.7/extjs-build/examples/tree/treegrid.html
Good luck

Related

How to read kendo grid columns from a json file

I have a kendo grid which is reading data from a remote json file. I want that the grid columns should also be read from the same json file so that I dont have to change the client side code again and again. Whatever comes in the json file it should be capable enough to present the same data without any hard coding on client side. My json file looks like
{ "data":[
{"_type":"ProductDetails:#NWProducts","Discount":0,"OrderId":10248,"ProductId":11,"UnitPrice":14.0000,"quanity":12},{"_type":"ProductDetails:#NWProducts","Discount":0,"OrderId":10248,"ProductId":42,"UnitPrice":9.8000,"quanity":10},{"_type":"ProductDetails:#NWProducts","Discount":0,"OrderId":10248,"ProductId":72,"UnitPrice":34.8000,"quanity":5},{"_type":"ProductDetails:#NWProducts","Discount":0,"OrderId":10249,"ProductId":14,"UnitPrice":18.6000,"quanity":9}],
"columns":[
{"field":"_type","title":"Type"},{"field":"Discount","title":"Discount($)"},{"field":"OrderId","title":"Order ID"},{"field":"ProductId","title":"Product ID"},{"field":"UnitPrice","title":"Unit Price"},{"field":"quanity","title":"Quanity"}]
}
HTML code is as below
<div id="grid"></div>
JS code is below
$("#grid").kendoGrid({
title: { text: "Stats" },
sortable: false,
pageable: {
pageSizes: true,
buttonCount: 5
},
columnMenu: true,
dataSource: {
transport: {
read: {
url: "............/demo.json",
dataType: "json"
}
},
schema: {
data: "data"
}
},
columns: {
//What should be done here.
}
});
I tried the same transport read schema way to fetch the column data but it did not work. If I store the same columns json data in a variable and substitute that variable for columns then it works. Is there any way to store the columns json data as such in a variable from the json file. What is the best approach to achieve this behavior. Any help would be appreciated.
Thanks in Advance.

jqGrid + POST + default parameters + serializedGridData

I need to load my grid from a server that expect a URL + parameters + a serialized payload, i.e. the message body. I am using a POST method and the server expects this along with JSON payload.
The serialized payload is a JSON string for MongoDB that instructs mongo how to find the data we care about. I designed the RESTful interface to respond back in the JSON format that jqGrid expects, however, to use pagination, I expected jqGrid to append the values for "page", "rows", etc, etc as a query string: baseURL?rows=10&page=1
Here is my grid setup
grid.jqGrid({
ajaxGridOptions: {
contentType: "application/json",
},
altRows: true,
autoWidth: true,
caption: "Results for " + ADC_Idl.buildQueryTitle(),
colNames: displayNames,
colModel: columnModel,
datatype: "json",
height: "auto",
mtype: "POST",
pager: '#pager5',
//postData: ADC_Idl.buildQueryPayload(),
serializeGridData: function (postData) {
grid.jqGrid("setGridParam", "url", ADC_Idl.buildQueryURL() + "?" + jQuery.param(postData));
return ADC_Idl.buildQueryPayload();
},
beforeRequest: function() {
grid.jqGrid("setGridParam", "url", ADC_Idl.buildQueryURL() + "?page=" +
grid.jqGrid("getGridParam", "page") + "&rows=" +
grid.jqGrid("getGridParam", "rowNum") );
},
rowList: [10, 20, 30],
rowNum: 10,
url: ADC_Idl.buildQueryURL(),
viewrecords: true,
jsonReader: {
repeatitems: false
}
I've left a few things in there to show what I have tried. I tried having the serializedGridData function update the URL, with no luck, for whatever reason it seems to be ignored.
I tried updating the URL before the request, still no luck.
Originally I just set postData = serialized data, assuming the default pagination parameters would still be appended. This was not the case.
The documentation for postData just says "See API methods for manipulation" with no link (NO LINK IN A WIKI??!!! come on!!)
I've read every Oleg answer I could find here, nothing seems to address this scenario, which I find hard to understand, this must be a pretty common usecase.
This is how my server responds to the initial request for data (no pagination needed)
page: 1
records: 500
rows: [{_id: 1, REALM: "example.com", ACCOUNT: "8561000000",…},…]
total: 50
truncated for brevity.
After three days of trying everything I can think of, I'm pleading for some jqGrid experts to help!!
Thanks!
UPDATE
Figured it out and comments from Oleg made it even better. Posted as Answer!
Almost immediately after I posted this question I noticed something in another post from StackOverflow,
jqGrid("setGridParam"...
format is different for setting then getting, it excepts a hash for the update vs a parameter list for the get... UGH.
Once I fixed that, it worked!
Using some of the recommendations from Oleg's (thanks!) I have an even better solution as the code is cleaner and feels less hacky.
grid.jqGrid({
ajaxGridOptions: {
contentType: "application/json",
},
altRows: true,
autoWidth: true,
caption: "Results for " + ADC_Idl.buildQueryTitle(),
colNames: displayNames,
colModel: columnModel,
datatype: "json",
height: "auto",
gridview: true,
mtype: "POST",
pager: '#pager5',
postData: ADC_Idl.buildQueryPayload(),
beforeRequest: function() {
var gridParameters = jQuery(this).jqGrid("getGridParam");
var baseURL = gridParameters.url.split("?").shift();
var queryString = {
page: gridParameters.page,
rows: gridParameters.rowNum
};
gridParameters.url = baseURL + "?" + jQuery.param( queryString );
},
rowList: [10, 20, 30],
rowNum: 10,
url: ADC_Idl.buildQueryURL(),
viewrecords: true,
jsonReader: {
repeatitems: false,
id: "_id"
}
});
The relevant parts are:
postData: I use this to have jqGrid call my payload builder which returns JSON.stringify(payload object)
beforeRequest: Causes jqGrid to take the url used to define the grid with and remove any params already attached then update them with the newest values for page and rows.
jasonReader: added "id: "_id" as this is the key mongodb uses for the id.
gridview: true - This apparently speeds of the display of the grid? Oleg recommended, I did it, he's got a very detailed write up about it here: Oleg's explaination of gridview: true
It was also recommended that I provide my colModel, but I can't, this code is designed to build a jqGrid dynamically once the user submits a query that is directed at mongodb. The grid is built as a response to the users input, thus it is not something I have to share.

Have jqGrid display raw json in a column

I have a use case where I would like to have jqGrid display some raw JSON for a particular column. I have the following JSON being sent from the server:
{"items":[
{
"code":"ABC123",
"description":"",
"custom_data":{"items":[
{"prop1":"val1","prop2":"val2"},
{"prop1":"val3","prop2":"val4"}
]}
},
{"code":"ABC124","description":"","custom_data":[]},
...,
]}
and a jqGrid configuration like so:
{
url:'/api/somewhere',
datatype: "json",
jsonReader : {
root:"items",
repeatitems: false,
id: "code"
},
colNames:['Code',
'Description',
'Data',],
colModel:[
{
name:'code', index:'code', width:100, hidden:false,
edittype:'text',
editable: true,
editrules:{required:true, edithidden:true},
editoptions: {readonly:false}
},
{
name:'description',
index:'description',
width:250,
editable:true,
edittype:'text',
editrules:{required:true}
},
{
name:'custom_data',
index:'custom_data',
width:100,
hidden:true,
sortable:false,
editable:true,
edittype:'text',
editrules:{required:false, edithidden:true}
},
],
...,
The grid displays OK, but the custom_data column is displayed as [object Object]. What I need is for it to display the raw JSON string I have tried calling JSON.stringify on the custom_data object for each row object using the loadComplete event, but that didn't work. I need to do some data manipulation after the GET anyway, as I want to delete null values from the custom_data object.
My users are comfortable reading and editing raw JSON, so I also need the add/edit form to accept raw JSON which will then get POSTed.
I'm not sure if I'm simply using the wrong event to convert the object back to a string, or if there is something else going on.
What you can do is usage of custom formatter for "custom_data" column
formatter: function (cellValue, options, rawData) {
return cellValue.items ? JSON.stringify(cellValue.items) : "";
}
I changed in the demo hidden property for "custom_data" column to true to see the data
Additionally you can consider to use userdata instead of hidden column to save additional custom data. I recommend you to read the answer additionally which shows not only how to use userdata, but additionally how to show additional data in form subgrid.

jqgrid Toolbar search on custom formatted column

I am loading JQGrid from an API, one of the data structures that I have for my grid is a JSON element formatted as such:
{"id":123,"name":"John Doe","username":"john.doe"}
The data is properly displayed in the grid, however if I try to type in the toolbar search, I do not get a match presumably because jqgrid still has the above JSON stored as an object.
A truncated version of my grid is as follows:
$('#test').jqGrid({
...
loadonce: true,
datatype: 'local',
colModel: [
{name:'test', index:'test', label:'Test', formatter:customFormatter}
],
...
});
function customFormatter (cellvalue,options) {
return cellvalue.name;
}
I found this post that seems to address this very matter, however I am struggling to get my head around as to how to use this for a JSON object. Once the grid is loaded, I don't see a reason as to why the local data should be anything other than string (Until the grid is reloaded).
After stumbling upon the JSON dot notation in the docs, and adding it to the index this now works:
colModel: [
{name:'test.name', index:'test.name', label:'Test'}
]
You should choose name property of colModel which corresponds the names of the properties in the JSON input. So it's native to use just
colModel: [
{name: "name", label: "Name"}
{name: "username", label: "User Name"}
]
If you do need to remap some names in the JSON input to another names in the colModel you should use jsonmap property. For example
colModel: [
{name: "test1", label: "Name", jsonmap: "name"}
{name: "test2", label: "User Name", jsonmap: "username"}
]
The usage of index different as name is not possible in case of usage of loadonce: true. It is not recommended to use values of name property which have . or any other meta-character. The restriction exist because the name property will be used to build id property of many elements of the grid.

jqGrid toolbar search with autocomplete using json data

I found the very nice demo by Oleg (http://www.ok-soft-gmbh.com/jqGrid/FillToolbarSearchFilter.htm) which shows a "jqGrid toolbar search with autocomplete using local data" but have trouble to get this to work for json via ajax. Is there a good reason why the autocomplete feature won't work - even if I force the grid to be local after loading?
$(document).ready(function() {
var mygrid = $("#mylist"),
mygetUniqueNames = function(columnName) {
var texts = mygrid.jqGrid('getCol',columnName), uniqueTexts = [],
textsLength = texts.length, text, textsMap = {}, i;
for (i=0;i<textsLength;i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
return uniqueTexts;
};
mygrid.jqGrid({
url:'autocompleteTest.php',
datatype: "json",
colNames:['name', 'City','stateCd'],
colModel:[
{name:'name',index:'name',width:225, search: true},
{name:'City',index:'City',width:125},
{name:'stateCd',index:'stateCd',width:75},
],
rowNum: 100,
loadonce : true,
sortname: 'name',
sortorder: 'desc',
sortable: true,
viewrecords: true,
rownumbers: true,
sortorder: "desc",
ignoreCase: true,
pager: '#mypager',
height: "auto",
caption: "How to use filterToolbar better with data from server"
}).jqGrid('navGrid','#mypager',
{edit:false, add:false, del:false, search:false, refresh:false});
mygrid.jqGrid('setColProp', 'name',
{
searchoptions: {
sopt:['bw'],
dataInit: function(elem) {
$(elem).autocomplete({
source:mygetUniqueNames('name'),
delay:0,
minLength:0
});
}
}
});
mygrid.jqGrid('filterToolbar',
{stringResult:true, searchOnEnter:true, defaultSearch:"bw"});
});
It is difficult to provide an example in case of the usage of remote source parameter of jQuery UI Autocomplete. The main problem is that your question is about jqGrid which is pure JavaScript solution. If we would discuss the server part of tha solution we would have too options. Many users uses different languages: Java, C#, VB, PHP and so on. For example I personally prefer C#. Then we would have to choose the technology which we use: ASP.NET MVC, WCF, ASPX web service and so on. For example I would choose WCF. Then we should define the database access technology, for example, Entity Framework, LINQ to SQL, SqlDataReader, SqlDataAdapter and so on. Let us I would choose Entity Framework and would provide you the corresponding code example, but it would help you not really if you use for example PHP and MySQL.
So I just describe which interface should have the server for the remote source parameter of jQuery UI Autocomplete without any code.
You should replace in my example the source parameter to your server url like following:
dataInit: function(elem) {
$(elem).autocomplete({
source:'yourSearchUrl.php',
minLength:2
});
}
If the user types two characters (the value can be changed by minLength option), for example 'ab' then the autocomplete will make HTTP GET request with the parameter term=ab:
yourSearchUrl.php?term=ab
your server should answer with the JSON data in the same format as for the local source. I used the string array format in my previous example. Another supported format is array of objects with label/value/both properties like
[
{
"id": "Dromas ardeola",
"label": "Crab-Plover",
"value": "Crab-Plover"
},
{
"id": "Larus sabini",
"label": "Sabine`s Gull",
"value": "Sabine`s Gull"
},
{
"id": "Vanellus gregarius",
"label": "Sociable Lapwing",
"value": "Sociable Lapwing"
},
{
"id": "Oenanthe isabellina",
"label": "Isabelline Wheatear",
"value": "Isabelline Wheatear"
}
]
read the documentation for more information.
If you need to implement more complex scenario and send some additional data to the server or convert the server response in any way you can use custom source callback function. In the case you should use source: function(request, response) {/*your implementation*/}, where the request would be an object having term property (request.term). Inside of your implementation your should make ajax request to the server manually. The response would be callback function which you should call after your custom ajax request will be finished (inside of success event handler). The response function should be called with the parameter which should be array in the same format as mygetUniqueNames returns. I recommend you to examine the source code from the jQuery Autocomplete demo.
To de able to provide unique data from one column of tabele you should just use SELECT DISTINCT SQL statement which are supported in the most databases.
I hope that my description would help you.
UPDATED: If you have the local source the solution you could find in my old answer which you already use. What you just need to do is to call the filterToolbar after the source array are filled. Because you load the data from the server your should move the call of filterToolbar inside of loadComplete. You use loadonce:true jqGrid option which switch the datatype from 'json' to 'local' after the first data loading. So you can include in the loadComplete event handler of your grid the code like the following:
var grid = $('#list');
grid({
url:'autocompleteTest.php',
datatype: 'json',
loadonce: true,
// ... other parameters
loadComplete: function(data) {
if (grid.getGridParam('datatype') === 'json') {
// build the set 'source' parameter of the autocomplete
grid.jqGrid('setColProp', 'name', {
searchoptions: {
sopt:['bw'],
dataInit: function(elem) {
$(elem).autocomplete({
source:mygetUniqueNames('name'),
delay:0,
minLength:0
});
}
}
});
mygrid.jqGrid('filterToolbar',
{stringResult:true,searchOnEnter:true,
defaultSearch:"bw"});
}
}
});
If you will need to reload the data from the server (change the datatype to 'json' and call grid.trigger('reloadGrid')) you will have to change the code above so that you first destroy the autocomplete widget with $('#gs_name').autocomplete('destroy') and then create it one more time with the same code like inside of dataInit.