jqGrid - Inline edit - Detect dirty / changed cells
Asked Answered
M

5

14

is there an example of using jqgrid's getChangedCells method to determine if data has changed?

I grepped getChangedCells in the downloadable demos for jqgrid, and could only find the function definition, not example usages of getChangedCells.

What I want to do is save the edits that a user's made if the user clicks on another row. But, I only want to submit the save if the row is dirty.

Thanks in advance, --Nate

Miserable answered 15/6, 2011 at 15:46 Comment(2)
+1 It's a good question.Reticent
Seriously, this is a gooood one! I hope have more votes to give you :(Reticent
S
5

There are no safe dirty flag on the row. You can use the fact that at the beginning of row editing (at the start of the inline editing mode) the method editRow add editable="1" attribute to the grid row (<tr> element). Later the methods saveRow and restoreRow changes the attribute value to editable="0". So the rows of the current page which was at least once in the inline editing mode will have the editable attribute. If the id of the table element is "list" you can find the edited rows with

$("#list tr[editable]")

The ids of the elements of the set are the rowids of the rows.

If you use paging in the grid you should be careful and save the ids of the edited rows on the current page before the changing of the page. The onPaging event would help you here.

In my opinion the best and the most safe way to do what you need is to use aftersavefunc parameter of the editRow or saveRow methods (probably you use directly only editRow). Inside of your aftersavefunc function you can save the id of the modified row in an array/map. This will solve your problem and will safe work.

Sulfonmethane answered 15/6, 2011 at 17:37 Comment(16)
I analized your method because I need what he asks too, but your method give the information of what row has been selected for inline editing at some point, rather than tell wether the data in the row has been changed or not.Reticent
@diosney: In the first sentence of my answer I wrote: "There are no safe dirty flag on the row". In case if you has nothing you can use $("#list tr[editable]") to reduce the number of rows which you need send to the server. You can see rows which are definitively not changed. Like I wrote later you can use aftersavefunc to trace the changes. It will work safe.Sulfonmethane
I am trying to do almost the same thing, warning the user when unsaved changes. the above mentioned approach is not applicable, when user changes the value and later reverts it back, it will still consider it as changed. I am using inline edit. Since its been 5 years, do you have any update on this now? Please assist. ThanksAllerus
@RustinCohle: It's better that you open new question, where you describe exactly what you do and which problem you have. The standard way is editurl and to save the data directly on the server. It prevents many problems (processing errors on the server side like concurrency control for example) and simplify the code. Moreover one should don't edit more as one row at the same time. There are more alternatives, but it's vary important to know the exact usage of jqGrid and the version and fork of jqGrid which you use.Sulfonmethane
@Sulfonmethane I am banned from asking a question. Sorry.I am not trying to save. I prompt the user as Do you want to leave? not save. I want the way to track the changes, Saving isnt a problem, because I am not saving. Thanks. I am using Tony's fork. 4.6.0.Allerus
@RustinCohle: I really need to understand what scenario you use to be able to help you. I still don't understand your problem. Which datatype you use? Do you use loadonce: true or not? In general inline editing allows to specify aftersavefunc callback. You can extend the local data with additional property (for example boolean saved property). You can grep all items, which have saved: true property. Alternatively you can hold the map with ids of saved/modified items and to have the same results. One need just to use aftersavefunc callback.Sulfonmethane
@RustinCohle: The demo jsfiddle.net/OlegKi/byygepy3/11 created for the answer shows how to set dirty property for an local item after modification. It uses jqGrid afterSetRow callback which exist on free jqGrid only, but you can use the same idea with old jqGrid 4.6.0 and to use aftersavefunc callback of inline editing.Sulfonmethane
@Sulfonmethane I am not trying to save dirty data, I am only trying to warn the user whether to discard or stay. I just want to track if the user has edited the row value or not like if user edits a row some flag needs to be set to true. I am using datatype: json, loadonce: defaultAllerus
@Sulfonmethane Thanks and als I want the dirty flag to be set only if the user has changed any value in the row(textbox,select,option). Again, my scenario: Click Editrow -> change some value -> click refresh button(or any server calling function) -> Warn user as you have unsaved data, proceed?. Thanks.Allerus
@RustinCohle: If you use remote datatype without (datatype: "json" without loadonce: true) then there are exist no local data which could be changed by user. Which editurl you use? If the user modifies the data with respect of inline editing then the data will be saved on the server and reloading of data will return new data. I can guess that the user is editing the data. I mean that some row is in editing mode. You can detect the case by usage savedRow parameter of jqGrid. If the length of the array savedRow is not 0 then there are exist at least one row in editing mode.Sulfonmethane
@RustinCohle: Look at the large number of comments about the subject, but I still not sure what problem you really have. I suggested you before to open new question where you post some code, pictures and describe the problem more detailed. It would be really helpful. I'm working now on a solution for one of my customer and it has no relation with jqGrid or JavaScript. Thus posting many comments just take time and bring us not so quickly to the solution of the problem.Sulfonmethane
Thanks @Oleg. I wish I could post the code. I used your idea of editable attr. However, in inline edit, is there a way to get the defaultValue(original value before editing) of textbox or any other html element of a particular row? Please helpAllerus
@RustinCohle: You still don't understand me. Till now you wrote just about "inline editing". I don't know whether you call editRow directly (inside of onSelectRow for example) or you use inlineNav or you use formatter: "actions". All what you explain I can interpret in many ways. Indirectly, from your questions, I guess that you have the problem because you use inline editing in the wrong way (but I don't know how you do it). I think that you try to solve the problem, which should not exist and thus you should fix the code where you use inline editing. Do you tried aftersavefunc?Sulfonmethane
@RustinCohle: I wrote you additionally that jqGrid saves the values from the editing row (original values before editing) in savedRow option of jqGrid. Thus grid.jqGrid("getGridParam", "savedRow")[0] contains the information which you need.Sulfonmethane
Thanks @oleg, I am using formatter:actions, to keep a buttong in each row, on clicking i call editRow manually. at the same time as of now i serialize the row data and keeping it and then if the user clicks anywhere without saving, i compare the serialized data and current row data for unsaved changes. this is my current way.Allerus
@RustinCohle: Sorry, but I really have to have the demo or the JavaScript code which shows exactly what you do and I need the exact description of the problem. I do my main job, implement solutions for my main customers, post answers on issues to GitHub and try to answer on questions on the stackoverflow. Every time after I read your last comment I have to reread all previous one to remember what problem you have. It spend too many my time. I can't help you till you post either new question on stackoverflow or new issue to free jqGrid.Sulfonmethane
R
4

Finally, I managed to bring a piece of code to detect what we want ;)

Hopefully any jqgrid gurus there (like Oleg), have enough time to review this code and improve it.

The example code will work for detect data changed in a grid with an editable field named "name". If you want to check for changed data in more columns, you have to add the variables after_edit and before_edit asociated with that columns.

To get the previous cell data inside the onSelectRow function, I don't used the getCell method because in the documentation says in red:

Do not use this method when you editing the row or cell. This will return the cell content and not the actuall value of the input element

By disgrace I could check that the documentation was right :(. However the getCell function works properly with the current cell data.

And here is the code:

 // Declare variables used for inline edit functionality.
 var last_selected;
 var before_edit_value;
 var after_edit_value;
 $('#grid-id').jqGrid({
...

onSelectRow: function(row_id){
    if(row_id && row_id !== last_selected) {
        /*
         * Determine if the value was changed, if not there is no need to save to server.
         */
         if (typeof(last_selected) != 'undefined') {
            after_edit_value = $('#grid-id tr#' + last_selected + ' .name_column input').val();
         }

        if (before_edit_value != after_edit_value) {
            /*
             * Save row.
             */
            $('#grid-id').jqGrid(
                'saveRow', 
                last_selected, 
                function(response){
                    /* SuccessFunction: Do something with the server response */

                    return true;    
                }, 
                'http://url.to.server-side.script.com/server-side-script.php', 
                {
                    additional_data: 'example: additional string',
                });
            }
            else {
                /*
                 * Restore the row.
                 */
                $('#grid-id').jqGrid('restoreRow', last_selected);
            }

        before_edit_value   = $('#grid-id').jqGrid('getCell', row_id, 'name');
    }   

    last_selected       = row_id;

    /*
     * Edit row.
     */
    $('#grid-id').jqGrid(
        'editRow', 
        row_id, 
        true, 
        function() {/* OnEditFunction */}, 
        function(response) {
        /* SuccessFunction: Do something with the server response */

        return true;

    }, 
    'http://url.to.server-side.script.com/server-side-script.php', 
    {
        additional_data: 'example: additional string',
    }); 
   },
...
});
Reticent answered 21/8, 2011 at 22:49 Comment(1)
excellent solution. Unfortunately this works only with single column. How to check all editable columns for any column has changed or if some edit has made ?Fluorosis
T
2

In one of my projects I did the following: before editing the row I remember row data in global variable and after editing is done just check if row data was changed. Something like this (edit mode activated by double click):

var beforeEditData;

function onGridDblClickRow(id) {
  if (isRowEditable(id)) {
    beforeEditData = grid.getRowData(id);
    grid.editRow(id, true, null, null, 'clientArray', null, onRowAfterEdit);
    ...
  }
}
function onRowAfterEdit(row) {
  var data = grid.getRowData(row);
  if (!isDataChanged(beforeEditData, data)) {        
    return; // No changes
  }
  ... // Save data here
}
function isDataChanged(before, after){
  ... // Allows tricky logic for dirty data, e.g. one may trim spaces etc.
}

Terpsichore answered 29/12, 2011 at 13:7 Comment(0)
H
1

Using MVC4 and JQuery this is what I did

In the View

<script type="text/javascript">

var $grid = $("#Grid");
var lastSelection;
var datachanged = false;

function gridInitialised() {
    var headers = $('th>div>:input');
    for (var h = 0; h < headers.length; headers[h++].onclick = (function () { if (datachanged) { $grid.saveRow(lastSelection); datachanged = false; } }));
}

function editRow(id) {
    if (id && id !== lastSelection) {
        if (datachanged) { $grid.saveRow(lastSelection); datachanged = false; }
        $grid.restoreRow(lastSelection);
        $grid.editRow(id, true);
        var inputs = $('#'+id+'>td>:input[class="editable"]');
        for (var i = 0; i < inputs.length; inputs[i++].onchange = (function () { datachanged = true; }));
        lastSelection = id;
    }
}
</script>

@Html.Trirand().JQGrid(Model.Grid, "Grid")

in the Model

            Grid.ClientSideEvents.RowSelect = "editRow";
            Grid.ClientSideEvents.GridInitialized = "gridInitialised";

The gridInitialised code is to handle changes to the search filter.

Dave

Howler answered 26/2, 2013 at 16:11 Comment(0)
K
0

As Oleg mentioned 5 (wow) years ago - I used the saveRow function and passed the flag as extraparam.

something like this, assuming your "model" or a hidden column IsDirty in my case:

onSelectRow: function(id) {
                if (id && id !== lastgridsel) {
                    $("#myGrid").saveRow(lastgridsel, false, "clientArray", { IsDirty: "True" });
                    $("#myGrid").editRow(id, true, null, null, "clientArray");
                    lastgridsel = id;
                }
            },

and then loop through the rows on Save click (external button in my case), something along the lines of:

$("#gridSaveBtn").on("click", function() {
            var batch = new Array();
            var dataIds = $("#myGrid").jqGrid("getDataIDs");
            for (var i = 0; i < dataIds.length; i++) {
                try {
                    $("#myGrid").jqGrid("saveRow", dataIds[i], false, "clientArray");
                    //get row data
                    var data = $("#myGrid").jqGrid("getRowData", dataIds[i]);
                    if (data["IsDirty"] === "True") {
                        batch.push(data);
                    }
                } catch (ex) {
                    alert(ex.Message);
                    $("#myGrid").jqGrid("restoreRow", dataIds[i]);
                }
            }
        });
Kendry answered 26/1, 2016 at 19:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.