1

I have one doubt with ajax implementation. I could find that "url" parameter need to be defined as "service_name1.azure-mobile.net/tables/" to fetch data to populate grid. But I need to add request header "X-ZUMO-APPLICATION" to define application key. To accomplish this, I think I have to make a httprequest with proper headers in a function and need to set reference of that function in some parameter of jqGrid to load data. Can you point out how is it possible to achieve?

Page on which jqGrid is used, starts with "https://service_name2.azure-mobile.net"

Here service_name1 is azure mobile service name and service_name2 is azure web service name and I have enabled CORS (cross object resource sharing) for service_name2 on mobile service service_name1.

Please let me know if any additional information is required

Updated code to make it work with Ajax call :

        jQuery("#list4").jqGrid({
        datatype: "json",
        url : 'https://mohit.azure-mobile.net/tables/Schedules',
        height: "auto",
        colNames: ['RowNo', 'RouteId', 'Area],
        colModel: [
                  { name: 'id', index: 'id', width: 50, sortable: false },
                  { name: 'RouteId', index: 'RouteId', width: 50, sortable: false, editable: true, editrules: { required: true} },
                  { name: 'Area', index: 'Area', width: 130, sortable: false, editable: true, editrules: { required: true} },
              ],
        rowList: [10, 20, 30],
        loadBeforeSend: function(jqXHR) {
                                            jqXHR.setRequestHeader('X-ZUMO-APPLICATION', 'mykey');
                                        },
        ajaxGridOptions: { contentType: "application/json" },
        postData: "",
        serializeGridData: function (data) {return JSON.stringify(data);},
        pager: '#pager1',
        viewrecords: true,
        caption: "Schedule Data",
        //loadonce: true,
        gridview: true
    });

Weird thing is, I am not able to capture this request using fiddler so I am capturing request using IE developer toolbar (using F12). I tried composing a request using fiddler, used GET with url'https://mohit.azure.net/tables/Schedules' and set header parameter as X-ZUMO-APPLICATION : appKey. I got proper response (expected JSON formatted table data) with this request. So I am feeling appended parameters are issue.

Update code part 2

    jQuery("#list4").jqGrid({
        datatype: "json",
        url : 'https://mohit.azure-mobile.net/tables/Schedules',
        height: "auto",
        colNames: ['RowNo', 'RouteId', 'Area'],
        colModel: [
                  { name: 'id', index: 'id', width: 50, sortable: false },
                  { name: 'RouteId', index: 'RouteId', width: 50, sortable: false, editable: true, editrules: { required: true} },
                  { name: 'Area', index: 'Area', width: 130, sortable: false, editable: true, editrules: { required: true} }
              ],
        rowList: [10, 20, 30],
        loadBeforeSend: function(jqXHR) {
                                            jqXHR.setRequestHeader('X-ZUMO-APPLICATION', 'myKey');
                                        },
        loadComplete: function () {
                                        //alert("OK");
                                  },
        loadError: function (jqXHR, textStatus, errorThrown) {
                                                                    alert('HTTP status code: ' + jqXHR.status + '\n' +
                                                                    'textStatus: ' + textStatus + '\n' +
                                                                    'errorThrown: ' + errorThrown);
                                                                     alert('HTTP message body (jqXHR.responseText): ' + '\n' + jqXHR.responseText);
                                                             },
        ajaxGridOptions: { contentType: "application/json", cache: true },
        postData: "",
        pager: '#pager1',
        viewrecords: true,
        caption: "Schedule Data",
        loadonce: true,
        gridview: true
    });

   var inlineparams = {
        restoreAfterSelect: false,
        add: true,
        edit: true,
        save: true,
        cancel: true,
        del: true
    };

    jQuery("#list4").jqGrid('navGrid', "#pager1", { edit: false, save: false, add: false, cancel: false, del: false });
    jQuery("#list4").jqGrid('inlineNav', "#pager1", inlineparams);       
}

Solution for loading data in grid with jqGrid version 4.4.5 using Ajax way

                       jQuery("#list4").jqGrid({
        datatype: "json",
        url : 'https://mohit.azure-mobile.net/tables/Schedules',
        height: "auto",
        colNames: ['RowNo', 'RouteId', 'Area'],
        colModel: [
                  { name: 'id', index: 'id', width: 50, sortable: false },
                  { name: 'RouteId', index: 'RouteId', width: 50, sortable: false, editable: true, editrules: { required: true} },
                  { name: 'Area', index: 'Area', width: 130, sortable: false, editable: true, editrules: { required: true} },
              ],
        rowList: [10, 20, 30],
        loadBeforeSend: function(jqXHR) {
                                            jqXHR.setRequestHeader('X-ZUMO-APPLICATION', 'myKey');
                                        },
        loadComplete: function () {
                                        //alert("OK");
                                  },
        loadError: function (jqXHR, textStatus, errorThrown) {
                                                                    alert('HTTP status code: ' + jqXHR.status + '\n' +
                                                                    'textStatus: ' + textStatus + '\n' +
                                                                    'errorThrown: ' + errorThrown);
                                                                     alert('HTTP message body (jqXHR.responseText): ' + '\n' + jqXHR.responseText);
                                                             },
        ajaxGridOptions: { contentType: "application/json", cache: true },
        postData: "",
        pager: '#pager1',
        viewrecords: true,
        caption: "Schedule Data",
        loadonce: true,
        jsonReader: {repeatitems: false},
        gridview: true
    });
Mohit
  • 39
  • 1
  • 2
  • 10

1 Answers1

0

First of all I think the the title of the question "how to call custom function to load data instead of using “url” parameter" is incorrect. I think that what you describe could be implemented per standard Ajax call, but using JSONP type instead of JSON.

To set custom HTTP/HTTPS headers you can use setRequestHeader method of inside of loadBeforeSend callback of jqGrid. See the answer. In case of editing of grid inside of beforeSend callback of jQuery.ajax call which do jqGrid. You can use ajaxEditOptions or ajaxRowOptions option of jqGrid (depend on editing mode which you use) to set the beforeSend callback of jQuery.ajax call. Alternatively you can use headers option of jQuery.ajax (one can set it in jqGrid using ajaxGridOptions, ajaxEditOptions or ajaxRowOptions).

I think that if you configured correctly Cross-Origin Resource Sharing (CORS) (see here) you could use JSONP in jqGrid to load the data. See examples here, here and here.

UPDATED: I can't test the code, but I think you should change some options/callbacks which you use:

  1. remove serializeGridData is you use postData: ""
  2. change datatype: "json" to datatype: "jsonp"
  3. change ajaxGridOptions: { contentType: "application/json" } to ajaxGridOptions: { contentType: "application/json", cache: true }

If it will not help I would recommend you to use tools like Fiddler to trace HTTPS traffic. You will need additionally activate tracing of HTTPS inside the tool (see the documentation).

UPDATED 2: It seems that in case of usage Windows Azure Mobile Services you can use datatype: "json" and url: 'https://<service_name1>.azure-mobile.net/tables/<TableName>'. To get the data it's important only to use

ajaxGridOptions: { contentType: "application/json" },
postData: "",
jsonReader: {
    repeatitems: false,
    root: function (obj) {
        return obj;
    }
}

To be able to modify the data with respect of inline editing you should produce HTTP request having

PATCH https://mstrans.azure-mobile.net/tables/<TableName>/<TableItemId> HTTP/1.1
Content-Type: application/json

in the HTTP header and JSON data with the modified row, but without unneeded oper parameter. To do this you can

editurl: "https://mohit.azure-mobile.net/tables/Schedules",
ajaxRowOptions: { contentType: "application/json" },
serializeRowData: function (postData) {
    if (postData != null && postData.oper) {
        delete postData.oper;
    }
    return JSON.stringify(postData);
}

The code above will do almost all what one need with the exception that it will be used as URL "https://mohit.azure-mobile.net/tables/" instead of "https://mohit.azure-mobile.net/tables//".

To make the last step one can modify url inside of for example oneditfunc callback of inlineparams or better jqGridInlineEditRow event:

var inlineparams = {
    editParams: { mtype: "PATCH", keys: true},
    addParams: {
        addRowParams: { mtype: "POST", keys: true }
    }
};

jQuery("#list4").bind("jqGridInlineEditRow", function (e, rowid, options) {
    if (options.mtype === "PATCH") {
        options.url = "https://mohit.azure-mobile.net/tables/Schedules/" +
            encodeURIComponent(rowid);
    }
});
Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • I think by putting up details about different domains, I made my simple question complex. CORS will work as I have already tested it and I think it will work simply with JSON. IF it does not work with JSON, then I will try with JSONP and update you. MY main motive with this question was to understand if it is possible to call a custom function to load/show data in grid instead of using "url" parameter. I have already defined functions which query/update/insert data in my mobile service database and they have all success and error callbacks defined. I am looking to hook these functions. – Mohit Apr 08 '13 at 04:28
  • @Mohit: One can use `datatype` as function to make custom load of data. Editing function don't provide any *asynchronous* way to save the data. I think that you still misunderstood *the complexity* of different implementation ways. Ajax way is *standard way* for jqGrid. So it's the best. The are a lot of small things which jqGrid implement automatically and which you can forget if you use follow the standard way. If you'll try *your own way* you will have many other problems in implementation details. So I recommend you to use JSONP as standard Ajax way. – Oleg Apr 08 '13 at 05:51
  • Following your suggestion of Ajax implementation, I have changed design on my app and now using "url" parameter to fetch data for grid. I have defined "url" parameter as url : "https://myDom.azure-mobile.net/tables/Schedules" but when I capture request, request is going as https://myDom.azure-mobile.net/tables/Schedules?_search=false&nd=1365529697418&rows=20&page=1&sidx=&sord=asc. I am getting bad request result and I think this is all dues to additional parameters which got append automatically. How can I escape from these parameters? – Mohit Apr 09 '13 at 17:57
  • @Mohit: What error exactly you have? Do you used Fiddler/Firebug to see the HTTP traffic with the server? What error you could see. In any way you should append the text of your question with JavaScrupt code which you try now. I don't think that parameters appended to the URL make the problems. – Oleg Apr 09 '13 at 18:28
  • Updated as you have asked. In request headers, I can see "Key Value Request OPTIONS /tables/Schedules?_search=false&nd=1365533446530&rows=20&page=1&sidx=&sord=asc HTTP/1.1" Response headers "Key Value Response HTTP/1.1 400 Bad Request" – Mohit Apr 09 '13 at 18:54
  • @Mohit: To sent no typical jqGrid parameters you can either add `postData: ""` or use callback `serializeGridData: function () {return "";}`. Probably you need add `ajaxGridOptions: { contentType: "application/json" }` option and the callback `serializeGridData: function (data) {return JSON.stringify(data);}`. You don't added `&jsonCallback=?` part to the URL, so you should probably use `datatype: 'jsonp'` instead of `datatype: 'json'` if your page is not on the URL starting with `https://mohit.azure.net/`. You should either make some tests or read about access Azure Mobile Service per JSONP. – Oleg Apr 09 '13 at 21:06
  • postData : "" did the trick. Earlier (without postData), I can see one web call(OPTIONS method) to azure service. After using postData " "", I can see two calls to azure service (OPTIONS method and GET method). In GET request's response body, I can see desired json formatted data, but it is not shown in Grid. As suggested above, tried "serializeGridData: function (data) {return JSON.stringify(data);}," but no luck. So now problem is how to show data in jqGrid? – Mohit Apr 10 '13 at 04:52
  • @Mohit: It's good news! You should post the JSON data returned from the server to see which `jsonReader` you should use. You can use Fiddler Firebug or Developer Tools of Internet Explorer (press F12 to start) or Google Chrome to trace the HTTP traffic. – Oleg Apr 10 '13 at 06:20
  • @Mohit: I recommend you additionally include always `loadError` callback in the grid if you load data from the server. See for example [the answer](http://stackoverflow.com/a/6969114/315935) for details. By the way it you use `postData: ""` you don't need `serializeGridData: function (data) {return JSON.stringify(data);}`. – Oleg Apr 10 '13 at 08:21
  • @Mohit: See **UPDATED** part of my answer. – Oleg Apr 10 '13 at 08:37
  • JSON response is as below : [{"id":1,"RouteId":"1","Area":"ECIL X-ROADS"},{"id":2,"RouteId":"1","Area":"KAPRA"}].Read about jsonReader in jqGrid documentation but could not figure out for this data properly. – Mohit Apr 10 '13 at 19:57
  • @Mohit: The new version of [jqGrid 4.4.5](http://www.trirand.com/blog/?page_id=6) contains the feature which I [suggested](http://www.trirand.com/blog/?page_id=393/feature-request/autodetection-of-input-json-format/) and [implemented](https://github.com/tonytomov/jqGrid/pull/439). So if you just update jqGrid to the version you should don't need specify any `jsonReader` to read the data. Alternatively you need use `jsonReader: {repeatitems: false, root: function (obj) {return obj;}}`. I recommend you still to use `loadonce: true`. – Oleg Apr 10 '13 at 20:16
  • jqGrid 4.4.5 solved jsonReader problem. Having & not having of "loadonce : true", both causing issue for me. If use "loadonce : true", then in pager by default 20 records are selected. In network call I can see 50 records are fetched from server. Grid keeps showing "loading" image and when I click on pager, it does not go to next page. When do not use "loadonce : ture", pager is not enabled, so can't go to next page. But I can still select no of records to show on a page and when I change it from 20 to 30, it shows proper 30 record.From pager, I mean navigation buttons for page. Code updated. – Mohit Apr 11 '13 at 04:06
  • @Mohit: try to replace `if(dReader.cell) {cur = $.jgrid.getAccessor(cur,dReader.cell);}` line in `jquery.jqGrid.src.js` to `if(dReader.cell) {cur = $.jgrid.getAccessor(cur,dReader.cell) || cur;}`. Alternatively you can add `jsonReader: {repeatitems: false}`. You should use `loadonce: true` to have local paging of data. – Oleg Apr 11 '13 at 06:16
  • jsonReader: {repeatitems: false} solved problem. Now for update row operations, I need to make a call to separate url https://.azure-mobile.net/tables// and send JSOn row data which I want to update. How can I specify a separate url and embed JSON row data specifically for edit row operation? Please let me know if I need to post a new question for this. – Mohit Apr 11 '13 at 07:33
  • Not sure, what caused confusion in last comment but to make things more clear, I am accessing same domain web end points to load data in grid and to update data from grid. For loading data my url is "https://mohit.azure-mobile.net/tables/Schedules" and for updating data my url is "https://mohit.azure-mobile.net/tables/Schedules/". So not sure where does "Same origin policy" come in picture and how does my requirement dependent on browser. I am looking for cross browser application. Sorry If I am talking too naïve. – Mohit Apr 11 '13 at 09:27
  • updated title of question and Solution part also as mentioned. Thanks for guiding here. Once you answer on my last comment about doubt of "Same origin policy", probably I would be able to understand root problem and will start a new question with proper title. Thanks again – Mohit Apr 11 '13 at 09:28
  • @Mohit: You are welcome! I am wonder that you use `datatype: "json"` in the final solution. Probably you placed HTML page which execute JavaScript creating jqGrid *on the same web site* (on `https://mohit.azure-mobile.net/`). In the case you could remove the prefix `https://mohit.azure-mobile.net` from the url. In your question you described that you need access from `service_name1` to `service_name2`. Is it so in your current solution? – Oleg Apr 11 '13 at 09:41
  • Oleg : I would say we can ignore this service_name1 & service_name2 part because if we properly define CORS at azure sit, it takes care of same. SO Even though my originated web page is in domain service_name1, it is able to fetch data from mobile service which is in domain service_name2. Due to this additional support of CORS provided by azure, we do not need to worry about Same origin policy. Now problem where I am stuck is, parameter to define url for update. – Mohit Apr 11 '13 at 10:06
  • @Mohit: You misunderstand the problem. If you try to make Ajax call from one place to *another* URL which don't corresponds "Same origin policy" rules the call will be **blocked locally**. So it's not important which settings you have on the server **the web browser will don't permit the call**. You will see **no HTTP traffic**. So I can repeat my question: which URL have the HTML page in your working solution which make Ajax call to `https://mohit.azure-mobile.net/tables/Schedules`? Has the page URL which starts with `'https://mohit.azure-mobile.net/'`? – Oleg Apr 11 '13 at 10:20
  • @Mohit: Another common question: Do you order your azure-mobile.net site per your MSDN subscription? I have MSDN premium subscription too and so I could order for free Azures Mobile Services, but I just don't spend my time in ordering of it. Is it complex? Or you ordered Azures Mobile Services not yourself? I think that having access to working site one could answer on all questions much more quickly. – Oleg Apr 11 '13 at 10:27
  • so my page is in different domain i.e. "http://mohit1.azurewebsites.net/" and to load data in grid, defined url is "https://mohit.azure-mobile.net/tables/Schedules". This all is working fine and data is properly loaded in grid. I can see one surprising thing in request captured in developer toolbar that Origin is defined as "http://mohit1.azurewebsites.net/" but host header is changed to "mohit.azure-mobile.net". Due to this host header change, it is working properly. But not sure, how this header is getting updated automatically at client side. – Mohit Apr 11 '13 at 10:46
  • so ordering is quite simple. Not complex. I would say you should try it sometime. – Mohit Apr 11 '13 at 10:49
  • @Mohit: In any way if you use `datatype: "json"` you *should* use `url` without any `https://mohit.azure-mobile.net/` prefix. There are some exception (like if the url contains something like `&jsonCallback=?` and will be interpreted as JSONP). In any way you can see that your current solution works with `url: '/tables/Schedules'` really. – Oleg Apr 11 '13 at 10:50
  • I tried with url : '/tables/Schedules' and it does not work with same (error 404 : resource not found). – Mohit Apr 11 '13 at 11:17
  • one question, does it cause any issue for inline data editing and saving requirement of mine with different url in same azure mobile domain? – Mohit Apr 11 '13 at 11:22
  • @Mohit: It's difficult for me to help you here, because I don't see exactly what you do during every experiment and I don't see full HTTP traffic during the experiment. – Oleg Apr 11 '13 at 11:25
  • @Mohit: Sorry, but all questions about inline data editing and saving is separate thema which has many aspects. For example you can read [here](http://www.w3.org/Security/wiki/Same_Origin_Policy): "the same-origin policy allows inter-origin HTTP requests with GET and POST methods but denies inter-origin PUT and DELETE requests". It's important of course the configuration of Azures Mobile Services. I find personally that you should better provide your own WebAPI/WCF etc service and make all request to it. The wed service could make all requests to database and you would have no problem at all. – Oleg Apr 11 '13 at 11:37
  • well I can share you my app url through other medium (like email), if you allow so. But if we ignore this cross domain part, I would like to come back to my original question : "Now for update row operations, I need to make a call to separate url https://.azure-mobile.net/tables// and send JSOn row data which I want to update. How can I specify a separate url (mohit.azure-mobile.net/tables/Schedules/) and embed JSON row data specifically for edit row operation?" – Mohit Apr 11 '13 at 11:40
  • @Mohit: you can send me Email to oleg.kiriljuk@ok-soft-gmbh.com. What I mean is that HTML page with jqGrid would access only web service from *the same web site*. The web service could make any other HTTP/HTTPS requests to get/modify/delete the data. In the case you would have no problem with "separate url". – Oleg Apr 11 '13 at 11:47
  • oleg : I have mailed you details from mohitagr@outlook.com. By the time, can you point me how can I define url for updating data? I will give that a try and I hope it will work. – Mohit Apr 11 '13 at 12:17
  • @Mohit: Could you replace usage of `jquery.jqGrid.min.js` to `jquery.jqGrid.src.js`? – Oleg Apr 11 '13 at 12:23
  • @Mohit: I made some tests and wrote **UPDATED 2** part of my answer. I hope that you will be able to Add/Adit data after small modifications of your code. – Oleg Apr 11 '13 at 14:35