jasperli
jasperli

Reputation: 11

How to keep a row edit-mode after getting error in ASP.NET MVC kendo grid?

Environment: Visual Studio 2012, ASP.NET MVC 4, Kendo UI Complete, Telerik OpenAccess 2013.3.101.

The scenario is as following :

1) The kendo grid is set up for 'Inline' editing.

2) The grid has a column including a kendo dropdownlist publishing a list of date type values.

3) The value of the dropdownlist should be unique in any rows. There is a model validation attribute called DateTypeValidation to check if the selected date type is existed in other rows or not.

4) The user click "Add New" button and add a new row. The row changes to 'Edit' mode, fill all fields and choose a datetype value.

5) Press 'Update' button and DateTypeValidation() return false meaning the selected datetype existed in other rows.

6) An error occurs in server side processing , the error handler displays a message.

5) now the grid row leaves the edit mode, removes dirty indicators and displays the new values changed from user but changes to be display mode with button "Edit" and "Delete".

This is confusing for the user because no clue of the current data state of the row. Is there an approach how to reset the grid row to 'Edit Mode' with button "Update" and "Cancel" and indicate the current state of the grid/row.

Upvotes: 1

Views: 4160

Answers (2)

Sundar Rajan
Sundar Rajan

Reputation: 61

This is how I achieved. I stopped the data binding from occurring once the server error is returned. So my new(Add) row remains with the data and Save, Cancel Button remains

$('#ResultGrid').data().kendoGrid.one('dataBinding', function (e) {
  e.preventDefault();
})

Refer this post. https://www.telerik.com/forums/handling-validation-errors-from-server-in-kendo-grid

Upvotes: 0

jasperli
jasperli

Reputation: 11

I eventually got this workable. The key is to either put this

elemPhoneType.select(0);   //Re-set the list as non-selection

or un-comment-out this in the JS function OnIndexChangedPhoneTypeList() but never enable both coding.

//keep the grid in edit-mode 
//var grid = $("#PhonesSubGrid").data("kendoGrid");
//grid.one("dataBinding", function (e) {
//    e.preventDefault();
//});

The view:

@using Kendo.Mvc.UI;
@using Telerik.OpenAccess;

@model IEnumerable<mdc.Models.ViewModels.ContactPhoneVM>
@{      
    var actionValidatePhoneType = Url.Action("ValidatePhoneTypeExists", "Locations");     
}

 @(Html.Kendo().Grid(Model)
    .Name("PhonesSubGrid")
    .HtmlAttributes(new { style = "text-align:left; max-width: 776px;" })
    .Columns(columns =>
    {
        columns.Bound(p => p.SITE_NUM).Visible(false);
        columns.Bound(p => p.CONTACT_ID).Visible(false);           
        columns.Bound(p => p.ddlPhoneType.TypeName).EditorTemplateName("PhoneTypeDropDownEditor").Title("Phone Type")
               .ClientTemplate("#= ddlPhoneType.TypeName #");
        columns.Bound(p => p.PHONE_NUMBER).Title("Number");
        columns.Bound(p => p.PHONE_EXT).Title("Extension");
        columns.Command(c => { c.Edit(); c.Destroy(); });         
    })    
    .Pageable(pager => pager
        .Input(true)
        .Numeric(true)
        .Info(true)
        .PreviousNext(true)
        .Refresh(true)
        .PageSizes(true))
    .Sortable()
    .Scrollable()
    .Selectable()
    .Filterable()
    .ToolBar(t => { t.Create(); })     
    .Events(events => events.Edit("SubGrid_OnRowEditing"))   
    .DataSource(        
        dataSource => dataSource                           
        .Ajax()
        .Batch(false)
        .ServerOperation(false)            
        .Model(m =>
        {
            m.Id(p => p.ID);
            m.Field(p => p.CONTACT_ID).DefaultValue(1);
            m.Field(p => p.SITE_NUM)
                    .DefaultValue(mdc.LocationContext.LocationID);
            m.Field(p => p.PHONE_NUMBER).Editable(true);
            m.Field(p => p.PHONE_EXT).Editable(true);
            m.Field(p => p.ddlPhoneType).Editable(true)
                    .DefaultValue(new mdc.Models.ViewModels.PhoneTypeListItemModel { TypeID = 0, TypeName = "Select a phone type" });
        })           
        .Create(update => update.Action("CreateContactPhoneRecord", "Locations"))
        .Update(update => update.Action("UpdateContactPhoneRecord", "Locations"))
        .Destroy(update => update.Action("DeleteContactPhoneRecord", "Locations"))
    )
)

The dropdownlist editor template:

@(Html.Kendo().DropDownList()
    .Name("ddlPhoneType") 
    .HtmlAttributes(new { required = true })
    .OptionLabel("Select a phone type")        
    .DataValueField("TypeID")  
    .DataTextField("TypeName") 
    .BindTo((System.Collections.IEnumerable)ViewData["phone_type_list"])
    .Events(events => events.Change("OnIndexChangedPhoneTypeList"))     
)

The client-side scripting:

<script type="text/javascript">
 function OnIndexChangedPhoneTypeList() {              
    var elemPhoneType = $("#ddlPhoneType").data("kendoDropDownList");

    //var inputVal = document.getElementById("phoneTypeValue");
    //inputVal.value = elemPhoneType.options.dataSource[elemPhoneType.selectedIndex - 1].TypeID


    if (elemPhoneType != null && elemPhoneType.selectedIndex > 0) {
        var selPhoneTypeId = elemPhoneType.options.dataSource[elemPhoneType.selectedIndex - 1].TypeID;
        $.ajax({
            url: '@actionValidatePhoneType',
            type: "post",
            data: {
                ContactID: selectedContactId, PhoneType: selPhoneTypeId
            },
            dataType: "json",
            success: function (result) {
                if (result == 'false' || result == false)
                {
                    alert('A phone type may only be used once for a contact.  Please choose a different phone type.');

                    elemPhoneType.select(0);   //Re-set the list as non-selection

                    //keep the grid in edit-mode 
                    //var grid = $("#PhonesSubGrid").data("kendoGrid");
                    //grid.one("dataBinding", function (e) {
                    //    e.preventDefault();
                    //});


                    return false;
                }
            },
            error: function (xhr, status) {
                alert('Validating phone type failed.  Error: ' + xhr.responseText);
            }
        });
    }
}
</script>

The controller:

public partial class LocationsController : Controller
{
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult CreateContactPhoneRecord([DataSourceRequest] DataSourceRequest request, ContactPhoneVM phone)
    {
        bool result = false;

        if (ModelState.IsValid)
        {
            try
            {
                result = _contactsRepository.AddPhone(phone.SITE_NUM, phone.CONTACT_ID, phone.PHONE_TYPE, phone.PHONE_NUMBER, phone.PHONE_EXT, "");
            }
            catch (Exception ex)
            {
                string msg = ex.Message;
            }
        }
        return Json(new[] { phone }.ToDataSourceResult(request, ModelState));
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public string ValidatePhoneTypeExists(long ContactID, long PhoneType)
    {
        long _siteId = mdc.LocationContextCompile.LocationID;
        List<long> phonetypeids = new List<long>();
        List<ContactPhoneVM> phones = _contactsRepository.GetContactPhones(ContactID, _siteId);
        foreach (ContactPhoneVM pvm in phones)
        {
            phonetypeids.Add(pvm.PHONE_TYPE);
        }

        if (phonetypeids.Contains(PhoneType))
            return "false";
        else
            return "true";
    }
}

Upvotes: 0

Related Questions