1

In my jqGrid, I have a checkbox which is also available for editing, i.e. a user can click on the checkbox and that checkbox's value will be updated in the database. That is working fine. However when I click on the checkbox and if I try clicking on it again, nothing happens. The row does not get saved. Theoretically the unchecked value of the checkbox should be saved. But this does not happen.

I have tried referring to this answer of Oleg but it does not help.

The weird problem is if I select another row and then try to unselect the checkbox again, I do see a save request going.

I am guessing this is because I am trying to edit a row which is currently selected. But I am not sure what I am doing wrong here.

This is what I am doing in my beforeSelectRow

beforeSelectRow: function (rowid, e) {
    var $target = $(e.target),
        $td = $target.closest("td"),
        iCol = $.jgrid.getCellIndex($td[0]),
        colModel = $(this).jqGrid("getGridParam", "colModel");
    if (iCol >= 0 && $target.is(":checkbox")) {
        if (colModel[iCol].name == "W3LabelSelected") {
            console.log(colModel[iCol].name);
            $(this).setSelection(rowid, true);
            $(this).jqGrid('resetSelection');
            $(this).jqGrid('saveRow', rowid, {
                succesfunc: function (response) {
                    $grid.trigger('reloadGrid');
                    return true;
                }
            });
        }
    }
    return true;
},

Configuration:

jqGrid version: Latest free jqGrid

Data Type: Json being saved to server

Minimal Grid Code: jsFiddle

EDIT: After Oleg's answer this is what I have so far:

beforeSelectRow: function (rowid, e) {
    var $self = $(this),
        iCol = $.jgrid.getCellIndex($(e.target).closest("td")[0]),
        cm = $self.jqGrid("getGridParam", "colModel");
    if (cm[iCol].name === "W3LabelSelected") {
        //console.log($(e.target).is(":checked"));
        $(this).jqGrid('saveRow', rowid, {
            succesfunc: function (response) {
                $grid.trigger('reloadGrid');
                return true;
            }
        });
    }

    return true; // allow selection
}

This is close to what I want. However if I select on the checkbox the first time and the second time, the console.log does get called everytime. However the saveRow gets called only when I check the checkbox and then click on it again to uncheck it the first time and never after that. By default the checkbox can be checked or unchecked based on data sent from server.

enter image description here

In the image, the request is sent after selecting the checkbox two times instead of being sent everytime.

UPDATE: As per @Oleg's suggestion, I have implemented cellattr and called a function inside. In the function I simply pass the rowid and update the checkbox of that rowid on the server.

Here's the code I used:

{
    name: 'W3LabelSelected',
    index: 'u.W3LabelSelected',
    align: 'center',
    width: '170',
    editable: false,
    edittype: 'checkbox',
    formatter: "checkbox",
    search: false,
    formatoptions: {
        disabled: false
    },
    editoptions: {
        value: "1:0"
    },
    cellattr: function (rowId, tv, rawObject, cm, rdata) {
        return ' onClick="selectThis(' + rowId + ')"';
    }
},

and my selectThis function:

function selectThis(rowid) {
    $.ajax({
        type: 'POST',
        url: myurl,
        data: {
            'id': rowid
        },
        success: function (data) {
            if (data.success == 'success') {
                $("#list").setGridParam({
                    datatype: 'json',
                    page: 1
                }).trigger('reloadGrid');
            } else {
                $("<div title='Error' class = 'ui-state-error ui-corner-all'>" + data.success + "</div>").dialog({});
            }
        }
    });
}

FIDDLE

Community
  • 1
  • 1
Dipen Shah
  • 1,911
  • 10
  • 29
  • 45
  • The jsFiddle demo don't full corresponds the description from your question. Moreover you use `formatoptions: { disabled: false }` which is good typically if you don't combine it with inline editing. Moreover the demo use `onSelectRow` instead of `beforeSelectRow`. What is your real scenario? Do you use inline editing or not? Do you have more editable columns as the column with the checkbox? What behavior you need if the user click on the row, click on checkbox of the row which is not yet in editing state, click on checkbox of the row which is in editing state? – Oleg Oct 03 '15 at 07:21
  • It could be differences too if you use `iconSet: "fontAwesome"` bacause it don't use `` during formatting. You can use `iconSet: "fontAwesome"` option of the grid, add `template: "booleanCheckboxFa"`. You will see the grid which have checked or unckecked **icon** in the column, but no `` elements. – Oleg Oct 03 '15 at 07:27
  • It you prefer `formatter: "checkbox"` then I suppose that you should you need remove `formatoptions: { disabled: false }` option and use `"change"` event for `W3LabelSelected` column. It allows you to call `saveRow` in the `"change"` handler of the checkbox. To get rowid of inside of `"change"` handler you can use `$(this).closest("tr.jqgrow").attr("id")`. – Oleg Oct 03 '15 at 07:30
  • Hi @Oleg sorry for the delayed reply, I was away for the weekend. I use inline editing in my real scenario. Typically `onSelectRow` is used for inline editing which I am aware of. However I need something like when the user clicks on the checkbox a request should be sent **everytime** to the server to save that row. Which is why I am also using `beforeSelectRow` so that I can save the checkbox state as soon as the user click on it. (This is to reduce the number of clicks a user has to make) – Dipen Shah Oct 05 '15 at 12:20
  • I inspected my source code and the checkboxes are rendering as `` so I am not sure if `iconSet: "fontAwesome"` is making any change to my checkbox's html I tried using the `change` event but I can't seem to get it to work. Could you give an example how can I use the checkbox's change event to save the row? Sorry for the trouble but I can't figure it out. – Dipen Shah Oct 05 '15 at 12:24
  • The most important to know whether you edit **only one column** `"W3LabelSelected"` or some other column too. It's unclear why you use `formatoptions: { disabled: false }` option in the demo. One can't combine it which inline editing because during initializing of inline editing the checkbox will be *recreated*. I still don't full understand your requirements. Do you want that inline editing will be started on click on the row? Do you want that the editing data will be saved and the editing will be stopped on checking/unchecking of the row? (the method `saveRow` save the data and stop editing) – Oleg Oct 05 '15 at 12:54
  • sorry I edit multiple columns. My understanding was that if I use `formatoptions: { disabled: false }` , a user can directly click on the checkbox and save the state of the checkbox (with the request being sent to the server) But if I can't do multiple columns inline editing with the checkbox then I will have to use the checkbox's `change` event. If the user clicks on `W3LabelSelected` column the state of that checkbox should be saved to the server **everytime**. I want the other inline editing of other columns as it is right now. no change in that. – Dipen Shah Oct 05 '15 at 12:59

1 Answers1

2

I think there is a misunderstanding in the usage of formatter: "checkbox", formatoptions: { disabled: false }. If you creates non-disabled checkboxs in the column of the grid in the way then the user just see the checkbox, which can be clicked and which state can be changed. On the other side nothing happens if the user changes the state of the checkbox. On the contrary the initial state of the checkbox corresponds to input data of the grid, but the changed checkbox makes illusion that the state is changed, but nothing will be done automatically. Even if you use datatype: "local" nothing is happens and even local data will be changed on click. If you do need to save the changes based on the changing the state of the checkbox then you have to implement additional code. The answer demonstrates a possible implementation. You can change the state of some checkboxes on the corresponding demo, then change the page and go back to the first page. You will see that the state of the checkbox corresponds the lates changes.

Now let us we try to start inline editing (start editRow) on select the row of the grid. First of all inline editing get the values from the rows (editable columns) using unformatter, saves the old values in internal savedRow parameter and then it creates new editing controls inside of editable cells on the place of old content. Everything is relatively easy in case of using standard disabled checkbox of formatter: "checkbox". jqGrid just creates enabled checkboxs on the place of disabled checkboxs. The user can change the state of the checkboxs or the content of any other editable columns and saves the changes by usage of Enter for example. After that the selected row will be saved and will be not more editable. You can monitor the changes of the state of the checkbox additionally (by usage editoptions.dataEvents with "change" event for example) and call saveRow on changing the state. It's important that the row will be not editable after the saving. If you do need to hold the row editable you will have to call editRow once more after successful saving of the row. You can call editRow inside of aftersavefunc callback of saveRow, but I recommend you to wrap the call of editRow inside of setTimeout to be sure that processing of previous saving is finished. It's the way which I would recommend you.

On the other side if you try to combine enabled checkboxs of formatter: "checkbox" with inline editing then you will have much more complex processing. It's important that enabled checkbox can be changed first of all before processing of onclick and onchange event handlers. The order of 3 events (changing the state of the checkbox, processing of onclick and processing of onchange) can be different in different web browsers. If the method editRow be executing it uses unformatter of checkbox-formatter to get the current state of the checkbox. Based of the value of the state editRow replace the content of the cell to another content with another enabled checkbox. It can be that the state of the checkbox is already changed, but editRow interprets the changes state like the initial state of the checkbox. In the same way one can call saveRow only after editRow. So you can't just use saveRow inside of change handler of formatter: "checkbox", formatoptions: { disabled: false }, because the line is not yet in editing mode.

UPDATED: The corresponding implementation (in case of usage formatter: "checkbox", formatoptions: { disabled: false }) could be the following:

editurl: "SomeUrl",
beforeSelectRow: function (rowid, e) {
    var $self = $(this),
        $td = $(e.target).closest("tr.jqgrow>td"),
        p = $self.jqGrid("getGridParam"),
        savedRow = p.savedRow,
        cm = $td.length > 0 ? p.colModel[$td[0].cellIndex] : null,
        cmName = cm != null && cm.editable ? cm.name : "Quantity",
        isChecked;
    if (savedRow.length > 0 && savedRow[0].id !== rowid) {
        $self.jqGrid("restoreRow", savedRow[0].id);
    }
    if (cm != null && cm.name === "W3LabelSelected" && $(e.target).is(":checkbox")) {
        if (savedRow.length > 0) {
            // some row is editing now
            isChecked = $(e.target).is(":checked");
            if (savedRow[0].id === rowid) {
                $self.jqGrid("saveRow", rowid, {
                    extraparam: {
                        W3LabelSelected: isChecked ? "1" : "0", 
                    },
                    aftersavefunc: function (response) {
                        $self.jqGrid("editRow", rowid, {
                            keys: true,
                            focusField: cmName
                        });
                    }
                });
            }
        } else {
            $.ajax({
                type: "POST",
                url: "SomeUrl", // probably just p.editurl
                data: $self.jqGrid("getRowData", rowid)
            });
        }
    }
    if (rowid) {
        $self.jqGrid("editRow", rowid, {
            keys: true,
            focusField: cmName
        });
    }

    return true; // allow selection
}

See jsfiddle demo http://jsfiddle.net/OlegKi/HJema/190/

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Thank you for such a detailed answer. This is very close to what I want. See the edit. If I select on the checkbox the first time the `console.log` does get called everytime. However the `saveRow` gets called only when I check the checkbox and then click on it again to uncheck it. I explained more in my edit. – Dipen Shah Oct 05 '15 at 15:00
  • @DipenShah: You are welcome! The reason is the following: you try to call inline editing method `saveRow` **before** the inline editing will be started using `editRow`. I don't recommend you to use `formatoptions: { disabled: false }` of `formatter: "checkbox"` in combination with `editable: true` property. – Oleg Oct 05 '15 at 15:46
  • @DipenShah: I suggest to use **either `formatoptions: { disabled: false }` or `editable: true`**. If you would **remove `formatoptions: { disabled: false }`** then the code will be short and clear. The user will just need to make two clicks for changing the checkbox only. If you prefer to have `formatter: "checkbox", formatoptions: { disabled: false }` then you should **remove `editable: true`** from the checkbox-column. You code will be much longer. You should test in `beforeSelectRow` whether the row is in editing mode or not. Only if the row already in editing mode then you can use saveRow – Oleg Oct 05 '15 at 16:02
  • @DipenShah: If the row is not in editing mode then you can make jQuery.ajax call to the server directly without using of `saveRow`. – Oleg Oct 05 '15 at 16:04
  • Now I get the root of the problem. In this case if I decide to remove `editable:true` will the function `cellattr` serve my purpose correctly? What I can do is write a custom function to make a jQuery.ajax call to save the data manually. Is `cellattr` the right way to go? – Dipen Shah Oct 05 '15 at 16:12
  • @DipenShah: Sorry, I have to prepare now for the visit of my customer tomorrow. Could you try to prepare some jsfiddle demo which I can examine tomorrow evening or one day later? – Oleg Oct 05 '15 at 16:25
  • for sure @Oleg I am going to try something and let you know how it worked. Thank you for your invaluable time. – Dipen Shah Oct 05 '15 at 16:28
  • I prepared a fiddle [here](http://jsfiddle.net/HJema/183/) Take a look when you have the time. Thanks. – Dipen Shah Oct 05 '15 at 19:53
  • @DipenShah: OK, I'm just now back from the customer. I get your demo and I can see what you do wrong. I will modify it tomorrow and let you known. – Oleg Oct 06 '15 at 16:08
  • Thank you for your time. – Dipen Shah Oct 06 '15 at 16:25
  • @DipenShah: First of all jsfiddle has the setting (of the left size) which you chosen "onDomready". Because of that `selectThis` function is not global and it will be not called by `onClick` set inside of `cellattr`. One have to use "No wrap in " instead to make the code working in jsfiddle. I think that the setting of `onClick` inside of `cellattr` is not the best choice in your case. I will modify your code and post it soon. – Oleg Oct 07 '15 at 17:47
  • @DipenShah: See the modified demo http://jsfiddle.net/OlegKi/HJema/190/ and **UPDATED** part of my answer. I used everywhere URL `"/echo/json/"`. You can use [Fiddler](http://www.telerik.com/fiddler) for example to examine the data which will be send by the demo to the server. – Oleg Oct 07 '15 at 21:00
  • Thank you @Oleg. I just left work so I'm going to try this tomorrow and let you know if it worked. Thanks again for the help – Dipen Shah Oct 07 '15 at 21:09
  • @DipenShah: You are welcome! I hope that you can create the solution of your problem based on the demo. Best wishes! – Oleg Oct 07 '15 at 21:16
  • Thank you @Oleg This is actually better than my way of using `formatter` This demonstrates hybrid use of saving the checkbox state one using jqGrid's inbuilt `saveRow` method and one using my own url to save the state. Much better than what I was doing. Thanks again for all the help. – Dipen Shah Oct 08 '15 at 14:11
  • @DipenShah: You are welcome! I'm glad that I could help you. – Oleg Oct 08 '15 at 14:15
  • Hi @Oleg sorry to bother you again, but with the code that you provided, I am not able to select a row. If you see in your demo, you can edit the row but you can not select it. when I hit the Enter key to save the data, even then the grid does not have the last edited row as selected. This was not the case before. Is there something wrong with the code? I tried commenting the `beforeSelectRow` part and I was able to select that row. – Dipen Shah Oct 08 '15 at 16:01
  • the select row functionality is required to me for other purposes. – Dipen Shah Oct 08 '15 at 16:02
  • @DipenShah: I think that the most easy way to fix the problem is moving the code which calls `editRow` from `beforeSelectRow` to `onSelectRow` or in `ondblClickRow`. You can consider to use `ondblClickRow` instead of `onSelectRow`. It allows to use both selection and editing in one grid in very easy way. – Oleg Oct 08 '15 at 16:11
  • Thanks @Oleg I used ondblClickRow and it worked perfectly. – Dipen Shah Oct 08 '15 at 16:18
  • @DipenShah: You are welcome! By the way, I just posted some changes to GitHub and posted [the answer](http://stackoverflow.com/a/33021115/315935) with [the demo](http://www.ok-soft-gmbh.com/jqGrid/OK/multiPageSelection.htm). The changes implements new option `multiPageSelection: true` which can be used in combination with `multiselect: true`. Probably the feature could be interesting for you too. – Oleg Oct 08 '15 at 16:23
  • Thank you @Oleg. This seems to be actually a very useful feature which is going to come in handy to me. Thanks for the update. – Dipen Shah Oct 08 '15 at 16:45
  • Hi @Oleg sorry to bump you in this old question but I am having a problem with another one of my grids. In this grid I have two columns having checkboxes as the format type instead of one. I need the same functionality as in this answer which does not work with the code given in the answer. Could you suggest an alternative if I had two columns instead of one? – Dipen Shah Nov 26 '15 at 20:37