kendodropdownlist not binding value to model after post - asp.net-mvc-4

I'm using kendo UI for my project. I have a kendo dropdownlist that I'm populating with json. I get the values in my dropdownlist but on post, the model doesn't get the selected value of the dropdownlist. I have been stuck on it for a day with no result. I'm not sure where I'm going. Please review the code
View:
#model IEnumerable<EntityFrameworkClasses.StaggingException>
#foreach (var item in Model)
{
#(Html.Kendo().DropDownListFor(modelItem => item.Level2)
.Name("Level2")
.HtmlAttributes(new { style = "width:10%" })
.OptionLabel("Select level 2...")
.DataTextField("Text")
.DataValueField("Value")
.BindTo((System.Collections.IEnumerable)ViewBag.Level2)
)
}
#(Html.Kendo().Grid(Model)
.Name("CashExceptionsGridTest")
.Columns(columns =>
{
columns.Bound(p => p.Category).Title("Category").Width(130);
columns.Bound(p => p.EnterText1).Title("Comments").Width(130);
columns.Bound(p => p.Dateoftransaction).Title("Date").Width(130);
columns.Bound(p => p.InternalLocalAmount).Title("InternalAmt").Width(130);
columns.Bound(p => p.ExternalLocalAmount).Title("ExternalAmt").Width(130);
})
.ToolBar(toolbar =>
{
//toolbar.Template("<a class='k-button k-button-icontext' onclick='customCommand()' href='#'></span>Cutom Command</a>");
toolbar.Create(); // The "create" command adds new data items.
toolbar.Save();// The "save" command saves the changed data items.
})
.Editable(editable => editable.Mode(GridEditMode.InCell)) // Use in-cell editing mode.
.HtmlAttributes(new { style = "height: 550px;" })
.HtmlAttributes(new { style = "height: 350px;" })
.Pageable(pageable => pageable
.Input(true)
.Numeric(false)
)
.Reorderable(r => r.Columns(true))
.Sortable()
.ColumnMenu()
.Scrollable(scr => scr.Height(430))
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.ServerOperation(false)
.Batch(true) // Enable batch updates.
.Model(model =>
{
model.Id(p => p.RowID); // Specify the property which is the unique identifier of the model.
model.Field(p => p.RowID).Editable(false); // Make the ProductID property not editable.
})
.Update("Editing_Update", "MultiTab")
.Create("Editing_Create", "MultiTab")
)
)
}
I have a kendo grid below which im not including for code brevity.
Controller:
public ActionResult GetLevel()
{
IEnumerable<SelectListItem> Level2 = db2.StaggingInternalCashExceptions.Where(x=>x.LoadID==loadid).Select(c => new SelectListItem
{
Value = c.Level2.ToString(),
Text = c.Level2
}).Distinct();
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Editing_Create([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<StaggingException> results)
if (results != null && ModelState.IsValid)
{
foreach (var result in results)
var entity = new StaggingException();
entity.RowID = result.RowID;
entity.Category = result.Category; //this is a textbox in the view for which i get the value
entity.Level1 = result.Level1; //gives null
//I'm adding those values to the db. Didn't include all that for the sake of keeping it short.
}
}
The grid has batch editing, once i hit on save changes, the grid's data is posted to the controller where i can see it in results. I cannot get the dropdown value though.
Any ideas or leads please.
Thank you.

Late to this post but I have had a similar issue, for those with the same problem of the value not being posted in the model, if your model value is a nullable int? (can't see from the above post...) then you need to configure the DropDownListFor as below to avoid the default value binding behavior to update the field with the selected item when the initial value is null. Hope this helps someone.
Html.Kendo().DropDownListFor(m => m)
.HtmlAttributes(new { data_value_primitive = "true" })

Related

Kendo MVC Group Paging

I have a kendo grid that shows around more than a million records and in its initial load, it takes more than a minute to display.
how can I use the kendo Grouppaging feature to minimize the load time so the page loads the group items on demand? Loading of the group items happens when a group is expanded. Any other options to speed up are also appreciated.
what it basically does is that based on the dropdown value it draws the kendo grid
<div>
#(Html.Kendo().DropDownList()
.Name("samplegrid")
.DataTextField("samplegrid")
.DataValueField("samplegrid")
.HtmlAttributes(new { style = "width:90%" })
.DataSource(source => source
.Custom()
.Transport(transport => transport
.Read(read =>
{
read.Action("infoDropdown_Read",
"sample").Type(HttpVerbs.Get);
})))
.Events(e =>
{
e.Select("onCheckSelectForDetail");
})
)
</div>
Here is the code for the Grid.
#(Html.Kendo().Grid<Portal.Data.Models.InfoModel>()
.Name("gridSummary")
.DataSource(dataSource => dataSource
.Ajax()
.Aggregates(aggregates =>
{
aggregates.Add(p => p.OutstandingCount).Sum();
})
.Group(groups =>
{
groups.Add(p => p.OfficeNumber);
})
.Batch(true)
.ServerOperation(false)
.Sort(sort => sort.Add(column => column.Date))
)
.Columns(columns =>
{
columns.Bound(c => c.OfficeState).Width(70)
.Title("xxxx");
columns.Bound(c => c.OfficeNumber).Width(70)
.Title("zzzz");
columns.Bound(c => c.OutstandingCount).Width(60)
.Title("yyyy");
})
)
and the controller looks like
public async Task<IActionResult> infoDropdown_Read(){
try{
var infoListSR = await _eService.GetInfoListAsync();
if (infoListSR.Failed){
Log.Error($"Unexpected error occured due to
{infoListSR.ErrorData.ApplicationErrorMessage}");
throw new DataException($"{infoListSR.ErrorData.ApplicationErrorMessage}");
}
return Json(infoListSR.ResultData, new JsonSerializerOptions() {
PropertyNameCaseInsensitive = false});
}
catch (Exception ex){
Log.Error($"Username: {User.Identity.Name} - Dropdown list Failed with
Exception: {ex}");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
An option to boost the performance, you could use the server grouping along with virtualization:
Demo

How can i create detail page in asp.net core MVC

I have the following code to create master-detail relationship in asp.net core. i have a kendo UI Grid but i wanted to pass data to the detail page of the selected record.
Product Controller look like as follows
GetProduct Action
[HttpGet]
public async Task<IActionResult> Getproduct()
{
var product= await ProductService.Getproduct();
return Json(products);
}
Detail Action
public IActionResult Detail()
{
return View();
}
Index.cshtml
#inject IProductService productService
#(Html.Kendo().Grid<ProductList>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(p => p.productCode).Width(120);
columns.Bound(p => p.productCode).ClientTemplate( "Details");
columns.Bound(p => p.productName).Width(120);
})
.Groupable()
.ToolBar(t => t.Search())
.Sortable()
.PersistSelection()
.Filterable()
.Pageable(pageable => pageable
.ButtonCount(5)
.Refresh(true)
.PageSizes(new[] { 5, 10, 20 }))
.DataSource(dataSource => dataSource
.Custom()
.Transport(transport => transport
.Read(read => read.Action("Getproduct", "Product")
)) ))
I wanted to create a link to a detail page and show the selected record information in detail.cshtm, I'm able to pass the productCode with the url as http://localhost:XXX/Product/product/Detail/800013 but I need help displaying Product Name in detail page, I used ClientTemplate as follows but i need some help displaying other information's
columns.Bound(p => p.productCode).ClientTemplate("Show Details");

Kendo Grid ClientTemplate conditional column

I am working with ASP.NET MVC 4 with Kendo UI(kendo grid).Below is sample code of Kendo Grid -
#(Html.Kendo().Grid(Model.Users).Name("Grid").Columns(columns =>
{
columns.Bound(p => p.FirstName);
columns.Bound(p => p.LastName);
columns.Bound(p => p.UserName);
columns.Bound(p => p.Email);
columns.Bound(o => o.IsActive).ClientTemplate(links).Title("Action");
})
In the above code my IsActive column have some links for Actions like Edit,Update,Delete.And i am adding those links into Kendo grid by links variable.And I want to use links variable on the basis of conditions.Means i want conditional ClientTemplate here.
So anyone suggest how can make a conditional ClientTemplate in kendoGrid ?
2) Also i want to add condition on the basis on the bool field value of my model(Model.Users).
So i want to know how we can get that field from Model.Users model in kendo grid for each row.Like -
.ClientTemplate(if(IsAdmin && ViewBag.IsActive){.....} else{....})
You can try like below code..may be this help you..
columns.Bound(p => p.Active).ClientTemplate("\\#if('#=Active#'=='Y') {\\<input type='button' value='OK' />\\}\\#");
or may be use
"#= (Active) ? ' ' : 'your code here' #"
You can use the following piece of code:
#(Html.Kendo().Grid(Model.Users).Name("Grid").Columns(columns =>
{
columns.Bound(p => p.FirstName);
columns.Bound(p => p.LastName);
columns.Bound(p => p.UserName);
columns.Bound(p => p.Email);
columns.Bound(o => o.IsActive).ClientTemplate("#if(IsActive){#<a href='javascript:void(0)' >Edit</a>#}#").Title("Action");
})
I'm concatenating a name and using a javascript function which made condition testing much easier, plus you can get access to multiple fields:
cshtml:
#(Html.Kendo().Grid<Debtors>()
.Name("Debtors")
.Columns(columns =>
{
columns.Bound(c => c).Title("Name").ClientTemplate("#=showName(data)#");
columns.Bound(c => c.Busname);
...
})
...
)
js:
function showName(data) {
var returnName = "";
if (data.Lname) {
returnName = data.Lname;
if (data.Fname) {
returnName += ", " + data.Fname;
if (data.Mi) {
returnName += " " + data.Mi;
}
}
}
return returnName;
}

Kendo MVC Grid not passing parent ID to ClientID Template, when creating Child record

I'm having a problem adding a child record in my hierarchical grid. It won't pass over the HeaderId from the parent in the grid.
Can anyone spot an issue, or am I trying to do something that isn't possible?
Thanks.
Here's the controller action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult BillDetail_Create(BillDetail billDetail, int billHeaderId)
{
if (billHeaderId == 0)
{
ModelState.AddModelError("billHeaderID", "add bill header first");
}
if (billDetail != null && ModelState.IsValid)
{
var target = new BillDetail
{
Category = billDetail.Category,
Description = billDetail.Description,
Amount = billDetail.Amount,
BillHeaderId = billHeaderId,
BillDetailId = SessionBillDetails.Max(d => d.BillDetailId) + 1
};
//Get next Id in sequence
billDetail.BillDetailId = target.BillDetailId;
SessionBillDetails.Add(target);
}
return Json(new[] { billDetail }.ToDataSourceResult(new DataSourceRequest(), ModelState));
}
And here's the view:
#(Html.Kendo().Grid<BillHeader>()
.Name("BillHeaders")
.Columns(columns =>
{
columns.Bound(h => h.BillHeaderId);
columns.Bound(h => h.Category);
columns.Bound(h => h.Description);
columns.Bound(h => h.Amount);
})
.Pageable()
.Selectable(selectable => selectable
.Mode(GridSelectionMode.Multiple)
.Type(GridSelectionType.Row))
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(6)
.Events(events => events.Error("error_handler"))
.Read(read => read.Action("BillHeaders_Read", "Bill"))
)
.Events(events => events.DataBound("dataBound"))
.ClientDetailTemplateId("BillDetails")
)
<script id="BillDetails" type="text/kendo-tmpl">
#(Html.Kendo().Grid<BillDetail>()
.Name("BillDetails_#=BillHeaderId#")
.Columns(columns =>
{
columns.Bound(d => d.BillHeaderId).Width(50);
columns.Bound(d => d.BillDetailId).Width(70);
columns.Bound(d => d.Category).Width(70);
columns.Bound(d => d.Description).Width(150);
columns.Bound(d => d.Amount).Width(80);
columns.Command(command =>
{
command.Edit();
command.Destroy();
}).Width(75);
})
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(10)
.Model(model =>
{
model.Id(d => d.BillDetailId);
model.Field(d => d.BillDetailId).Editable(false);
})
.Events(events => events.Error("error_handler"))
.Read(read => read.Action("BillDetails_Read", "Bill", new { billHeaderId = "#=BillHeaderId#" }))
.Update(update => update.Action("BillDetail_Update", "Bill"))
**.Create(create => create.Action("BillDetail_Create", "Bill", new { billHeaderId = "#=BillHeaderId#" }))**
.Destroy(destroy => destroy.Action("BillDetail_Destroy", "Bill")))
.Pageable()
.ToolBar(tools => tools.Create())
.ToClientTemplate()
)
</script>
Managed to finally fix this. Unbelievable really....
I named the parameter in my controller (and view) to be "id"
So Controller:
public ActionResult BillDetail_Create(BillDetail billDetail, int id)
And View:
.Read(read => read.Action("BillDetails_Read", "Bill", new { id = "#=BillHeaderId#" }))
.Update(update => update.Action("BillDetail_Update", "Bill"))
.Create(create => create.Action("BillDetail_Create", "Bill", new { id = "#=BillHeaderId#" }))
.Destroy(destroy => destroy.Action("BillDetail_Destroy", "Bill")))
For a better explanation of why that worked:
This can occur if the BillDetail class has a property with the same name. In this case the MVC model binder will override the value sent with the request route values with the value sent as form data for the grid model. If this is the case then the simplest option to avoid the problem would be to rename the parameter. that is why renaming to ID worked.

Updating Kendo grid row on column value change

I am working on an MVC .Net Framework v4.5 site using Kendo MVC controls. One of the pages uses a Kendo grid which is bound to the view model. When I edit a row, there is a field which uses a dropdownlist control, and when the selection is changed, the remaining fields in the row should be updated to reflect that newly selected item..I am doing this with a JSON call which then returns the new view model to use for that row. However, I cannot figure out how to tell the grid to use the data that was returned from that JSON call. Any ideas?
EDIT:
I have attached some code. The issue now is that I can get the grid's datasource to 'refresh', but in the UpdateGridSource jscript function, at the grid.dataSource.read() line, the grid is now out of edit mode, and if I go to edit the row, the data is reverted back to how it originally was
(VIEW)
#(Html.Kendo().Grid<RedFile.Models.QuickQuoteItemView>()
.Name("QuoteItems")
.Columns(c =>
{
c.Bound(p => p.Id).Hidden();
c.Bound(p => p.Description).EditorTemplateName("Combobox");
c.Bound(p => p.ItemQty);
c.Bound(p => p.ItemPrice).Format("{0:c}");
c.Bound(p => p.Total).ClientTemplate("#= kendo.format('{0:c}', Total) #").FooterHtmlAttributes(new { style = "text-align:right;" }).ClientFooterTemplate("#= kendo.format('{0:c}', sum)#").HtmlAttributes(new { style = "text-align:right;" }).Width(100);
c.Command(cmd => { cmd.Edit(); cmd.Destroy(); }).Title("Commands").Width(200);
})
.ToolBar(tb => tb.Create())
.ClientDetailTemplateId("subitems")
.Editable(eb => eb.Mode(GridEditMode.InLine).CreateAt(GridInsertRowPosition.Bottom))
.Events(e=>e.Edit("editGrid"))
.Scrollable()
.DataSource(ds => ds
.Ajax()
.ServerOperation(false)
.Aggregates(a =>
{
a.Add(p => p.LineTotal).Sum();
a.Add(p => p.Total).Sum();
})
.Model(model =>
{
model.Id(p => p.Id);
model.Field(p => p.LineTotal).Editable(false);
model.Field(p => p.ItemPrice).Editable(true);
})
.Read(read => read.Action("GridSelect", "QuickQuote", new { qqid = Model.Id })).ServerOperation(false)
.Create(create => create.Action("GridCreate", "QuickQuote", new { qqid = Model.Id }))
.Update(update => update.Action("GridUpdate", "QuickQuote"))
.Destroy(destroy => destroy.Action("GridDelete", "QuickQuote"))
)
)
<script type="text/javascript">
function dropDownSelectionChanged(e) {
var dataItem = this.dataItem(e.item.index());
UpdateGridSource(dataItem.Value);
}
function UpdateGridSource(DropDownValue) {
var grid = $("#theGrid").data("kendoGrid");
grid.dataSource.transport.options.read.url = '/Controller/refreshGridDataSource?selection=' + DropDownValue;
grid.dataSource.read();
}
</script>
(CONTROLLER)
public JsonResult refreshQuickQuoteTest2([DataSourceRequest] DataSourceRequest request, string selection)
{
QuickQuoteItem qqi = db.QuickQuoteItems.FirstOrDefault(p => p.ItemID == selection);
QuickQuote quickQuoteOriginal = qqi.QuickQuote;
QuickQuoteItemView qqiv = new QuickQuoteItemView();
IEnumerable<QuickQuoteItemView> return2;
qqiv.Id = qqi.Id;
qqiv.ItemID = qqi.ItemID;
qqiv.ItemPrice = qqi.ItemPrice;
if (Session["quickQuote"] != null)
{
QuickQuote qq = (QuickQuote)(Session["quickQuote"]);
if (Session["editingQuickQuoteId"] != null)
{
int row = Convert.ToInt32(Session["editingQuickQuoteId"]);
foreach (var item in qq.QuickQuoteItems)
{
if (item.Id == row)
{
QuickQuoteItem test = new QuickQuoteItem();
StandardItem stdItem = new StandardItem();
stdItem = db.StandardItems.Find(selection);
item.ItemPrice = stdItem.Price;
item.Description = stdItem.Description;
item.ItemID = stdItem.ItemId;
}
}
}
return2 = QuickQuoteItemViewItems(qq);
}
else
{
return2 = QuickQuoteItemViewItems(quickQuoteOriginal);
}
return Json(return2.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
You can use the grids Ajax binding to call your controller Update Action method
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(false)
.Model(model => model.Id(p => p.SampleId))
.Update(read => read.Action("SampleGrid_Update", "Controller")))
Then you need to decorate your methods datasource parameter with the DataSourceRequest attribute and return the ModelState as a DataSourceResult
[HttpPost]
public ActionResult SampleGrid_Update([DataSourceRequest] DataSourceRequest dsRequest, IEnumerable<SampleViewModel> viewModel)
{
if (viewModel != null && ModelState.IsValid)
{
// other code goes here...
}
return Json(ModelState.ToDataSourceResult());
}
You can view the samples and documentation on the Kendo website
Edit
You can bind your ajax call to the change event of your dropdownlist and when this returns you can refresh the grid data from the server using
$("#gridId").data("kendoGrid").dataSource.read();