Using jqGrid's inline-editing with RESTful urls?
Asked Answered
M

3

3

I'm using jqGrid and would like to be able to use its built-in editing functions to make ajax calls to add/edit/delete. Our API uses RESTful verbs and urls like so:

verb     url               action
--------------------------------------------------------------
GET      /api/widgets      get all widgets (to populate grid)
POST     /api/widgets      create new widget
PUT      /api/widgets/1    update widget 1
DELETE   /api/widgets/1    delete widget 1

Is it possible to use the built-in ajax handling with these restrictions, or do I have to use local data (as outlined here & here) and manage the ajax calls myself? If it is possible, what properties do I set on the grid?

(ajaxRowOptions looks promising, but the documentation is a bit thin on how to use it.)

Margarettmargaretta answered 8/9, 2011 at 7:1 Comment(3)
Which editing mode you want to use: inline editing, form editing, "actions" formatter or some mix (like add/delete with form editing and edit with inline editing)?Ulani
Ideally, form editing for creating new widgets, inline editing for editing them, and an action icon for deleting them. :) Second choice would probably be the "select-a-row-then-click-a-button" pattern for all three.Margarettmargaretta
All this is possible, but has just different code. I will try to write the answer in the next time (probably tomorrow). Today I spend too many time for jqGrid and have to go back to my main business. :-)Ulani
U
10

The usage of POST in Add form is by default.

The main idea for customizing jqGrid for RESTfull backend you can find in the old answer.

To use 'DELETE' in form editing if you use the Delete button of the navigator toolbar. Look at here or here. So you should use about the following settings:

$("#grid").jqGrid('navGrid', '#pager',
    {edit: false, add: false, search: false}, {}, {},
    { // Delete parameters
        mtype: "DELETE",
        serializeDelData: function () {
            return ""; // don't send and body for the HTTP DELETE
        },
        onclickSubmit: function (params, postdata) {
            params.url = '/api/widgets/' + encodeURIComponent(postdata);
        }
    });

I use in the example above the encodeURIComponent function to be sure that if the id will have some special characters (spaces for example) if will be encoded so that the server part automatically received the original (decoded) data. Probably you will need to set some additional settings for the $.ajax call used during sending Delete request to the server. You can use for it ajaxDelOptions property.

You can make the above settings as your default settings. You can do this with respect of the following

$.extend($.jgrid.del, {
    mtype: "DELETE",
    serializeDelData: function () {
        return ""; // don't send and body for the HTTP DELETE
    },
    onclickSubmit: function (params, postdata) {
        params.url = '/api/widgets/' + encodeURIComponent(postdata);
    }
});

The method onclickSubmit from the example above can be used for the Edit operations (in case of form editing) to modify the URL dynamically to /api/widgets/1. In many cases the usage of onclickSubmit in the above form is not possible because one need to use different base urls ('/api/widgets') different grids. In the case one can use

$.extend($.jgrid.del, {
    mtype: "DELETE",
    serializeDelData: function () {
        return ""; // don't send and body for the HTTP DELETE
    },
    onclickSubmit: function (params, postdata) {
        params.url += '/' + encodeURIComponent(postdata);
    }
});

Then the usage of navGrid should be with explicit setting of url

$("#grid").jqGrid('navGrid', '#pager',
    {edit: false, add: false, search: false}, {}, {},
    { // Delete parameters
        url: '/api/widgets'
    });

and To use 'PUT' in inline editing you can set the following default jqGrid settings:

$.extend($.jgrid.defaults, {
    ajaxRowOptions: { contentType: "application/json", type: "PUT", async: true },
    serializeRowData: function (data) {
        var propertyName, propertyValue, dataToSend = {};
        for (propertyName in data) {
            if (data.hasOwnProperty(propertyName)) {
                propertyValue = data[propertyName];
                if ($.isFunction(propertyValue)) {
                    dataToSend[propertyName] = propertyValue();
                } else {
                    dataToSend[propertyName] = propertyValue;
                }
            }
        }
        return JSON.stringify(dataToSend);
    }
});

The setting contentType: "application/json" is not required in general, but it could be required for some server technologies. The callback function serializeRowData from the example above sent the data as JSON. It is not required for RESTfull, but it's very common. The function JSON.stringify is native implemented in the most recent web browsers, but to be sure that it work in old browsers to you should include json2.js on your page.

The code of serializeRowData could be very simple like

serializeRowData: function (data) {
    return JSON.stringify(data);
}

but I use above code to be able to use functions inside of the extraparam of the method editRow (see here and the problem description here).

The usage of the RESTfull URL (like /api/widgets/1) in the editRow is very simple:

$(this).editRow(rowid, true, null, null, '/api/widgets/' + encodeURIComponent(rowid));

To use it in case of the form editing you should use

grid.navGrid('#pager', {},
    { mtype: "PUT", url: '/api/widgets' });

and

$.extend($.jgrid.edit, {
    ajaxEditOptions: { contentType: "application/json" }, // can be not required
    onclickSubmit: function (params, postdata) {
        params.url += '/' + encodeURIComponent(postdata.list_id);
    }
});

It is important to remark that to get id from the postdata inside of onclickSubmit and need use postdata.list_id instead of postdata.id, where 'list' is the id of the grid. To be able to use different grid (<table>) ids one can use new non-standard parameter. For example, in the code below I use myGridId:

var myEditUrlBase = '/api/widgets';
grid.navGrid('#pager', {},
    { mtype: "PUT", url: myEditUrlBase, myGridId: 'list' },
    { // Add options
        url: myEditUrlBase },
    { // Delete options
        url: myEditUrlBase });

and the default setting defined as

$.extend($.jgrid.del, {
    mtype: "DELETE",
    serializeDelData: function () {
        return ""; // don't send and body for the HTTP DELETE
    },
    onclickSubmit: function (params, postdata) {
        params.url += '/' + encodeURIComponent(postdata);
    }
});

$.extend($.jgrid.edit, {
    ajaxEditOptions: { contentType: "application/json" }, // can be not required
    onclickSubmit: function (params, postdata) {
        params.url += '/' + encodeURIComponent(postdata[params.myGridId + '_id']);
    }
});

In case of the usage of formatter:'actions' (see here and here) with inline or form editing (or a mix) you can use the same technique as described before, but forward all needed Edit/Delete option using editOptions and delOptions formatoptions.

The last your question was the usage of GET as /api/widgets. The classical RESTfull services will returns just array of all items as the response on /api/widgets. So you should just use loadonce: true and jsonReader which used methods instead of properties (See here and here).

loadonce: true,
jsonReader: {
    repeatitems: false,
    root: function (obj) { return obj; },
    page: function () { return 1; },
    total: function () { return 1; },
    records: function (obj) { return obj.length; }
}

You should in some way include information which item property can be used as the id of grid rows. The id must be unique on the page. It your data has no id I would recommend you to use

id: function () { return $.jgrid.randId(); }

as an additional jsonReader method because per default the current version of jqGrid use sequential integers ("1", "2", "3", ...) as the row ids. In case of having at least two grids on the same page it will follow to the problems.

If the size of the data returned by 'GET' are more as 100 rows I would you recommend better to use server side paging. It means that you will add an additional method in the server part which support server side sorting and paging of data. I recommend you to read the answer where I described why the standard format of the input data are not RESTfull array of items and has page, total and records additionally. The new method will be probably not strange for the classical RESTful design, but the sorting and paging data in native or even SQL code can improve the total performance from the side of enduser dramatically. If the names of the standard jqGrid input parameters (page, rows, sidx and sord) you can use prmNames jqGrid parameter to rename there.

Ulani answered 9/9, 2011 at 17:23 Comment(5)
Thanks for the thorough answer! Where in the documentation can I find what the parameters are in a call like: $("#grid").jqGrid('navGrid', '#pager', {edit: false, add: false, search: false}, {}, {}, { // Delete parameters url: '/api/widgets' });Margarettmargaretta
I assume that's an API call on an already-built grid, but I don't see 'navGrid' in the list of methods on trirand.com/jqgridwiki/doku.php?id=wiki:methodsMargarettmargaretta
@sprugman: I am not sure that I understand correct what you mean. Here in the documentation of navGrid are described prmEdit, prmAdd, prmDel, prmSearch, prmView parameters which are parameters of form editing methods editGridRow, delGridRow, searchGrid and delGridRow. Here are described url property of delGridRow for example.Ulani
Or I guess the "navigator" section is better. trirand.com/jqgridwiki/doku.php?id=wiki:navigatorMargarettmargaretta
Yeah I found it. I mean, the call to 'navGrid' has a bunch of paramaters {edit: false, etc.}, {}, {}. I was trying to find out what those empty braces were for, etc.Margarettmargaretta
S
1

Also check out this excellent general tutorial for how to set-up jqGrid for RESTful URL's here, which also includes how the corresponding Spring MVC server portion would look.

Soyuz answered 29/6, 2012 at 19:37 Comment(0)
A
0

I have managed to achieve it by implementing beforeSubmitCell event handler:

beforeSubmitCell: function(rowId) {

            jQuery("#grid-HumanResource-table").jqGrid(
                'setGridParam',
                {
                    cellurl: s.getBaseModule().config.baseAPIUrl + "humanResource/" + rowId
                }
            );
        },

I am using jqGrid 4.6 version.

Aramanta answered 9/7, 2014 at 16:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.