jqGrid has no addJSONData method - javascript

I'm just playing around with jqGrid this afternoon, and have it working fairly well with a local array data source. However, now I'm trying to get it to load local JSON data.
My code is as follows:
jQuery("#list4").jqGrid({
datatype: "json", //<-- Also tried "local" here
height: 'auto',
autowidth: true,
forceFit: true,
colNames:['ID','Name'],
colModel:[
{name:'id',index:'id', width:60, sorttype:"int", jsonmap:"id"},
{name:'name',index:'name', width:90, jsonmap: "name"}
],
multiselect: false,
caption: "Test"
});
I then try to load JSON data using the following:
jQuery("#list4").jqGrid.addJSONData(json);
The issue is that jQuery("#list4").jqGrid.addJSONData is undefined. I've also tried:
jQuery("#list4").jqGrid('addJSONData', json);
Which throws an exception saying that the method addJSONData is not defined. I can see other documented methods on jQuery("#list4").jqGrid, just not this one. addXMLData is also missing. However, I can verify that these methods are in the jquery.jqGrid.min.js source code.
I just downloaded jqGrid today, so I know I have the latest versions of everything.
I must be doing something wrong, but I'm not sure what it could be. I've put the entire page here:
http://pastie.org/3825067

The addJSONData is very old method which uses still expandos to the DOM element of the grid (<table> element). So to use addJSONData correctly one should use
jQuery("#list4")[0].addJSONData(json);
See the documentation. More beter way will be to create jqGrid and fill the data directly. You can use
jQuery("#list4").jqGrid({
datatype: "local",
data: mydata,
height: 'auto',
autowidth: true,
colNames: ['ID', 'Name'],
colModel: [
{name: 'id', index: 'id', width: 60, sorttype: "int", key: true},
{name: 'name', index:'name', width: 90}
],
caption: "Test",
gridview: true // !!! improve the performance
});
The format of mydata can be like
var mydata = [
{id: 10, name: "Oleg"},
{id: 20, name: "Mike"}
];
It's allow to use local paging, filtering and sorting of data. The input data need not be sorted.
Alternatively you can use datatype: 'jsonstring' and datastr. The value of datastr can be either JSON string or already parsed object. The data from datastr have to be correctly sorted (if you use some sortname and sortorder parameters) and have the same format as for datatype: 'json' (see the documentation). One can use jsonReader and jsonmap to specify the data format:
var mydata = {
//total: 1, // will be ignored
//page: 1, // will be ignored
//records: 2 // will be ignored
rows: [
{id: 10, name: "Oleg"},
{id: 20, name: "Mike"}
]
];
What is the most strange for me is why you need to load "local JSON data"? Where is the difference to the "local array data source"? You can use $.parseJSON to convert the input data to object or use datatype: 'jsonstring' directly. In the most cases the usage of addJSONData is because of loading the data from the server manually per jQuery.ajax which is really bed idea (see one from my first posts on the stackoverflow here). jqGrid has a lot of customization options and callbackes like ajaxGridOptions, serializeGridData and beforeProcessing, you can use functions in jsonReader (see here) and jsonmap, which allows you to load practically any format of input data. Using prmNames, serializeGridData and postData (see here) you can make practically any customization of the parameters sent to the server. So the usage of low-level addJSONData are needed really in extremely very seldom scenarios.

For the most part, you are close. I don't think the addJSONData method is the way to go. Here's how we deal with local JSON data:
The grid:
$("#list4").jqGrid({
datatype: "local", //<-- "local" tells jqGrid not to try and get the data itself
height: 'auto',
autowidth: true,
forceFit: true,
colNames:['ID','Name'],
colModel:[
{name:'id',index:'id', width:60, sorttype:"int", jsonmap:"id"},
{name:'name',index:'name', width:90, jsonmap: "name"}
],
multiselect: false,
caption: "Test"
});
Give data to the grid:
// Clear the grid if you only want the new data
$('#list4').clearGridData(true);
// Set the data the tell the grid to refresh
$('#list4').setGridParam({ data: jsonData, rowNum: jsonData.length }).trigger('reloadGrid');
You should also change your jsonData to:
var jsonData = [
{id: 1, name: 'Apple'},
{id: 2, name: 'Banana'},
{id: 3, name: 'Pear'},
{id: 4, name: 'Orange'}
];
jqGrid is going to look to match up the columns specified to the objects passed into the array.

I'm working with version jqGrid 4.1.2
Having initialized the grid with a JSONReader and datatype:'jsonstring', when adding jsonstring data I've to include the datatype:'jsonstring' parameter.
$('#list4').setGridParam({ datastr: jsonData, datatype:'jsonstring', rowNum: jsonData.length }).trigger('reloadGrid');
As far as I know that is because after initialize the datatype:'jsonstring' is turned to datatype:'local', so when adding jsonstring it tries to load data from "data" param instead of "datastr" but because is empty no data is loaded.
I hope to contribute to this ...

Related

Extjs 4.2.1 Local filtering of Grid panel with Paging

Fiddle with the problem is here https://fiddle.sencha.com/#view/editor&fiddle/2o8q
There are a lot of methods in the net about how to locally filter grid panel that have paging, but no one is working for me. I have the following grid
var grid = Ext.create('Ext.grid.GridPanel', {
store: store,
bbar: pagingToolbar,
columns: [getColumns()],
features: [{
ftype: 'filters',
local: true,
filters: [getFilters()],
}],
}
Filters here have the form (just copy pasted part of my filters object)
{
type: 'string',
dataIndex: 'name',
active: false
}, {
type: 'numeric',
dataIndex: 'id',
active: false
},
The store is the following
var store = Ext.create('Ext.data.Store', {
model: 'Store',
autoLoad: true,
proxy: {
data: myData,
enablePaging: true,
type: 'memory',
reader: {
type: 'array',
}
},
});
Here myData - comes to me in the form of
["1245", "Joen", "Devis", "user", "", "email#com", "15/6/2017"],
["9876", "Alex", "Klex", "user", "", "email#com", "15/6/2017"],[...
Also I have the the pagingToolbar
var pagingToolbar = Ext.create('Ext.PagingToolbar', {
store: store, displayInfo: true
});
So all the elements use the store I declared in the top. I have 25 elements per grid page, and around 43 elements in myData. So now I have 2 pages in my grid. When I am on first page of grid and apply string filter for name, for example, it filters first page (25 elements), when I move to 2d page, grid is also filtered, but in scope of second page. So as a result each page filters seperately. I need to filter ALL pages at the same time when I check the checkbox of filter, and to update the info of pagingToolbar accordingly. What I am doing wrong?
Almost sure that it is a late answer, but I have found the local store filter solution for paging grid you are probably looking for:
https://fiddle.sencha.com/#fiddle/2jgl
It used store proxy to load data into the grid instead of explicitly specify them in store config.
In general:
create empty store with next mandatory options
....
proxy: {
type: 'memory',
enablePaging: true,
....
},
pageSize: 10,
remoteFilter: true,
....
then load data to the store using its proxy instead of loadData
method
store.getProxy().data = myData;
store.reload()
apply filter to see result
store.filter([{ property: 'name', value: 'Bob' }]);
See President.js store configuration in provided fiddle example for more details.
Hope it helps

How to use external libraries in a custom formatter?

I have some data coming as a timestamp so I need to format it before it goes to the end user. I didn't found any way to achieve this using a predefined formatter from jQgrid.
Having said that I am trying to use a mix of "native" Javascript and MomentJS to format the data before display it.
The first thing I did was load the library momentjs before load jqgrid:
<script src="js/jquery-3.2.1.min.js" type="text/javascript"></script>
<script src="js/jquery-migrate-3.0.1.min.js" type="text/javascript"></script>
<script src="js/moment.min.2.20.1.js" type="text/javascript"></script>
<script src="js/free-jqgrid/jquery.jqgrid.min.js" type="text/javascript"></script>
Next I have created a custom formatter to be used in that column:
$.extend($.fn.fmatter, {
customTimestampToDate: function (cellvalue, options, rowdata) {
var parsed_timestamp = parseInt(rowdata.timestamp),
tmp = new Date(parsed_timestamp * 1000).toISOString();
console.log(typeof cellvalue); // logs string
console.log(typeof rowdata.timestamp); // logs string
console.log(typeof parsed_timestamp); // logs "number"
console.log(tmp); // logs 2018-01-15T14:19:28.000Z
return moment(tmp);
}
});
Last I have tried to use the custom formatter in the colModel:
colModel: [
{name: "act", template: "actions", width: 115},
{name: "username", search: true, stype: "text"},
{name: "email", search: true, stype: "text"},
{name: "first_name", search: true, stype: "text"},
{name: "last_name", search: true, stype: "text"},
{name: "company", search: true, stype: "text"},
{name: "request_uri", search: true, stype: "text"},
{name: "client_ip", search: true, stype: "text"},
{
name: "timestamp",
search: true,
stype: "text",
formatter: "customTimestampToDate"
}
],
For some reason I am getting the timestamp value instead of the formatted one and I am not sure why or how.
I have been playing with momentjs on this Fiddle and it works as expected. I have been playing also with momentjs inside jqgrid in this Fiddle and as I am showing here is not working.
The problem: the issue here is the value being displayed as a string|int at timestamp column after the grid render which means the value on the column is the timestamp. The expected value would be the formatted one by moment doesn't matter if it's properly formatted or not (that's another different issue).
My guess is that the library hasn't been loaded when the grid is constructed or something like that but I am not sure at all.
Any ideas?
Note: Maybe there is an easy way to achieve this using a predefined formatter but I couldn't find it, if you know it let me know
To display timestamps in jqGrid you can use predefined formatter "date" instead of the custom formatter: "customTimestampToDate". You can replace
formatter: "customTimestampToDate"
to, for example,
formatter: "date", sorttype: "date",
formatoptions: {srcformat: "u", newformat: "n/j/Y g:i:s A"}
The srcformat could be "u" or "u1000" depend on which timestamp you have as input. The default value of newformat is "n/j/Y", but you can change it to another one. You should use PHP formatting syntax (see http://php.net/manual/en/function.date.php).
It's recommended to use custom formatters only if predefined formatters can't do what you need. You can use moment plugin for example for advanced formatting of dates. You should don't forget to define unformatter (unformat callback function) always if you define formatter. It's required for editing of the data for example.
As the docs says:
To print out the value of a Moment, use .format(), .toString() or .toISOString().
Your code could be like the following:
customTimestampToDate: function (cellvalue, options, rowdata) {
var parsed_timestamp = parseInt(rowdata.timestamp),
tmp = new Date(parsed_timestamp * 1000).toISOString();
return moment(tmp).format();
}
You can pass a format token to format() or use toISOString() to the the output in ISO 8601 compliant string.
Note that moment accepts also Unix timestamps in seconds, so you can use moment.unix(Number), in your case: return moment.unix(rowdata.timestamp).format();
You do not need to use moment. Just use srcformat u (which is Unix timestamp) and the grid will do the job
formatter : 'date', formatoptions : {
srcformat : 'u',
newformat : 'Y-m-d H:i:s'
}

Jquery grid loading only on 1st click and not reloading on subsequent clicks

I have a JQuery grid which is being populated on a button click based on certain drop-down selections.
The grid is loaded with data on the first button click. But on subsequent clicks the grid doesn't reload based on the changed drop-down selections.
The grid data loaded on the first button click persists until and unless i reload the page.
I have gone through some solutions online,such as
using $("#tblJQGrid").trigger("reloadGrid");for subsequent clicks except for the first click
cache:false property.
But none of them worked.
Here is my jqgrid code for reference
function BindGridData()
{
$("#tblJQGrid").jqGrid(
{url: "#Url.Action("GetGeographyBreakUpData", "GeoMap")"+ "?Parameters=" + Params + "",
datatype: "json",
//data: { "Parameters": Params },
async: false,
mtype: 'GET',
cache: false,
colNames: ['Id','GeoGraphy', 'Completed', 'InProgress'],
colModel: [
{ name: 'Id', index: 'Id', width: 20, stype: 'text',hidden:true },
{ name: 'Geography', index: 'Geography', width: 150 },
{ name: 'Completed', index: 'Completed', width: 150 },
{ name: 'InProgress', index: 'InProgress', width: 150 },
],
pager:'#pager',
jsonReader: {cell:""},
rowNum: 10,
sortorder: "desc",
sortname: 'Id',
viewrecords: true,
caption: "Survey Status:Summary",
scrollOffset: 0});
}
And here is how i am initialising the button click event
$(document).ready(function () {
var firstClick=true;
$("#btnSubmit").click(function(){
btnSubmitClick();
debugger
if(!firstClick)
{
$("#tblJQGrid").trigger("reloadGrid");
}
firstClick=false;
BindGridData();
});
});
Can someone tell me what i am doing wrong?
It seems that there are typical misunderstanding what the code $("#tblJQGrid").jqGrid({...}); do. It's create the grid. It means that in converts the empty table <table id="btnSubmit"></table> in relatively complex structure of divs and tables. See here. After understanding of that it should be clear that the second calling of BindGridData has no sence, becsue table#btnSubmit is not more empty. jqGrid tests it and just do nothing. Thus your current code just trigger reloadGrid with the old URL (see Params).
To fix the problem you have two main options:
usage url: "#Url.Action("GetGeographyBreakUpData", "GeoMap")" and postData with properties defined as functions (see the old answer)
recreate the grid on click instead of triggering reloadGrid. You can call GridUnload method (see the old answer) before call of BindGridData.

jqGrid setting multiselect checkbox id and name to a different value

I've just added free jqGrid to my ASP.NET MVC web application. Whist it is working great for the most part, I would like to set the values for "id" and "name" attributes on the multiselect checkboxes to an Id column value from a different column in the table?
Instead the checkboxes are set as follows:
<input type="checkbox" id="jqg_list2_jqg30" class="cbox" name="jqg_list2_jqg30" aria-checked="false">
How do I replace the jqg_list2_jqg30?
I've been following this demo where the id and name attributes on the checkboxes are set correctly, but I can't see what I am doing differently - http://www.trirand.com/blog/jqgrid/jqgrid.html
This is the logic for jqGrid
$("#list2").jqGrid({
url: 'https://localhost:44319/Package/GetPackages/2',
datatype: "json",
contentType: "application/json; charset-utf-8",
mtype: 'GET',
colNames: ['Id', 'Name', 'Description'],
colModel: [
{ name: 'Id', index: 'Id', width: 55, sorttype: "int" },
{ name: 'Name', index: 'Name', width: 90, searchoptions: { "sopt": ["bw", "eq"] } },
{ name: 'Description', index: 'Description', width: 90 }
],
rowNum: 25,
rowList: [25, 50],
pager: '#pager2',
toppager: true,
sortname: 'Id',
viewrecords: true,
height: "auto",
sortorder: "asc",
multiPageSelection: true,
multiselect: true,
selarrrow: [],
caption: "JSON Example",
loadonce: true,
jsonReader: { repeatitems: false }
});
jQuery("#list2").jqGrid('navGrid', '#pager2',
{ edit: false, add: false, del: false, search: true, view: false, refresh: true });
jQuery("#m1").click(function () {
var s;
s = jQuery("#list2").jqGrid('getGridParam', 'selarrrow');
alert(s);
});
I know I could write some custom logic to do this but I don't think this is required as the example above shows and is something that should work out of the box?
Thanks in advance.
I think there are some common misunderstandings which follow your question. I suppose that you get the ids of selected elements by using jQuery("#list2").jqGrid('getGridParam', 'selarrrow') and then you need to get detailed information about the selected items: "id" and "name".
The first problem is the rowid of your grid. You don't included any test data returned from url: 'https://localhost:44319/Package/GetPackages/2', but I can guess that it's array of items like {"Id": 123, "Name": "Some name", "Description": "Some description"}, where the value of Id come from the database and all the values are unique. The internal organization of jqGrid require that every row of the grid (every <tr> element of the HTML table with the main data) has id attribute with an unique value. One names the value of id attribute as "rowid". By default jqGrid examines the input data for id property and uses the values as rowid. If you use Id instead of id then you can add jsonReader: { id: "Id" } to fix the problem and to inform jqGrid to use it as the input of the rowids. Alternatively you can configure Newtonsoft.Json settings of your ASP.NET MVC application to assign ContractResolver = new CamelCasePropertyNamesContractResolver();. The exact place of the assignment in the code depends on the version of ASP.NET MVC, which you use. The answer shows where you can assign the configuration settings in ASP.NET Core. I personally use such settings because I try to follow the standard name conversions of C# and JavaScript.
One more option which you have is adding key: true to the column Id. It will do almost the same as jsonReader: { id: "Id" }.
If you have the rowid (or the array of rowids by jQuery("#list2").jqGrid('getGridParam', 'selarrrow')) then you can easy get the value from any column or the value of any properties of the corresponding data item. If you use loadonce: true then the items of the data returned from the server will be saved locally in data parameter, like in the case of usage datatype: "local". You can easy get the data item using getLocalRow method. You can change the code
jQuery("#m1").click(function () {
var s;
s = jQuery("#list2").jqGrid('getGridParam', 'selarrrow');
alert(s);
});
to
jQuery("#m1").click(function () {
var $grid = jQuery("#list2"), i, item,
ids = $grid.jqGrid("getGridParam", "selarrrow");
for (i = 0; i < ids.length; i++) {
item = $grid.jqGrid("getLocalRow", ids[i]);
alert("rowid=" + ids[i] +
"\nId=" + item.Id +
"\nName=" + item.Name +
"\nDescription=" + item.Description);
}
});
By the way, I recommend you to remove unneeded index properties from all columns (from colModel) and remove some options of jqGrid with default values (mtype: 'GET', height: "auto", sortorder: "asc", selarrrow: []). I recommend you to remove empty div <div id="pager2"></div> from your HTML page and to use pager: true instead of pager: '#pager2'. Free jqGrid will generate the div for the page in the same way like for the toppager (see toppager: true). It simplifies the code. You can get the id selector of generated pager (if you need) using jQuery("#list2").jqGrid('getGridParam', 'pager'), but one don't need it in the most cases. Instead of using
jQuery("#list2").jqGrid('navGrid', '#pager2', {...});
you can use just
jQuery("#list2").jqGrid('navGrid', {...});
which will add navigator buttons to all pages of the grid.

Javascript library for table rendering

I need to show an array of objects in the table like representation. Table has columns with the properties, and when clicked on the column it should show more data inside the table. It should be sortable.
Is there a JS library that could do this, so I dont have to write this from scratch?
Please see the attached image with the JSON object.
When the user clicks on Ana, additional row is inserted.
I created the demo https://jsfiddle.net/OlegKi/kc2537ty/1/ which demonstrates the usage of free jqGrid with subgrids. It displays the results like
after the user clicks on the "+" icon in the second line.
The corresponding code you can find below
var mydata = [
{ id: 10, name: "John", lname: "Smith", age: 31, loc: { location: "North America", city: "Seattle", country: "US" } },
{ id: 20, name: "Ana", lname: "Maria", age: 43, loc: { location: "Europe", city: "London", country: "UK" } }
];
$("#grid").jqGrid({
data: mydata,
colModel: [
{ name: "name", label: "Name" },
{ name: "lname", label: "Last name" },
{ name: "age", label: "Age", template: "integer", align: "center" }
],
cmTemplate: { align: "center", width: 150 },
sortname: "age",
iconSet: "fontAwesome",
subGrid: true,
subGridRowExpanded: function (subgridDivId, rowid) {
var $subgrid = $("<table id='" + subgridDivId + "_t'></table>"),
subgridData = [$(this).jqGrid("getLocalRow", rowid).loc];
$("#" + subgridDivId).append($subgrid);
$subgrid.jqGrid({
idPrefix: rowid + "_",
data: subgridData,
colModel: [
{ name: "location", label: "Localtion" },
{ name: "city", label: "City" },
{ name: "country", label: "Country" }
],
cmTemplate: { align: "center" },
iconSet: "fontAwesome",
autowidth: true
});
}
});
Small comments to the code. Free jqGrid saves all properties of input data in data parameter. I added id property to every item of input data. It's not mandatory, but it could be helpful if you would add more functionality to the grid. See the introduction for more details.
The columns are sortable based on the type of the data specified by sorttype property of colModel. To simplify usage some standard types of data free jqGrid provides some standard templates which are shortcurts for some set of settings. I used template: "integer" in the demo, but you could replace it to sorttype: "integer" if only sorting by integer functionality is important.
If the user click on "+" icon to expand the subgrid then jqGrid inserts new row and creates the div for the data part of the subgrid. You can replace subGridRowExpanded from above example to the following
subGridRowExpanded: function (subgridDivId) {
$("#" + subgridDivId).html("<em>simple subgrid data</em>");
}
to understand what I mean. The unique id of the div will be the first parameter of the callback. One can create any common HTML content in the subgrid. Thus one can create empty <table>, append it to the subgrid div and
then convert the table to the subgrid.
To access to the item of data, which corresponds to the expanding row one can use $(this).jqGrid("getLocalRow", rowid). The return data is the item of original data. It has loc property which we need. To be able to use the data as input for jqGrid we create array with the element. I's mostly all, what one have to know to understand how the above code works.
You can add call of .jqGrid("filterToolbar") to be able to filter the data or to add pager: true (or toppager: true, or both) to have the pager and to use rowNum: 5 to specify the number of rows in the page. In the way you can load relatively large set of data in the grid and the user can use local paging, sorting and filtering. See the demo which shows the performance of loading, sorting and filtering of the local grid with 4000 rows and another one with 40000 rows. All works pretty quickly if one uses local paging and not displays all the data at once.
I use datatables.net for all my "more complex than lists"-tables. I It's a very well kept library with loads of features and great flexibility.
In the "con" column I would say that it's so complex that it probably has quite a steep learning curve. Although the documentation is great so there is always hope for most problems.

Categories