This is a migrated thread and some comments may be shown as answers.

Delete / Save Changes / Revert

8 Answers 1154 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Patrick Rioux
Top achievements
Rank 1
Patrick Rioux asked on 06 Mar 2012, 11:47 PM
Hi,

I experienced a strange behavior with the new beta version. I can't tell if this is a new bug.
I'm using batch grid edition. Click on Delete and Save Changes. The change is really committed on the sever at this point.
I click on 'Cancel' and my record is back on the grid. Since it has been already deleted, if I try to edit or destroy it raised errors.
Do you have any work around for this?

The beta demo is doing grid edition on local data. I think a example with server-side data would be very good sample to add.
The behavior could certainly be different.
Thank you.

8 Answers, 1 is accepted

Sort by
0
Nikolay Rusev
Telerik team
answered on 07 Mar 2012, 09:47 AM
Hello Patrick,

The beta batch editing demo seems to be working properly:
http://demos.kendoui.com/beta/web/grid/editing.html

Regards,
Nikolay Rusev
the Telerik team
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Patrick Rioux
Top achievements
Rank 1
answered on 07 Mar 2012, 04:42 PM
It seems like when I click on 'Save changes' or 'Cancel changes' the internal model keep data in it.
Therefore if I perform a destroy and click save, it has been committed on the server (good).
And then if I click again on:
save - It will post again with the same row I have just deleted. It will end up with an error since the record doesn't exist anymore.
cancel - It pull back the row on the grid.

It seems that I need to do something after records has been successfully committed and/or cancelled.
I have attached my code.
You will not be able to run this code since it is a server-side grid but you may find something.
Maybe I'm doing something wrong but I can't figure it.
0
Patrick Rioux
Top achievements
Rank 1
answered on 07 Mar 2012, 04:44 PM
Sorry I wasn't able to attach my file:

<!DOCTYPE html>
<csp:comment>
    Digital Technology International
</csp:comment>
<csp:class super="dt.common.ui.csp.kendo.page.AbstractPage">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
    Kendo Grid Editing
</title>
    #(..IncludeThemeTemplate())#
    #(..IncludeConsole())#
</head>

<body>         
    <div class="k-content samplesContent">
        <h2 class="samplesInfo">Kendo Grid Editing</h2>
            <ul>
                <li>Row Editing</li>
                <li>Server/Client-Side Validations</li>
                <li>Updates thru Business Object</li>
                <li>Display any Broken Rules errors</li>
            </ul>
        
        <label style="k-label">Editor Type:</label>
        <label><input id="batch" type="radio" name="editortype" onclick="setEditorType(this.value);" value="batch"/>Batch</label>
        <label><input id="inline" type="radio" name="editortype" onclick="setEditorType(this.value);" value="inline"/>Inline</label>
        <label><input id="popup" type="radio" name="editortype" onclick="setEditorType(this.value);" value="popup"/>Popup</label>
        
        <div id="grid"></div>
                
        #(..ConsoleDiv())#
                            
    </div>
            
    <!--To create random data for the grid: W ##class(dt.common.ui.samples.data.Salesrep).Populate(1000)  -->
    <script type="text/javascript">

          // change Event
        function onChange(arg) {
            var selected = $.map(this.select(), function(item) {
                return $(item).text();
            });
            kendoConsole.log("[Event: change] [Selected: " + selected.length + " item(s)] [Data:" + selected.join(", ")+ "]");
        }
        
        // dataBound Event
        function onDataBound(arg) {
            kendoConsole.log("[Event: dataBound]");
        }
          
          function setEditorType(value) {
              sessionStorage.setItem('kendoEditorType',value);
              window.location.reload();
          }
          
          /// To move to dtKendoUtils.js
          function dtParseResponseText(intext)
          {
              var tstr = intext.substring(parseInt(intext.indexOf('([{'))+1,parseInt(intext.lastIndexOf(')')));
              if ((tstr.indexOf('[') == 0) && (tstr.lastIndexOf(']') == tstr.length-1)) {
                  return JSON.parse(tstr)
              }
              else {
                return null;
              }
          }
                        
        // Create the grid instance.  
        function createGrid()
        {
            // Set the schema model
              var schema = [{model: {id: "SalesrepId",
                               fields: {
                                        SalesrepId: { type: "number",editable: false},
                                        Code: { type: "string",editable: false},
                                        Active: { type: "boolean",editable: true},
                                        LastName: { type: "string",editable: true,validation:{ required: true }},
                                        FirstName: { type: "string",editable: true,validation:{ required: true }},
                                        StreetName: { type: "string",editable: true, validation:{ required: true }},
                                        YearSalesTarget: { type: "number",editable: true,validation: { min: 0 }},
                                        StartDate: { type: "date", editable: true},
                                        LastChangedUtc: { type: "date", editable: false},
                                        State: { type: "string",editable: false}
                                        }
                               },
                               parse : function(data) {
                                    // Dates are returned in ODBC format because Kendo require a JavaScript date.
                                    $.each(data.d.results, function(i, val){
                                        val.StartDate = new Date(val.StartDate);
                                        val.LastChangedUtc = new Date(val.LastChangedUtc);
                                     });
                                 return data;
                               }
                          },
                      ];
          
              var editorType = sessionStorage.getItem('kendoEditorType');
              if (!editorType) editorType = 'batch';
              $("#"+editorType).attr('checked','checked')
              var batchEditor = (editorType == 'batch');
          
              // Build a csv list of fields based on the schema
              var selectFields = "";
              $.each(schema[0].model.fields, function(key, value) {
                  // Cast StartDate as Date to force checking the date only. Timestamp by default.
                  selectFields += ((selectFields != '')?',':'') + ((key == 'StartDate')?'cast(StartDate as Date) as StartDate' : key);
            });           
            
            var updateServiceBaseUrl = "csp/mediapool/public/dt.common.odata.UpdateServer.cls",
              fetchServiceBaseUrl  = "csp/mediapool/public/dt.common.odata.FetchServer.cls",
              
              // DataSource Object
               ds = new kendo.data.DataSource({
                    type: "odata",
                    serverFiltering: true,
                    // Example of a build-in filter
                    filter: [{
                        field: "YearSalesTarget",
                        operator: "gte",
                        value: 1000}],
                    transport: {
                        // Build custom parameters
                        parameterMap: function(data,operation) {
                               if (operation == 'read') {
                                   // Used default odata parameters
                                   return kendo.data.transports["odata"].parameterMap(data,operation)
                               }

                               else {
                                   return {
                                           $operation: function () { return operation},
                                        $dataset: function () { return "dt.common.ui.samples.kendo.SalesrepDataset" },
                                        $datasetabstract: function () { return "dt.common.ui.samples.kendo.SalesrepDatasetAbstract" },
                                        model: kendo.stringify(data.models)  // models to JSON
                                             };
                                   }
                          },
                        // $select would fetch only the necessary columns. Must match columns:[]
                        read: { type: "GET", url: fetchServiceBaseUrl,dataType: "jsonp",
                                data: { $select: function () { return selectFields},
                                        $tablename: function () {return "dt_common_ui_samples_data.Salesrep"}
                              }
                        },
                        update:  { type: "POST", url: updateServiceBaseUrl,dataType: "jsonp"},
                        destroy: { type: "POST", url: updateServiceBaseUrl,dataType: "jsonp"}
                    },
                    schema: schema[0],
                    error: function(e)
                    {
                        var data = dtParseResponseText(e.responseText);
                        alert('Update has failed!'+((data && data[0] && data[0]._errmsg)?"\n\n"+data[0]._errmsg:''))
                            
                        // Cancel grid changes.
                        $("#grid").data("kendoGrid").cancelChanges();
                    },
                    pageSize: 10,
                    serverPaging: true,
                    serverSorting: true,
                    batch: true
                });
                
            $("#grid").kendoGrid({
                 dataSource: ds,
                        navigatable: true,  // Indicates whether keyboard navigation is enabled/disabled.
                        pageable: true,
                        scrollable: false,
                        filterable: true,
                        sortable: true,
                        selectable: "row",
                        groupable: true,
                        change: onChange,
                        dataBound: onDataBound,
                          columns: [    {field:"SalesrepId",title:"Salesrep",width:"4%"},
                                      {field:"Code",title:"Code",width:"4%"},
                                      {field:"Active",title:"Active",width:"4%", template: '<div>#=(Active)?"Yes":"No"#</div>'},
                                      {field:"LastName",title:"Last Name",width:(batchEditor)?"10%":"8%"},
                                    {field:"FirstName",title:"First Name",width:(batchEditor)?"10%":"8%"},
                                    {field:"StreetName",title:"Street",width:(batchEditor)?"20%":"12%"},
                                      {field:"YearSalesTarget",title:"Year Sales $",width:"10%",template: '<div style="text-align:right">#=kendo.toString(YearSalesTarget,"c")# $</div>'},
                                      {field:"StartDate",title:"Start Date",width:"10%",template: '#=dtFormatDate(StartDate)#'},
                                      {field:"State",title:"State",width:"5%"},
                                      {field:"LastChangedUtc",title:"Updated",width:"15%",template: '#=dtFormatDateTime(LastChangedUtc)#'},
                                      {command: (batchEditor)?"destroy":["edit","destroy"], title: " ", width:(batchEditor)?"5%":"18%", filterable: false }],
                           toolbar: (batchEditor)? ["save", "cancel"]:"",
                        editable: (batchEditor)?true:editorType
            });
            
            // Set column filter formatting
            var grid = $("#grid").data("kendoGrid"),
                columnFilterMenu = grid.thead.find("th[data-field=SalesrepId]").data("kendoFilterMenu");
            columnFilterMenu.form.find("[" + kendo.attr("type") +"=number]").each(
                function() {
                    $(this).data("kendoNumericTextBox").options.format="n0";
                });
         }
          
        $(document).ready(function() {
            createGrid();
        });
    </script>
</body>
</html>


0
Accepted
Nikolay Rusev
Telerik team
answered on 08 Mar 2012, 04:24 PM
Hello Patrick,

Is your service OData? OData services requires a bit more different implementation for CRUD and our DataSource does not currently have implementations for this yet. It also requires the OData service to be in the same domain as the host application, which means no JSONP can be used with OData CRUD operations.

Regards,
Nikolay Rusev
the Telerik team
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Patrick Rioux
Top achievements
Rank 1
answered on 08 Mar 2012, 05:56 PM
Nikolay,
I guess you are referring to the type="odata" on the top? 
I have attached my code sample (test.zip), you may double check this is the real issue here.
I'm afraid that I don't fully understand your response.
In my code, every thing is updated successfully on the server and the success callback method is never called.
Maybe I don't set the proper response (or something else)?  Or just not supported by the datasource as you stated.
About the odata service, I'm on a Intersystem Cache environment and there is no ODATA service supported "out of the box".
My http request is handled my a server who parse the request and send back the response. Initially when an error occurs, I didn't send back the 422 code dans therefore the error: callback event was not called. When I changed the server response using 422 (when an error occurs), the callback start to work.  Everything look good except that red markers remains after a update operation. It seems like just a grid refresh is missing. I never works with odata before and honestly don't know how to fix this.
0
Patrick Rioux
Top achievements
Rank 1
answered on 08 Mar 2012, 09:33 PM
I finally fixed my issue...The response sent back to the client was in the wrong format.
The key here is it was requiring the "d":{"results":[....odata structure to match the one from the read.
Just spends many hours to find this. Thank you for your support.

jQuery17106964007887141991_1331238107791
({"d":{"results":[{"SalesrepId":56041,"Code":"J425","Active"
:true,"LastName":"Nelson","FirstName":"Lisa","StreetName":"5447 Washington Place","YearSalesTarget":5000,"StartDate":"1901-09-12T04:00:00.000Z","LastChangedUtc":"2012-03-09T01:15:51.000Z","State":"IN"},{"SalesrepId":56052,"Code":"T4522","Active":true,"LastName":"Duquesnoy","FirstName":"Kyra","StreetName":"1501 Franklin Court","YearSalesTarget":5257.1,"StartDate":"1942-02-22T05:00:00.000Z","LastChangedUtc":"2012-03-08T20:20:59.000Z","State":"NE"}]}});

0
Alexandre
Top achievements
Rank 1
answered on 03 Oct 2012, 09:36 AM
Hi Patrick.

I've got the same problem you described.
But, I don't understand your solution.

Could you explain it.

Thanks very much

Alexandre
0
Matthew
Top achievements
Rank 1
answered on 16 Jul 2013, 02:16 PM
What I believe he means is that you need to return the data in the same format as the read.  In my read I returned data in a Json result like so: 
        /// <summary>
        /// Populate the page layout settings
        /// </summary>
        /// <returns></returns>
        public ActionResult PageLayoutSettingsRead([DataSourceRequest] DataSourceRequest request, string pageType)
        {
                return Json(GetPageLayoutSettings(pageType).ToDataSourceResult(request)); // Returns List<PageLayout>
        }

Originally in my update, I just returned true if the update succeeded.  This resulted in in the problem of the Cancel changes button still working even after the save.  The changes got committed at the server but the user could still visually undo the changes which lead to confusion.

        /// <summary>
        /// Update the page layout settings (problem)
        /// </summary>
        /// <returns></returns>
        public ActionResult PageLayoutSettingsUpdate([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")]List<PageLayout> modifiedPageLayouts)
        {
            return Json(UpdatePageLayout(modifiedPageLayouts));
        }

What I had to do was make sure the response was int he same format as the read. (Read returned Json List of PageLayouts so update needed to return Json List of PageLayouts)
 
        /// <summary>
        /// Update the page layout settings (fixed)
        /// </summary>
        /// <returns></returns>
        public ActionResult PageLayoutSettingsUpdate([DataSourceRequest] DataSourceRequest request, [Bind(Prefix ="models")]List<PageLayout> modifiedPageLayouts)
        {
           // Update the page layouts
           UpdatePageLayout(modifiedPageLayouts);

            // Return the modified content because otherwise the cancel button will still work
            return Json((modifiedPageLayouts).ToDataSourceResult(request));
        }
Tags
Grid
Asked by
Patrick Rioux
Top achievements
Rank 1
Answers by
Nikolay Rusev
Telerik team
Patrick Rioux
Top achievements
Rank 1
Alexandre
Top achievements
Rank 1
Matthew
Top achievements
Rank 1
Share this question
or