Kendo UI Grid CRUD firing multiple times - asp.net-mvc-4

I have a kendo UI grid in my page. Below is the code of kendo UI grid with CRUD datasource actions.
#(Html.Kendo().Grid<Gts.GlaspacLX.Web.ViewModel.ProductViewModel>()
.Name("xyzGrid")
.Columns(columns =>
{
columns.Bound(p => p.SelectedProductCategory).EditorTemplateName("_ProductDropDownList").Title("Product Category").HtmlAttributes(new { #tabindex = "8" });
columns.Bound(p => p.Name).Width(130).Title("% Off").HtmlAttributes(new { #tabindex ="9" });
columns.Bound(p => p.Rate).Width(130).HtmlAttributes(new { #class = "prodDiscRtAlign",#tabindex= "10" });
columns.Bound(p => p.Hours).Width(130).HtmlAttributes(new { #class = "prodDiscRtAlign",#tabindex= "11" });
if (SiteContext.CurrentUser.HasPrivilege(PrivilegeNames.Maintenance, PermissionNames.DELETE))
{
columns.Command(command => { command.Destroy(); }).Width(110).Title("Delete").HtmlAttributes(new { #tabindex = "12" });
}
})
.ToolBar(commands =>
{
commands.Create();
commands.Save();
})
.Editable(editable => editable.Mode(GridEditMode.InCell).CreateAt(GridInsertRowPosition.Bottom))
.Sortable()
.Navigatable()
.DataSource(dataSource => dataSource
.Ajax()
.Batch(true)
.ServerOperation(false)
.Model(model =>
{
model.Id(p => p.ProductID);
model.Field(p => p.SelectedProductCategory).DefaultValue(ViewBag.DefaultProductCategory);
})
.Read(read => read.Action("Product_Read", "ProductController"))
.Update(update => update.Action("Product_Update", " ProductController "))
.Create(create => create.Action("Product_Create", " ProductController "))
.Destroy(update => update.Action("Product_Destroy", " ProductController ")
))
.Events(e => e.Edit("proField").DataBound("boundProductChange"))
)
Below is the screen shot of "Save" button just after the kendo grid. It's responsible for any create/update operation of the page.
My problem is once I clicked on Save button for any create or update operation its posting the action method twice. You can see the console of above screen shot.
Below is the piece of the code of my controller's action method:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Product_Create([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<ProductViewModel> product){
return Json(results.ToDataSourceResult(request, ModelState));
}
Below is proField function code :-
function proField(e) {
var defaultproduct = $("#DefaultProductCategory").val();
defaultproduct = "\n" + defaultproduct + "select ";
if (e.model.SelectedProductCategory == "Default" && (e.sender._editContainer[0].textContent == defaultproduct || e.sender._editContainer[0].textContent == "\n select ")) {
e.sender._editContainer[0].disabled = true;
e.sender._editContainer[0].children[0].textContent = "Default";
e.sender.table[0].rows[1].cells[1].click();
e.sender.table[0].rows[1].cells[4].disabled = true;
}
}

after insert any record you should return primary(Id) key to view.
see kendo demo.

Related

Display two values foreign key in kendo Grid MVC

I'm so tired to resolve this problem. I just want to display two values, For example in columns.Foreignkey. Showing Name and Id on the same columns. How do I do this?
#(Html.Kendo().Grid<Project_Test.Models.Workcenter>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(p => p.WorkcenterCode)
.Width(80)
.Title("Workcentercode")
.ClientTemplate("");
columns.Bound(p => p.WorkCenterSection)
.Width(84)
.Title("WorkcenterSection");
columns.ForeignKey(p => p.WorkcenterCategory,
(System.Collections.IEnumerable)ViewBag.WorkcenterCategory,
"WorkcenterCategoryID",
"WorkcenterCategoryName")
.Title("Category")
.Width(200);
//command.Custom("Details").Click("showDetails").HtmlAttributes(new { #class = "k-font-icon k-i-insert-unordered-list " });
command.Custom(" ")
.Click("showDetails")
.HtmlAttributes(new { #class = "btn btn-default btn-xs glyphicon glyphicon-list-alt" })
.Width(230);
})
//.Events(e => e.DataBound("onDataBound"))
.ToolBar(toolbar => toolbar.Create())
.Editable(editable => editable
.Mode(GridEditMode.PopUp)
.TemplateName("Workcent")
.DisplayDeleteConfirmation("Are you sure to delete this Workcenter")
)
.Sortable()
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(true)
.Messages(messages => messages.Refresh("Click to refresh"))
.ButtonCount(8)
)
.Groupable()
.Resizable(resize => resize.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
.Selectable()
.Scrollable()
.HtmlAttributes(new { style = "height:580px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Events(events => events.Error("error_handler"))
.Model(model =>
{
model.Id(p => p.WorkcenterID);
model.Field(p => p.WorkcenterID).Editable(true);
model.Field(p => p.UpdatedBy).DefaultValue(User.Identity.Name);
model.Field(p => p.CreatedBy).DefaultValue(User.Identity.Name);
})
.Create(update => update.Action("Employee_Create", "Home"))
.Read(read => read.Action("List", "Home"))
.Update(update => update.Action("Products_Update", "Home"))
.Destroy(update => update.Action("adress_Destroy", "Home"))
)
)
The ForeignKey column is just displaying the WorkcenterCategoryName associated with the corresponding WorkcenterCategoryID from the bound list(ViewBag.WorkcenterCategory).
Just make the WorkcenterCategoryName of each element in ViewBag.WorkcenterCategory contain the text you actually want to display, i.e.
"IDOfSelectedItem (TextOfSelectedItem)"
instead of just
"TextOfSelectedItem"
Edit to be more specific:
I'm assuming your server action is filling ViewBag.WorkcenterCategory something like:
ViewBag.WorkcenterCategory = GetWorkcenterCategories()
.Select(x => new
{
WorkcenterID = x.ID,
WorkcenterName = x.Name
});
Let's say this returns the list:
{ WorkcenterID = 1, WorkcenterName = "One" },
{ WorkcenterID = 2, WorkcenterName = "Two" }
Then the ForeignKey column maps a particular key to the corresponding item in the list bound to it (ViewBag.WorkcenterCategory) and the text value associated to the key will be displayed, whatever is contained in the WorkcenterName field.
i.e. value of 1 will display "One" in the grid.
If you want to display more than just the name of the Workcenter, then set the WorkcenterName of the objects in the ViewBag.WorkcenterCategory list to the text you want to have displayed, i.e.:
ViewBag.WorkcenterCategory = GetWorkcenterCategories()
.Select(x => new
{
WorkcenterID = x.ID,
WorkcenterName = x.ID + " (" + x.Name + ")"
});
This would return the list:
{ WorkcenterID = 1, WorkcenterName = "1 (One)" },
{ WorkcenterID = 2, WorkcenterName = "2 (Two)" }
And a value of 1 would now display "1 (One)" instead of just "One".

Kendo grid foreign key Column in popup show as drop downlist

i have three tables tbl_admin_group ,tbl_admin_role, tbl_admin_groupRole the primary key of group and role are foreign keys in grouprole.
now i have a form in which i want to display foreign keys in dropdownlist first
for tbl_admin_role. image link given below
Controller Action Method
public ActionResult GetGroupRole()
{
dbcontext.Configuration.ProxyCreationEnabled = false;
List<TBL_ADMIN_GROUP_ROLE> lst = dbcontext.TBL_ADMIN_GROUP_ROLE.Where(x => x.IsDeleted == 0).ToList();
also try this
//List<TBL_ADMIN_GROUP_ROLE> lst = dbcontext.TBL_ADMIN_GROUP_ROLE.Include(r => r.TBL_ADMIN_ROLE).Include(g => g.TBL_ADMIN_GROUP).ToList();
ViewData["rolesList"] = lst;
return View(lst);
}
Razor view
#(Html.Kendo().Grid<TBL_ADMIN_GROUP_ROLE>().Name("Grid")
.Columns(columns =>
{
columns.Template(t => { }).Title("S.No").ClientTemplate("#= renderNumber(data) #");
columns.ForeignKey(p => p.RoleID, (System.Collections.IEnumerable)ViewData["rolesList"], "RoleID", "RoleName")
.Title("Role").Width(200).EditorTemplateName("RolesDropDown");
columns.Bound(gp => gp.GroupID).Width(200).Title("Group ID");
columns.Command(command => { command.Edit(); command.Destroy(); }).Title("Actions");
})
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(10)
.Model(model => model.Id(gp => gp.GroupRoleID))
.Read(read => read.Action("GroupRole_Read", "Security"))
.Update(up => up.Action("UpdateGroupRole", "Security"))
.Destroy(update => update.Action("DeleteGroupRole", "Security")))
.Pageable(pageable => pageable
.PageSizes(true)
.ButtonCount(5))
.Selectable()
.Sortable()
.Editable(ed => ed.Mode(GridEditMode.PopUp).TemplateName("Update Group Role"))
.Events(e => e.Edit("onEdit"))
.Events(ev => ev.DataBound("resetRowNumber"))
)
i also trying with editor template but failed. please help me . thank in advance.
Editor Template
#model int
#(Html.Kendo().DropDownListFor(m => m)
.AutoBind(false)
.OptionLabel("Select Role...")
.DataTextField("RoleName")
.DataValueField("RoleID")
.DataSource(dataSource =>
{
dataSource.Read(read => read.Action("GetRoles", "Security"))
.ServerFiltering(true);
})
)
enter image description here

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();

How the pop up works in the KendoUI grid and how to bring the controls in the pop up in KendoUI ajax grid for MVC4

How the popup window works when the edit button is click and how to bring the three Combobox in the popup. I am really confused with the below code
Client side Code
//show server errors if any
function error_handler(e) {
if (e.errors) {
var message = "Errors:\n\n";
$.each(e.errors, function (key, value) {
if ('errors' in value) {
$.each(value.errors, function () {
message += this + "\n\n";
});
}
});
alert(message);
}
}
#(Html.Kendo().Grid(Model)
.Name("SchoolGrid")
.Columns(columns =>
{
columns.Bound(p => p.SchoolID).Width("80px");
columns.Bound(p => p.Name);
columns.Bound(p => p.Campus).Width("90px");
columns.Bound(p => p.StateCode).Width("90px");
columns.Bound(p => p.SectorCode).Width("95px");
columns.Bound(p => p.MDISurveyStartDate).ClientTemplate("#= (MDISurveyStartDate == null) ? 'Not Set' : kendo.toString(MDISurveyStartDate, 'dd/MM/yyyy') #").Width("90px");
columns.Bound(p => p.MDISurveyEndDate).ClientTemplate("#= (MDISurveyEndDate == null) ? 'Not Set' : kendo.toString(MDISurveyEndDate, 'dd/MM/yyyy') #").Width("90px");
columns.Command(command => { command.Edit(); command.Destroy(); }).Width("190px").HtmlAttributes(new { style = "text-align:center" });
})
.ToolBar(tb => tb.Create().Text("Add New School"))
.Editable(ed => ed.Mode(GridEditMode.PopUp).TemplateName("EditSchool").Window(w => w.Title("Add/Edit School Details").Name("editWindow").Width(600)))
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id(p => p.ClientID))
.Events(e => e.Error("error_handler"))
.Read("Read_Schools", "School")
.Update("Update", "School")
.Create("Create", "School")
.Destroy("Destroy", "School")
)
)
Server Side Code:-
[HttpPost]
public ActionResult Update([DataSourceRequest] DataSourceRequest request, School school)
{
try
{
if (ModelState.IsValid)
{
string errMsg = "";
if (!_Service.UpdateSchool(school, out errMsg))
ModelState.AddModelError("UpdateSchool", errMsg);
}
}
catch (Exception ex)
{
ModelState.AddModelError("UpdateSchool", ex.Message);
}
return Json(ModelState.ToDataSourceResult());
}
There is code library which shows how to manipulate the content of the Window. Rest of the editing is possible through the edit event of the Grid (check documentation).