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

Possible Grid Bug - Inline Edit vs. Create

5 Answers 267 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Bill
Top achievements
Rank 1
Bill asked on 13 Aug 2013, 07:49 PM
Hi, 

I have a grid working nicely with fairly simple rows and inLine editing enabled.  Everything is working  fine except for a couple of small issues.  Here they are:

  • I insert a row in the grid and fill it in.  Click save.  Row is committed as expected.
  • Without a refresh, I then click the edit button for the same row and attempt to make a change.  Save is clicked again.
  • The row acts as if it's still in "Create" mode and the data is sent to the the Create controller action.  As expected, that fails due to a primary key error of trying to insert the same row again.
  • I think this is incorrect.  It should be sent to the Update/Edit action.
  • Please advise...
Here is the grid code:

    @(Html.Kendo().Grid(Model.TimesheetDetails)
    .Name("TimesheetDetailGrid")
    .TableHtmlAttributes(new { style = "padding:0; margin:0;font-size:smaller;color:green" })
    .Columns(columns =>
    {
        columns.Bound(x => x.Id).Hidden();
        columns.Bound(x => x.TimesheetId).Hidden();
        columns.Bound(x => x.CompanyId).Hidden();
        columns.ForeignKey(p => p.JobCodeId, (System.Collections.IEnumerable)ViewData["JobCodes"], "Id", "JobCodeName")
                            .Title("Job Code")
                            .Width(150)
                            .HeaderHtmlAttributes(new { @class = "GridHeader" });
         
        columns.Bound(x => x.Description)
                            .Width(250)
                            .Title("Description")
                            .HeaderHtmlAttributes(new { @class = "GridHeader" });
         
        columns.Bound(x => x.WorkDate)
                            .Width(65)
                            .Title("Date")
                            .HeaderHtmlAttributes(new { @class = "GridHeader" });
 
        columns.Bound(x => x.StartTime)
                            .Width(55)
                            .Title("Start")
                            .Format("{0:hh:mm}")
                            .HeaderHtmlAttributes(new { @class = "GridHeader" })
                            .HtmlAttributes(new { @class = "StartTime" });
 
        columns.Bound(x => x.EndTime)
                            .Width(55)
                            .Title("End")
                            .Format("{0:hh:mm}")
                            .HeaderHtmlAttributes(new { @class = "GridHeader" })
                            .HtmlAttributes(new { @class = "EndTime" })
                            .ClientFooterTemplate("Hours: ");
 
        columns.Bound(x => x.Duration)
                            .Width(55)
                            .Title("Hours")
                            .HeaderHtmlAttributes(new { @class = "GridHeader" })
                            .ClientFooterTemplate("#=kendo.toString(sum, '0.00') #");
                             
        columns.Command(command => { command.Edit(); command.Destroy(); }).Width(122);
    })
    .ToolBar(toolbar => toolbar.Create())
    .Editable(editable => editable.Mode(GridEditMode.InLine))
    .Pageable(x => x
        .PageSizes(true)
        .PageSizes(new int[] { 2, 3, 4, 5, 10, 25, 100 }))
    .Sortable()
    .Events(events => events.Edit("onEdit"))
    .Events(events => events.Save("onSave"))
    //.Events(events => events.DataBound("gridDataBound"))
    .DataSource(ds => ds
        .Ajax()
        .ServerOperation(true)
        .PageSize(10)
        .Model(m =>
        {
            m.Id(vm => vm.Id);
            m.Field(vm => vm.Id).DefaultValue(Guid.NewGuid()).Editable(false);
            m.Field(vm => vm.TimesheetId).DefaultValue(Model.Id).Editable(false);
            m.Field(vm => vm.CompanyId).DefaultValue(Model.CompanyId).Editable(false);
            m.Field(vm => vm.JobCodeId).DefaultValue(Guid.Empty);
            m.Field(vm => vm.Duration);
             
        })
        .Aggregates(aggregates =>
        {
            aggregates.Add(p => p.Duration).Sum();
        })
        .Read(read => read.Action("TimesheetDetail_Json", "Timesheet", new { Id = Model.Id }))
        .Create(update => update.Action("AddDetailRow_Json", "Timesheet"))
        .Update(update => update.Action("EditDetailRow_Json", "Timesheet"))
        .Destroy(update => update.Action("DeleteDetailRow_Json", "Timesheet"))
    )
)



My other issue is that I cannot get the aggregations to refresh upon editing or inserting a row.  I know that this happens when the datasource is refreshed and I've searched around for some more info.  I tried this as the save event handler for the grid.  No luck.  BTW, the same behavior with or without the e.model.set line.
function onSave(e) {
 
    var dataSource = this.dataSource;
    e.model.one("change", function () {
        dataSource.one("change", function () {
            //alert(dataSource.aggregates().Amount.sum);
        });
        dataSource.fetch();
    });
    e.model.set("Duration", $("#Duration").val());
 
}
I'd appreciate any help.




5 Answers, 1 is accepted

Sort by
0
Vladimir Iliev
Telerik team
answered on 15 Aug 2013, 07:45 AM
Hi Bill,

 
From the provided information it seems that the first "AddDetailRow_Json" action on the server doesn't return the updated record to the Grid - in that case the model ID of that record is left to the default "0". When you click the Save button again the record is send through the Create action again as the DataSource think that the record is new (due to the model ID is equal to "0"). Please check the example below of correct Create action:

public ActionResult Create([DataSourceRequest] DataSourceRequest request, Order order)
{
    //insert the record to the DB
    if (order != null && ModelState.IsValid)
    {
        OrderRepository.Insert(order);
    }
     
    //return the updated record which contains the correct model ID
    return Json(new[] { order }.ToDataSourceResult(request, ModelState));
}

Also in current scenario you can use the RequestEnd event of the DataSource to check if current operation is create, update or delete to use the DataSource read method () in order to refresh the aggregations:

function onRequestEnd(e) {
    if (e.type != "read") {
        var dataSource = this;
        setTimeout(function () {
            dataSource.read();
        });
    }
}
Kind Regards,
Vladimir Iliev
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Bill
Top achievements
Rank 1
answered on 15 Aug 2013, 01:45 PM
Hi Vladimir,

The totals refresh works perfectly!  Thanks.

As to the inline edit situation...I was already returning the row to the grid as you suggested; at least I think I am.  Here is the code.

public ActionResult AddDetailRow_Json([DataSourceRequest]DataSourceRequest request, TimesheetDetailVM vm)
{
    if (ModelState.IsValid)
    {
        var entity = new TimesheetDetail
        {
            Id = vm.Id,
            WorkDate = vm.WorkDate,
            CompanyId = vm.CompanyId,
            TimesheetId = vm.TimesheetId,
            JobCodeId = vm.JobCodeId,
            Description = vm.Description,
            StartTime = vm.StartTime,
            EndTime = vm.EndTime,
            LastModDate = DateTime.Now,
            LastModUser = WebSecurity.CurrentUserId
        };
        db.TimesheetDetails.Add(entity);
        db.SaveChanges();
    }
    return Json(new[] { vm }.ToDataSourceResult(request, ModelState));
}
The vm.Id field is set to a Guid and returned as I think you intend.  Still the same behavoir.

TIA, Bill
0
Vladimir Iliev
Telerik team
answered on 16 Aug 2013, 06:55 AM
Hi Bill,

 
From the provided information it seems that you never return the created record Id to the client - please check the updated code below:

public ActionResult AddDetailRow_Json([DataSourceRequest]DataSourceRequest request, TimesheetDetailVM vm)
{
    if (ModelState.IsValid)
    {
        var entity = new TimesheetDetail
        {
            Id = vm.Id,
            WorkDate = vm.WorkDate,
            CompanyId = vm.CompanyId,
            TimesheetId = vm.TimesheetId,
            JobCodeId = vm.JobCodeId,
            Description = vm.Description,
            StartTime = vm.StartTime,
            EndTime = vm.EndTime,
            LastModDate = DateTime.Now,
            LastModUser = WebSecurity.CurrentUserId
        };
        db.TimesheetDetails.Add(entity);
        db.SaveChanges();
        //get the created record ID and send it back to the client
        vm.Id = entity.Id;
    }
    return Json(new[] { vm }.ToDataSourceResult(request, ModelState));
}
Kind Regards,
Vladimir Iliev
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Bill
Top achievements
Rank 1
answered on 16 Aug 2013, 02:10 PM
Vladimir,

As I step through my code, the viewModel already has the correct ID set upon successful creation of the row.  The specific assignment you suggest is redundant since the value is already returned.  Notice that the default value of the ID on the grid creation code is defaulted to Guid.NewGuid.  This ensures I have a new ID when the initial create happens and the VM is passed back to the controller.  Could this be trampling something??

I'm not sure where to go from here...this still looks like a bug to me...

.Model(m =>
        {
            m.Id(vm => vm.Id);
            m.Field(vm => vm.Id).DefaultValue(Guid.NewGuid()).Editable(false);
            m.Field(vm => vm.TimesheetId).DefaultValue(Model.Id).Editable(false);
            m.Field(vm => vm.CompanyId).DefaultValue(Model.CompanyId).Editable(false);
            m.Field(vm => vm.JobCodeId).DefaultValue(Guid.Empty);
            m.Field(vm => vm.Duration);
              
        })


Thanks for working it with me.

0
Vladimir Iliev
Telerik team
answered on 20 Aug 2013, 01:39 PM
Hi Bill,

 
Please note that setting the model ID using the DefaultValue method is invalid configuration and can lead to unexpected behavior - the ID should be received from the server after adding the record to the dataBase (as demonstrated in my previous post).

Kind Regards,
Vladimir Iliev
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
Tags
Grid
Asked by
Bill
Top achievements
Rank 1
Answers by
Vladimir Iliev
Telerik team
Bill
Top achievements
Rank 1
Share this question
or