0

I have the following grid:

 var gridMyTasks = $('#gridMyTasks').jqGrid({
    jsonReader: { root: 'rows', repeatitems: false, id: 'ID' },
    datatype: 'json',
    colNames: ['Task ID', 'Task Name', 'Project Name', 'Task Stage', 'Doc Type', 'Due Date'],
    colModel: [
          { name: 'ShortCode', width: 70, jsonmap: 'ShortCode', sortable: false },
          { name: 'TaskName', width: 200, jsonmap: 'TaskName', formatter: 'fmtTaskName', sortable: false },
          { name: 'ProjName', width: 200, jsonmap: 'ProjName', formatter: 'fmtName', sortable: false },
          { name: 'TaskStage', width: 100, jsonmap: 'TaskStage', sortable: false },
          { name: 'DocType', width: 130, jsonmap: 'DocType', sortable: false },
          { name: 'DueDate', width: 70, jsonmap: 'DueDate', sortable: false }
  ],
    rowNum: 0,
    height: 'auto',
    autowidth: true,
    forceFit: true,
    multiselect: false,
    caption: '',
    altclass: 'zebra',
    altRows: true,
    hoverrows: false,
    gridview: true,
    sortable: false,
    grouping: true,
    groupingView: { groupField: ['ProjName'], groupDataSorted: true }
 });

When my page loads, I call a web service to get the first 15 rows and add it to a grid:

 TPM.GetHomepageData(function (results) // AJAX web service to load data
 {
    gridMyTasks[0].addJSONData({ rows: results.Tasks });
    if (results.Tasks.length >= 15) $('#divTaskFooter').show(); // Enable "Show All" link

    gridMyTasks.show();
 }, null);

This works great. However, for users who have more than 15 rows of data, I have a "Show all..." link. This calls a web service again, but passes in a parameter to indicate I want all rows. This is hooked up as follows:

var loadGrid = function (limit)
{
   TPM.GetMyTasks(limit, curSort, curDir, function (results)
   {
      grid.clearGridData(true); // should clear the existing rows first?
      grid[0].addJSONData({ rows: results }); // *all* rows, not sure new ones
      link.html(expanded ? 'Show less...' : 'Show all...');
   }, null);
};

moreLink.click(function (event) // When user clicks "Show All", load all the data
{
   expanded = !expanded;
   loadGrid(expanded ? null : 15);
   event.preventDefault();
});

In this case, results is an array of 18 rows, and this data is correct. However, what happens is the original 15 rows stick around, the 18 rows are added on, then I have 33 rows in total. In other words, the grid isn't being cleared first.

If I comment out the addJSONData line:

grid.clearGridData(true);
//grid[0].addJSONData({ rows: results });

Then, the grid will clear and I'll see zero rows. So, it's as if the grid is cleared, then the old data is resurrected like a bunch of undead zombie rows, and the duplicate rows are tacked on. I must be doing something wrong.

Update: Adding HTTP Traffic capture for Oleg

Initial Load:

POST http://oursite.com/TPM.svc/GetHomepageData HTTP/1.1
Accept: */*
Accept-Language: en-us
Referer: oursite.com
x-requested-with: XMLHttpRequest
Content-Type: application/json; charset=utf-8
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET CLR 1.1.4322; .NET4.0C; .NET4.0E)
Host: oursite.com
Content-Length: 0
Connection: Keep-Alive
Pragma: no-cache
Cookie: SMSESSION=Unimportant

Response:

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 893
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 25 Jul 2013 16:57:43 GMT

{"d":{ ... A bunch of JSON here ...}}

Show All Click:

POST http://oursite.com/TPM.svc/GetMyTasks HTTP/1.1
Accept: */*
Accept-Language: en-us
Referer: oursite.com
x-requested-with: XMLHttpRequest
Content-Type: application/json; charset=utf-8
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET CLR 1.1.4322; .NET4.0C; .NET4.0E)
Host: oursite.com
Content-Length: 42
Connection: Keep-Alive
Pragma: no-cache
Cookie: SMSESSION=Unimportant

{"limit":null,"orderBy":null,"desc":false}

Response:

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 1762
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
set-cookie: SMSESSION=...
Set-Cookie: SMSESSION=...
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 25 Jul 2013 17:01:55 GMT

{"d":{ ... A bunch of JSON here ...}}
Mike Christensen
  • 88,082
  • 50
  • 208
  • 326

1 Answers1

1

I hope, I understand your problem correctly. The problem seems to me very easy. jqGrid send per default some parameters to the server (page, rows, sidx, sord and so on). Because you implemented server side paging you use already the parameters. You wrote that you load the first 15 rows at the beginning. It means the the request to the server contains page=1 and rows=15. The value 15 is the value of rowNum parameter of jqGrid.

To load all rows you can just change the value of rowNum parameter to some large value like 10000 and reload the grid. The corresponding code can be the following

$("#grid").jqGrid("setGridParam", {rowNum: 10000})
    .trigger("reloadGrid", [{page: 1, current: true}]);

See the answer for parameters of reloadGrid. I use page: 1 above to be sure that the use not chnage the current page in pager before clicking on "Show all..." link.

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • I actually don't implement any paging. The grid only supports two modes: show the first 15 rows, or show all rows. What I'm looking for is a way to clear out the grid *before* displaying all rows. – Mike Christensen Jul 25 '13 at 15:18
  • Could you post the code which clear how you use jqGrid and how you fill it? I suppose that you use jqGrid in a wrong way and you try to solve the problem which should not exist at all. – Oleg Jul 25 '13 at 15:53
  • I've added some more code to hopefully make things more clear. – Mike Christensen Jul 25 '13 at 16:05
  • @MikeChristensen: if you use `datatype: 'json'` you have to specify `url` parameter for request the data. jqGrid makes request in any way. Which parameters supports the web service? you wrote "call a web service to get the first 15 rows", but not post the Ajax call which you use. jqGrid have a lot of options which allows you to make almost any request and process any response. – Oleg Jul 25 '13 at 16:11
  • I did post the Ajax call which I use: `TPM.GetHomepageData(function (results) // AJAX web service to load data` – Mike Christensen Jul 25 '13 at 16:13
  • Should I change the `datatype` to `local` then? Basically, I want to do all the loading myself. – Mike Christensen Jul 25 '13 at 16:14
  • `TPM.GetHomepageData` processes the response from the server only, but not shows `$.ajax` call, it's parameters. Which kind of "AJAX web service" you use? – Oleg Jul 25 '13 at 16:14
  • If you load the data from server with some kind of `$.ajax` request you should do use `datatype: "json"`, but allows jqGrid do the request to the server. Probably `loadonce: true` option will be additionally good in your scenario. In the case you will can at least remove `sortable: false` from the grid and additionally to sorting can allow the user to *filter* the local data. – Oleg Jul 25 '13 at 16:18
  • `TPM.GetHomepageData` is a *proxy* automatically generated by .NET Web Services. This method doesn't have any parameters, it simply takes a callback that is fired on complete. This particular web service method returns data for a few different grids so I don't have to make several separate web service calls when the page loads. – Mike Christensen Jul 25 '13 at 16:19
  • Setting `datatype: 'local'` as well as adding `loadonce: true` and removing `sortable: false` did not fix the problem. Nor did it break anything, same behavior as before. When I click the "Show More" link, I have 18 rows appended to the grid rather than 3. What's the best way to *totally clear the grid* and reload *new* data from scratch? – Mike Christensen Jul 25 '13 at 16:24
  • @MikeChristensen: It's better don't use such proxy. I think you try to take the wrong way of jqGrid usage. If you really have no other interface to the server you should use `datatype: 'local'` with `data: yourData` parameter *to create grid with the data* (or without `data` parameter to create empty grid). To reload the data you can change the value of internal `data` parameter of jqGrid (`grid[0].p.data` is the array) and call `grid.trigger("reloadGrid");`. You can use `sortname, sortorder` to display *sorted* data, user can sort such filled data. – Oleg Jul 25 '13 at 16:32
  • Do you have an example of how to call a .NET Web Service without using a proxy? This is the way I've always done it. In fact, one of the things I really like about .NET Web Services (and WCF) is that it generates these script proxy classes for you. The web service name is `/TPM.svc` – Mike Christensen Jul 25 '13 at 16:34
  • Do you created WCF based web service? Have your method which you call attributes like `[WebGet (UriTemplate = "", ResponseFormat = WebMessageFormat.Json)]`? Look in [the old answer](http://stackoverflow.com/a/3914796/315935) for code example. You can download the Demo Project from [here](http://www.ok-soft-gmbh.com/jqGrid/WfcToJqGrid.zip) – Oleg Jul 25 '13 at 16:37
  • Yea, the C# code is just `[OperationContract] public HomepageData GetHomepageData()` - I'd rather not rework the way my web services work at this time. – Mike Christensen Jul 25 '13 at 16:41
  • Changing `grid.clearGridData(true)` to `grid.clearGridData(true).trigger('reloadGrid');` actually fixed the problem! Thanks so much, Oleg! – Mike Christensen Jul 25 '13 at 16:42
  • @MikeChristensen: One can use more simple interface to the server with less in the referenced answer. The main idea is that you can use pure HTTP protocol to communicate with web service. You should be careful which activation you use for the WFC service. Just examine the content of svc in my demo. – Oleg Jul 25 '13 at 16:43
  • @MikeChristensen: You are welcome! I'm glad to hear that you have a working solution, but I really recommend you to invest the time in changing of your web service interface to support pure HTTP requests. You can consider to use WebApi which is simplification of WCF to support only RESTful HTTP communication and remove all very old and unneeded SOAP support. – Oleg Jul 25 '13 at 16:47
  • Well, behind the scenes, the script proxy *is* using pure HTTP to communicate with the server. It's doing a `POST` to `/tpm.svc` and getting back JSON as a response. You're correct I could probably get jqGrid to mimic the *same* HTTP command and not use the proxy code. Perhaps I will give that a shot when I have some free time. I just wanted to fix this bug because it's annoying a few of our users. – Mike Christensen Jul 25 '13 at 16:48
  • Oleg, I assure you the proxy is using pure HTTP and JSON to communicate with the server. There is no SOAP here. I've looked at the traffic using Fiddler. – Mike Christensen Jul 25 '13 at 16:52
  • @MikeChristensen: If you append your question with the request/response which you see in Fiddler I could write you which options you can use to load the data in jqGrid directly. – Oleg Jul 25 '13 at 16:54
  • Also, you'd want to keep in mind that `GetHomepageData()` returns data for multiple grids, so we want to bind to the `Tasks` property of the response. However, `GetMyTasks()` returns an array of tasks directly. So, that adds a bit of extra complexity. – Mike Christensen Jul 25 '13 at 17:13
  • @MikeChristensen: You can add `url: '/TPM.svc/GetHomepageData', loadonce: true, postData: "", ajaxGridOptions: { contentType: "application/json" }` to the jqGrid definition. If you want to post some parameters to the server you can use `serializeGridData: function (data) {return JSON.stringify(data);}`. To sent `{"limit":null,"orderBy":null,"desc":false}` to the server you can use `serializeGridData: function () {return JSON.stringify({limit: null, orderBy: null, desc: false});}`. – Oleg Jul 25 '13 at 17:21
  • @MikeChristensen: Because the response from the server wrap data in `{d: {}}` you have to change `jsonReader` used in jqGrid. For example you should use `jsonReader: {root: 'd.rows', repeatitems: false, id: 'ID'}`. You can declare any property of `jsonReader` as function like`jsonReader: {root: function (obj) { return obj.d.rows; }, repeatitems: false, id: 'ID'}`. In the way you can get the maximal flexibility. – Oleg Jul 25 '13 at 17:24
  • @MikeChristensen: I recommend you to set `rowNum` to some large value like `rowNum: 10000` if you want to display *all rows* without local paging, but you can also create the pager using `toppager: true` for example. I recommend you to try `grid.jqGrid("filterToolbar", {defaultSearch: "cn", searchOperators: true, stringResult: true});` It will allow users *to work* (filter) with the data in the grid and not just scroll large dataset. – Oleg Jul 25 '13 at 17:30
  • Thanks, I'm actually gonna give this a shot first on a different (simpler) page that also uses the jqGrid.. – Mike Christensen Jul 25 '13 at 17:30