Monday, May 25, 2015

Kendo UI MVC Grid Q&A

Q: the controller "add" action is triggered multiple times after add more than one records
A: need to set the Model.Id in the DataSource for the grid. otherwise all new record will have id=0 which causes the controller action be triggered multiple times.

Q: how to disable batch update
A: should not have command.Save() in the toolbar

Q: server bound vs ajax bound
A: server bound: default binding for Kendo Grid, to bind the grid with data you just need to set its data source and render the view
     ajax bound: Kendo Grid will make ajax requests when doing paging, sorting, filtering or saving data

Q: how to customize the way a property is displayed in a grid bound column
A: server bound: use the Template method
     Ajax bound: use the ClientTemplate method

Q: How to send values to the action method when binding the grid
A:
If the grid is server bound the overload method which accepts route values should be used.

Example: Send Additional Data In Server Bound Grid

// -- removed for brevity
.DataSource(dataSource => dataSource.Server()
    .Read(read => read.Action("Read", "Home", new { userID = (int)ViewData["UserID"] }))
)
// -- removed for brevity


If the grid is ajax bound the Data method should be used to specify the name of the JavaScript
 function which will return the additional data.

Example: Send Additional Data In Ajax Bound Grid

// -- removed for brevity
.DataSource(dataSource => dataSource.Ajax()
    .Read(read => read
        .Action("Read", "Home")
        .Data("additionalData")
    )
)
// -- removed for brevity  Q: During Edit mode, get error: An exception of type 'System.NotSupportedException' occurred in Kendo.Mvc.dll but was not handled in user codeAdditional information: There is no DataSource Model Id property specified.
A: Editing requires to set an ID field via the DataSource Model configuration e.g.
.DataSource(dataSource => dataSource
    .Ajax()
    .Model(model =>
        {
            model.Id(o => o.MyIDField);
        })
Please check the following documentations topics for information on how to setup the grid and the action methods in the different editing modes:

Friday, May 22, 2015

Telerik ASP.Net MVC model binding

Spend a full day working on model binding using KendoUI ASP.NET MVC grid component, the problem is as following:

there are two view models defined:

public class AccountViewModel
    {
        [Key]
        public int AccountId { get; set; }

        [StringLength(10)]
        [DisplayName("Account")]
        public string AccountCode { get; set; }

        [StringLength(100)]
        [DisplayName("Account name")]
        public string AccountName { get; set; }

        [Display(Name = "Account type")]
        public int? AccountTypeId { get; set; }

        [UIHint("ClientAccountType")]
        [Display(Name = "Account Type")]
        public AccountTypeViewModel AccountType { get; set; }

        public bool Inactive { get; set; }
    }

public class JournalEntryTypeAccountViewModel
    {
        [Key]
        public int JournalEntryTypeAccountId { get; set; }

        public int JournalEntryTypeId { get; set; }

        [Required]        public int? AccountId { get; set; }

        [DisplayName("Account")]
        public string AccountCode { get; set; }

        [DisplayName("Account name")]
        public string AccountName { get; set; }

        [Display(Name = "Account type")]
        public string AccountTypeName { get; set; }

        public bool Inactive { get; set; }

        [UIHint("ClientAccount")]
        public AccountViewModel Account { get; set; }
    }

and now I define the grid as following:
@(Html.Kendo().Grid()
    .Name("gridJournalEntryTypeAccount")
    .Columns(columns =>
    {
        columns.Bound(c => c.Account).ClientTemplate("#=Account.AccountCode#").Width(80);
        columns.Bound(c => c.AccountName).Width(240);
        columns.Bound(c => c.AccountTypeName).Width(100);
        columns.Bound(c => c.Inactive).Width(60).ClientTemplate(
            "                "# if (Inactive) { #" +
                    "checked='checked'" +
                "# } #" +
            "/>");
        columns.Command(command =>
        {
            command.Edit();
            command.Destroy();
        }).Width(80);
    })
    .ToolBar(toolBar =>
        {
            toolBar.Create();
        })
    .Editable(editable => editable.Mode(GridEditMode.InLine))
    .DataSource(dataSource => dataSource
        .Ajax()
        .ServerOperation(false)
        .PageSize(20)
        .Model(model =>
        {
            model.Id(p => p.JournalEntryTypeAccountId);
            model.Field(p => p.Account).DefaultValue(ViewData["defaultAccount"] as AccountViewModel);
        })
        .Read(read => read.Action("GetJournalEntryTypeAccounts", "JournalEntryType", new { journalEntryTypeId = journalEntryTypeId }))
        .Create(create => create.Action("AddAccount", "JournalEntryType", new { journalEntryTypeId         .Update(update => update.Action("UpdateAccount", "JournalEntryType"))
        .Destroy(destroy => destroy.Action("RemoveAccount", "JournalEntryType", new { journalEntryTypeId = "#=JournalEntryTypeId#", accountId = "#=AccountId#" }))
    )
    .Pageable()
    .Sortable())
 

in the controller action, I have the following:
        [AcceptVerbs(HttpVerbs.Post)]
        public JsonResult AddAccount([DataSourceRequest] DataSourceRequest request,
            JournalEntryTypeAccountViewModel account)
        {
            ......

            return Json(new[] { account }.ToDataSourceResult(request, ModelState));
        }
 
somehow, the account object always getting null on it's account sub-object, spending a whole day to find the problem ...... then eventually works after rename variable name from account to jeAcct

What a Joke!