I can't use edit and create command of a Kendo Grid, because binding always fails and controller always receives a null object, even though DataSourceRequest is fine.
I used a #html.EditorForModel() and it worked fine and controller received the data. So MVC Model binding and my class aren't the problem.
Also, using F12, I can see the data being posted and it's fine too.
Any Idea about possible problem and debugging? There is an issue with all of my Kendo Grids, sometimes they post a model twice and I receive double Create on the server, which one of them always fails because of repetitive Keys. Or sometimes create will be triggered by edit command too.
I have no idea where I'm going wrong, in most scenarios the user will choose the primary key as well, so my returned model doesn't need an update.
With this particular class, server always receives two create and none of them binds correctly. The first create, posts all of the fields, and the second posts all of the navigation properties' fields too!
This is the action method:
[HttpPost]
public ActionResult Create([DataSourceRequest] DataSourceRequest request, Stock stock){
if (stock != null && ModelState.IsValid)
{
repo.Insert(stock);
return Json(new[] { stock }.ToDataSourceResult(request, ModelState));
}
else
return Json(null);
}
And the Grid:
#(Html.Kendo().Grid<Stock>()
.Name("stock")
.Columns(columns =>
{
columns.ForeignKey(x => x.CGoodCode, (IEnumerable)ViewData["Goods"], "Id", "Text");
///
columns.Command(command => { command.Edit(); command.Destroy(); });
})
.ToolBar(toolbar => {
toolbar.Create();
toolbar.Excel();
toolbar.Pdf();
})
.Editable(edit => edit.Mode(GridEditMode.PopUp))
.Sortable()
.Pageable(p => p.PageSizes(true))
.DataSource(ds =>
ds.Ajax()
.Model(model => {
model.Id(x => x.CGoodCode);
model.Id(x => x.SWhCode);
model.Id(x => x.LiIdPeriod);
model.Field(x => x.CGoodCode).DefaultValue(ViewData["GoodsDefault"]);
////
})
.Read("Read", "Stock")
.Update("Edit", "Stock")
.Create("Create", "Stock")
.Destroy("Delete", "Stock")
)
)
UPDATE
It seems Kendo Grid doesn't support composite primary keys yet!
This question helped me out! I just need to rename the parameter like:
public ActionResult Create([DataSourceRequest] DataSourceRequest request, Stock somethingElse){
Because my class contains some fields with that name, Stock!
Related
Telerik MVC grid column not identified until I add
#model IEnumerable<NTI.Data.EDC.LabUnit> as first line of my view. However when I do add this line.
Telerik MVC Grid loads with data and also shows ups all buttons. But Insert, Update and delete events not getting triggered. There is no Javascript error in the browser console window. And I also noticed there is no form action for Insert/Update/Delete buttons created by telerik. Please help.
My code ref: http://www.telerik.com/help/aspnet-mvc/telerik-ui-components-grid-editing-ajax-editing.html
View
#(
Html.Telerik().Grid(Model)
.Name("Grid")
.DataKeys(dataKeys => dataKeys.Add( c.ID))
.ToolBar(commands => commands.Insert())
.DataBinding(dataBinding => dataBinding
//Ajax binding
.Ajax()
//Home.Index renders the grid initially
.Select("LabUnits", "Lab")
//Home.Insert inserts a new data record
.Insert("LabUnitsInsert", "Lab")
//Home.Update updates an existing data record
.Update("LabUnitsUpdate", "Lab")
//Home.Delete deletes an existing data record
.Delete("LabUnitsDelete", "Lab")
)
.Columns(columns =>
{
columns.Bound(c => c.ContactName);
columns.Bound(c => c.Country);
columns.Bound(c => c.BirthDay);
columns.Command(commands => commands
.Edit()
.Delete());
})
)
Controller
public class LabController : Controller
{
public ActionResult LabUnits()
{
IEnumerable<LabUnit> lbUnit = new LabUnitDB().SelectAll();
return View(new GridModel(lbUnit));
}
[HttpPost]
[GridAction]
public ActionResult LabUnitsInsert()
{
//insert
}
[HttpPost]
[GridAction]
public ActionResult LabUnitsUpdate(int id)
{
//update
}
[HttpPost]
[GridAction]
public ActionResult LabUnitsDelete(string id){
// Delete
}
}
I was able to fix the issue. Had to replace
.DataBinding(dataBinding => dataBinding
//Ajax binding
.Ajax()
with
.DataBinding(dataBinding => dataBinding
//Server binding
.Server()
So its server binding and not Ajax.
I have a Kendo grid whereas the columns are defined as:
.Columns(columns =>
{
columns.Bound(b => b.Field);
columns.Bound(b => b.OldValue);
columns.Bound(b => b.NewValue);
columns.Bound(b => b.DateImported).Format("{0:dd-MMM-yyyy}");
columns.Bound(b => b.BuildingChangeValidationStatusType).ClientTemplate("#=BuildingChangeValidationStatusType.Value#").Width(250);
columns.Command(command => command.Custom("Update").Click("updateValidation"));
columns.Command(command => { command.Edit(); }).Width(172);
})
The BuildingChangeValidationStatusType client template is defined as:
#model Rep.Models.BuildingChangeValidationViewModel
#(Html.Kendo().DropDownList()
.Name("BuildingChangeValidationStatusType") // Name of the widget should be the same as the name of the property
.DataValueField("Id")
.DataTextField("Value")
.BindTo((System.Collections.IEnumerable)Model.BuildingChangeValidationStatuses)
)
I'm wondering how I might pass the model for the Grid to the client template so that the line:
.BindTo((System.Collections.IEnumerable)Model.BuildingChangeValidationStatuses)
)
would resolve properly. Any ideas?
I solved it a different way by passing the data I needed to the DropdownList in the client template via a javascript function. So the client template containing the dropdown is as so:
#(Html.Kendo().DropDownList()
.Name("BuildingChangeValidationStatusType") // Name of the widget should be the same as the name of the property
.DataValueField("Id")
.DataTextField("Value")
//.BindTo((System.Collections.IEnumerable)Model.BuildingChangeValidationStatuses)
.DataSource(
source => source.Read(read =>
read.Action("BuildingValidationLookups_Read", "Plan").Data("getBuildingId")
)
.ServerFiltering(true)
)
.SelectedIndex(0)
)
Notice the data source read action, it invokes the method on my "Plan" controller named: "BuildingValidationLookups_Read", but also passes the data retrieved from the "getBuildingId" javascript function which is defined as:
function getBuildingId() {
var entityGrid = $("#BuildingValidationGrid").data("kendoGrid");
var selected = entityGrid.dataItem(entityGrid.select());
return {
buildingId: selected.BuildingId
};
}
My controller method is defined as:
public JsonResult BuildingValidationLookups_Read([DataSourceRequest] DataSourceRequest request, int buildingId)
{
return Json(PopulateBuildingChangeValidationTypes(buildingId), JsonRequestBehavior.AllowGet);
}
All is well now.
Is there a way to find the Grid Name in the Controller?
I am defining the grid name in my page.
<%:
Html.Telerik().Grid<Scout.Server.UI.Web.Mvc.ViewModels.WTO.WTOListViewModel>()
.Name("GridName")
.DataKeys(keys => keys.Add(wto => wto.WTORowID))
.DataBinding(dataBinding => dataBinding.Ajax()
.Select("QueryMyGrid", "GridController")
)
.Columns(columns =>
{
I need to find the Grid name in my Action Method.
[GridAction]
public ActionResult QueryMyGrid(GridCommand command)
{
var transferOrders = transferOrderService.GetActiveTransferOrdersBySubType(
typeService.GetSubTypeByMeaning(ModelDefinitions.TypeClassMeaning.ORDER_TYPES,
ModelDefinitions.TypeMeaning.ORDER_TYPE_TRANSFER_ORDER,
Is there a way to do that?
Why do you need the Grid name ?
When you use Ajax DataBinding, the Grid will call the specified action (Grid/QueryMyGrid) and fill the grid with the returned object.
You need to return something like this
return View(new GridModel<Scout.Server.UI.Web.Mvc.ViewModels.WTO.WTOListViewModel>(transferOrders));
I have a Kendo grid set up like so:
#(Html.Kendo().Grid<ParticipatingDentalEE>()
.Name("DentalEE")
.Columns(columns =>
{
columns.Bound(p => p.State).Title("State").Width(150).EditorTemplateName("State");
columns.Bound(p => p.Count).Title("Count").Width(150);
columns.Command(c => { c.Edit(); c.Destroy(); });
})
.DataSource(dataSource => dataSource
.Ajax()
.Model(m => {
m.Id(p => p.State);
m.Field(p => p.State).Editable(true);
m.Field(p => p.Count).Editable(true).DefaultValue("");
})
.Create(update => update.Action("EditingInline_Create", "Dental"))
.Read(read => read.Action("EditingInline_Read", "Dental"))
.Update(update => update.Action("EditingInline_Update", "Dental"))
.Destroy(update => update.Action("EditingInline_Destroy", "Dental"))
)
//.Scrollable()
//.Sortable()
.Editable(e => e.Mode(GridEditMode.InLine))
)
The "State" column consists of a dropdown template that looks like this:
#(Html.Kendo().DropDownList()
.Name("States") // Name of the widget should be the same as the name of the property
.DataValueField("CODE") // The value of the dropdown is taken from the EmployeeID property
.DataTextField("NAME") // The text of the items is taken from the EmployeeName property
.BindTo((System.Collections.IEnumerable)ViewData["States"]) // A list of all employees which is populated in the controller
)
My dropdown shows up properly when I edit or create an item, but when I save the item the dropdown value does not stay in the grid. Is there something else I need to set up in order to do this?
as you say in your own comment,
.Name("States") // Name of the widget should be the same as the name of the property
which is to say, it must match the name of the column, and the column name is "State" not "States".
Obviously this is an old thread, however the fix is to use the DropDownListFor method (as opposed to the DropDownList) and not to specify a name. I suspect Kendo does some internal name matching to apply the edited value back to the model.
#model int // ...or whatever type works for your model
#(Html.Kendo().DropDownListFor(i => i)
.DataValueField("CODE")
.DataTextField("NAME")
.BindTo((System.Collections.IEnumerable)ViewData["States"]))
I'm not sure if this will fix your problem, but the editor templates for my grid didn't work correctly until I had set the UIHint decorator in the model, and the EditorTemplateName in the view.
E.g.
public class ParticipatingDentalEE {
...
[UIHint("State")] // this should be the name of your EditorTemplate
public State State { get; set; }
}
I speculate that UIHint is used for the grid in 'view' mode, while the EditorTemplateName is used while in 'edit' mode, and both are required to link the two together.
Following the patten as set out in the Telerik Mvc Grid Demo for inserting and editing, everything works up until it gets to the point where the controller method returns.
See: http://demos.telerik.com/aspnet-mvc/razor/Grid/EditingAjax?theme=vista
The methods call into my repository functions which successfully update the database; however, the return code in the demo as shown here
[AcceptVerbs(HttpVerbs.Post)]
[CultureAwareAction]
[GridAction]
public ActionResult _InsertAjaxEditing()
{
EditableProduct product = new EditableProduct();
if (TryUpdateModel(product)) {
SessionProductRepository.Insert(product);
}
return View(new GridModel(SessionProductRepository.All()));
}
Everything works up to the return line, so I tried:
return View(new GridModel(myTypeRepository.All);
return View(new GridModel(myTypeRepository.All.ToList());
return View(new GridModel(myTypeRepository.All.ToArray());
return View(new GridModel(myTypeRepository.All);
return View(new GridModel(myTypeRepository.All.ToList());
return View(new GridModel(myTypeRepository.All.ToArray());
return View(GridModel(myTypeRepository.All))
return View(GridModel(myTypeRepository.All.ToList()))
return View(GridModel(myTypeRepository.All.ToArray()))
All of which resulted in an exception that could not be followed because it points to the Telerik file: GridActionAttribute.cs.
Now because it occurs at the end of the method, I can't be sure that it is the return statment or the html.Telerik.Grid. However, as I said I followed the pattern in the demo:
#(Html.Telerik().Grid<BerettaFarms.Models.FoodKind>()
.Name("myName")
.ToolBar(commands => commands.Insert())
.DataKeys(keys => keys.Add(c => c.myTypeId))
.DataBinding(dataBinding => {
dataBinding.Ajax()
.Select("SelectAjaxEditing", "myController")
.Insert("InsertAjaxEditing", "myController")
.Update("SaveAjaxEditing", "myController")
.Delete("DeleteAjaxEditing", "myController");
})
.Columns(columns => {
columns.Bound(o => o.Name).Width(200);
columns.Bound(o => o.Description).Width(400);
columns.Command(commands => {
commands.Edit();
commands.Delete();
}).Width(200);
})
.DataBinding(dataBinding => dataBinding.Ajax().Select("AjaxIndex", "myController"))
.Editable(editing => editing.Mode(GridEditMode.InLine))
.Sortable()
.Scrollable(h => h.Height("700px"))
.Groupable()
.Filterable()
)
So if anyone knows why the rebind fails? Or if it is attributable to something else, please let me know.
AS it turns out this is one of those issues related to the tools and not the substance. When you remove all the breakpoints in this method and just let the code run it works as expected. Somehow, when in debugging mode, with breakpoints set, it throws an error an halts the application.