Delete / Save Changes / Revert

9 posts, 1 answers
  1. Patrick Rioux
    Patrick Rioux avatar
    53 posts
    Member since:
    Sep 2012

    Posted 06 Mar 2012 Link to this post

    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.

  2. Nikolay Rusev
    Admin
    Nikolay Rusev avatar
    1954 posts
    Member since:
    Dec 2014

    Posted 07 Mar 2012 Link to this post

    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!

  3. Patrick Rioux
    Patrick Rioux avatar
    53 posts
    Member since:
    Sep 2012

    Posted 07 Mar 2012 Link to this post

    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.

  4. Patrick Rioux
    Patrick Rioux avatar
    53 posts
    Member since:
    Sep 2012

    Posted 07 Mar 2012 Link to this post

    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>


  5. Answer
    Nikolay Rusev
    Admin
    Nikolay Rusev avatar
    1954 posts
    Member since:
    Dec 2014

    Posted 08 Mar 2012 Link to this post

    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!

  6. Patrick Rioux
    Patrick Rioux avatar
    53 posts
    Member since:
    Sep 2012

    Posted 08 Mar 2012 Link to this post

    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.

  7. Patrick Rioux
    Patrick Rioux avatar
    53 posts
    Member since:
    Sep 2012

    Posted 08 Mar 2012 Link to this post

    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"}]}});

  8. Alexandre
    Alexandre avatar
    1 posts
    Member since:
    Dec 2010

    Posted 03 Oct 2012 Link to this post

    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

  9. Matthew
    Matthew avatar
    1 posts
    Member since:
    Jun 2013

    Posted 16 Jul 2013 Link to this post

    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));
            }

Back to Top