4

I have a jqGrid where I would like to check for cell data and only post the columns of which the data has changed.

Consider this is my colModel

colModel: [{
    name: 'I_PK',
    index: 'u.I_PK',
    align: 'right',
    editable: false,
    sopt: ['cn', 'eq', 'ne', 'lt', 'le', 'gt', 'ge', 'bw', 'ew', 'nc']
}, {
    name: 'W3LabelSelected',
    index: 'u.W3LabelSelected',
    align: 'center',
    width: 170,
    editable: false,
    edittype: 'checkbox',
    formatter: "checkbox",
    search: false,
    formatoptions: {
        disabled: false
    },
    editoptions: {
        value: "1:0"
    }
}, {
    name: 'I_ItemNumID',
    index: 'u.I_ItemNumID',
    align: 'right',
    editable: true,
    editoptions: {
        dataEvents: [{
            type: 'focusin',
            fn: function (e) {
                var elem = e.target;
                setTimeout(function () {
                    elem.select();
                }, 50);
            }
        }]
    }
}, {
    name: 'Quantity',
    index: 'u.Quantity',
    align: 'right',
    editable: true,
    editoptions: {
        dataEvents: [{
            type: 'focusin',
            fn: function (e) {
                var elem = e.target;
                setTimeout(function () {
                    elem.select();
                }, 50);
            }
        }]
    }
}],

In this grid, two of my columns are editable. Now let's say if I make changes in one of the columns of any row in inline editing, then only that cell's value should be posted. Current functionality posts all the cells of that specific row. Is this possible?

I found some questions here and there about this but none seem to be addressing this specific problem.

Basically the idea I can think of is that before saving, if I can somehow compare the original data of all the editable cells of that row to the new value before getting posted, I can eliminate the cells of which the data has not changed and only post the cell which has changed.

Sample grid: http://jsfiddle.net/dipenshah8/HJema/203/

Community
  • 1
  • 1
Dipen Shah
  • 1,911
  • 10
  • 29
  • 45

1 Answers1

4

I would suggest you to use serializeSaveData callback of inline editing or serializeRowData callback of old versions of jqGrid. The callback allows you to customize the data, which will be send to the server. The modified demo http://jsfiddle.net/OlegKi/HJema/206/ uses the following options:

inlineEditing: {
    keys: true,
    serializeSaveData: function (postData) {
        var changedData = {}, prop, p = $(this).jqGrid("getGridParam"),
            idname = p.keyName || p.prmNames.id;

        for (prop in postData) {
            if (postData.hasOwnProperty(prop) &&
                (postData[prop] !== p.savedRow[0][prop] || prop === idname)) {
                changedData[prop] = postData[prop];
            }
        }
        alert(JSON.stringify(changedData));
        return changedData;
    }
}

The code of serializeSaveData callback enumerate all properties which will be send to the server by default and generate new object changedData instead of postData. The code compare the value of all properties of postData with the corresponding values of savedRow[0] parameter, which contains the row before starting editing.

UPDATED: The above code should be a little complexer if the data could have formatter: "date". jqGrid saves formatted value in savedRow[0]. One can modify the above code to the following:

inlineEditing: {
    keys: true,
    serializeSaveData: function (postData) {
        var changedData = {}, prop, p = $(this).jqGrid("getGridParam"),
            idname = p.keyName || p.prmNames.id,
            oldValue, cm, formatoptions;

        for (prop in postData) {
            oldValue = p.savedRow[0][prop];
            if (p.iColByName[prop] != null) {
                cm = p.colModel[p.iColByName[prop]];
                formatoptions = cm.formatoptions || {};
                if (cm.formatter === "date" && formatoptions.sendFormatted !== true) {
                    oldValue = $.unformat.date.call(this, oldValue, cm);
                }
            }
            if (postData.hasOwnProperty(prop) &&
                    (postData[prop] !== oldValue || prop === idname)) {
                changedData[prop] = postData[prop];
            }
        }
        alert(JSON.stringify(changedData));
        return changedData;
    }
}

See the modified demo http://jsfiddle.net/OlegKi/HJema/209/

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Hi @Oleg thank you this works great. One question I have on this is that in one of my other grids I use a datepicker to edit the datetime values of that column. When I try to edit that field without making changes and if I try to save it, it still gets posted. This happens only in the case of datetime field. I put a demo [here](http://jsfiddle.net/dipenshah8/HJema/207/) to clarify my problem. Can you please take a look when you are free? – Dipen Shah Nov 05 '15 at 13:18
  • @DipenShah: You are welcome! I fixed the code. See **UPDATED** part of the answer and the modified demo. – Oleg Nov 05 '15 at 13:52
  • Thank you. This fixed my problem. You're amazing. – Dipen Shah Nov 05 '15 at 13:56
  • 1
    @Oleg If the data is not changed during inline edit, how to disable server callback and simply cancel inline editing mode if row is saved? – Andrus Nov 08 '15 at 20:49
  • @Andrus: The code from the demo calls `saveRow` **explicitly** inside of `onSelectRow`. I shown in my answer the code which analyse `p.savedRow[0]`. One can use the same code inside of `onSelectRow` to detect whether the data are changed and to call `saveRow` or `restoreRow`. The main problem is **reading the data from editing row**. I think the best way would be to introduce new option of `saveRow` which skip saving on no changes. Another extension would be callback/event which allows to stop saving before Ajax. One more idea to extend `getRowData` to work with editing row. I will think about – Oleg Nov 08 '15 at 21:07
  • Hi @Oleg sorry to bother with this old question but this does not seem to be working with checkboxes. Here's a [demo](http://jsfiddle.net/HJema/339/) If you click on the checkboxes, you will see the post data only contains the id and oper but it should include the checkbox too. Is there any way I can solve this? Thank you for your time. – Dipen Shah Jun 02 '16 at 13:25
  • @DipenShah: Hi! I'm not sure, which behavior exactly you try to implement. The code from the `beforeSelectRow` contains `if (savedRow[0].id === rowid) {`. In general I'd recommend you to reduce the usage of options in direct calls of inline editing methods (`editRow`, `saveRow`, ...) and to move it to `inlineEditing` whenever it's possible. – Oleg Jun 02 '16 at 13:55
  • @Oleg If you try to click on the checkboxes, since they have `formatoptions: { disabled: false }` in the code it should allow me to edit it right away. Please see the updated [demo](http://jsfiddle.net/HJema/341/) I don't have `beforeSelectRow` in the code now and still if I try to edit it , it does not send the checkbox to be saved. I hope it is clear to you now. – Dipen Shah Jun 02 '16 at 13:59
  • @DipenShah: I repeat that I just not full understand *what you want to implement*. If you want that the value from `W3LabelSelected` be sent to the server then you can set `editable: "hidden"` property in the column (instead of `editable: false`, which you use now). By the way calling of `saveRow` inside of `beforeSelectRow` have advantage: one can *allow selection* of another row only if saving was successful. See [the answer](http://stackoverflow.com/a/34976517/315935). It's important in case of client side validation (see `editrules`) or in case of server side saving error. – Oleg Jun 02 '16 at 14:50
  • @Oleg Okay let me reframe it for you. What I want is when a user click on checkbox, the checkbox should be the only thing posted on the server. By default, jqGrid posts everything. With this answer it restricts to only data that has been changed. However when I click on the checkbox nothing is posted. I want it to be able to post the checkbox value (and only the checkbox value) as soon as the user clicks on it. Does that help? – Dipen Shah Jun 02 '16 at 15:19
  • @Oleg As per your suggestion I also tried editable: "hidden" but it does not help. – Dipen Shah Jun 02 '16 at 15:23
  • 1
    @DipenShah: It seems to me that you made the problem in multiple times complex because of the usage of `formatoptions: { disabled: false }` and wanting to **edit** the column using non-editable (`editable: false` or `editable: "hidden"`). I described an implementation with `formatoptions: { disabled: false}` in [the answer](http://stackoverflow.com/a/24239416/315935), but it use `datatype: "local"`. Why you not just remove `formatoptions: { disabled: false}`, set `editable: true`? What you probably want is inverting of the checkbox in the case that the user clicked on the checkbox. Is't so?... – Oleg Jun 02 '16 at 16:36
  • 1
    @DipenShah: ... You start `editRow` inside of `onSelectRow` and you have `e` as the last parameter here. You can test `e.target`, whether `$(e.target).is("i.fa-square-o")` or `$(e.target).is("i.fa-check-square-o")` then the user clicked on the checkbox. You can test for `$(e.target).closest("tr.jqgrow>td")[0].cellIndex === p.iColByName.W3LabelSelected` to be sure that the user clicked on the "checkbox". You can use `oneditfunc` callback of `editRow` in the special case to invert (simulate `click`) on the checkbox (`$("#" + rowid + "_W3LabelSelected").click()`). It should work I think. – Oleg Jun 02 '16 at 16:47
  • @Oleg Thank you I am going to try this and get back to you. – Dipen Shah Jun 02 '16 at 17:04
  • @Oleg Thank you once again Oleg. I ended up doing something similar and it seems to be working fine now. – Dipen Shah Jun 02 '16 at 18:13