tab order is not working in Cell editing Kendo UI Grid - asp.net-mvc-4

I am using Kendo UI Grid.And i want to do InCell editing on it.The InCell editing is working well.And once i click on "Add New Record" button then it shows textbox for the first column "Name".
My problem is when i press tab after putting value on "Name" field then its not shifting into second field "Description".And the tab order should work there.
Below is the piece of code for Kendo Grid :-
#using Gts.GlaspacLX.Web.App_Start;
#using Gts.GlaspacLX.ListValues;
#using System.Collections;
#using Kendo.Mvc.UI
#*<script src="#Url.Content("~/Scripts/jquery-ui-1.8.18.min.js")"></script>*#
<script type="text/javascript" src="../../Scripts/js/Product/Category.js"></script>
<style>
.k-dirty { display:none; }
</style>
<fieldset>
<form>
<div id="divProduct" style="display: none;">
#(Html.Kendo().Grid<Gts.GlaspacLX.Web.ViewModel.ProductViewModel>()
.Name("ProductGrid")
.Columns(columns => {
columns.Bound(p => p.Name).Width(50);
columns.Bound(p => p.Description).Width(200);
columns.Command(command => { command.Destroy(); }).Width(75);
columns.Bound(p => p.ID).Hidden();
})
.ToolBar(commands => {
commands.Create();
commands.Save();
})
.Editable(editable => editable.Mode(GridEditMode.InCell))
.DataSource(dataSource => dataSource
.Ajax()
.Batch(true)
.ServerOperation(false)
.Model(model => {
model.Id(p => p.ID);
})
.Read(read => read.Action("ProductEditingInline_Read", "Product"))
.Create(create => create.Action("ProductEditingInline_Create", "Product"))
.Update(update => update.Action("ProductEditingInline_Update", "Product"))
.Destroy(destroy => destroy.Action("ProductEditingInline_Destroy", "Product")
)
.Events(events => events.Change("onProductChange"))
// .Events(events => events.Error("error_handler"))
)
)
<input type="button" value="Cancel" onclick=" $('.k-button.k-button-icontext.k-grid-cancel-changes').click(); $('#productWindow').data('kendoWindow').close(); " />
<input type="button" value="Save" onclick=" SaveProductChanges(); " />
</div>
</form>
</fieldset>
}
Can anyone help me out on this ?

You'll want to use the navigatable option of the grid. Following is a jsfiddle example I've built: Kendo Grid Example with keyboard navigation. In MVC the navigatable option is turned on by calling .Navigatable() on the grid (see example below):
#(Html.Kendo().Grid<TestModel>()
.Name("TestGrid")
.Columns(columns =>
{
columns.Bind(c => c.DisabledString);
columns.Bind(c => c.Description);
columns.Bind(c => c.TestInvisibleDate);
columns.Bind(c => c.TestDate);
columns.Bind(c => c.AllExpressions);
})
.HtmlAttributes(new { style = "height:550px;" })
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Sortable()
.Scrollable(s => { s.Enabled(true); s.Virtual(true); })
.Pageable(p => p.Enabled(false))
.Mobile(MobileMode.Disabled)
.Navigatable()
.Resizable(s => s.Columns(true))
.Reorderable(c => c.Columns(true))
.DataSource(dataSource => dataSource
.Ajax()
.Batch(true)
.PageSize(50)
.ServerOperation(false)
.Model(model =>
{
model.Id(e => e.UniqueId);
})
)
)
This help?

Related

ASP.NET Core - Kendo Dialog: How to stop modal window from going to top of page

Whenever the modal window pops up, it goes to the top of the page like so:
https://i.imgur.com/6DDP3Ic.gif
Self contained telerik project https://filebin.net/wgcuasrr6uhejmrv
How do I prevent it from going to the top of page?
Here's the code, the delete confirmation dialog goes to the top of page:
<div class="row">
<div class="col-12">
#(Html.Kendo().Grid<TelerikAspNetCoreApp7.Models.OrderViewModel>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(p => p.OrderID).Filterable(false);
columns.Bound(p => p.Freight);
columns.Bound(p => p.OrderDate).Format("{0:MM/dd/yyyy}");
columns.Bound(p => p.ShipName);
columns.Bound(p => p.ShipCity);
columns.Command(command =>
{
command.Custom("Destroy")
.Click("showDeleteConfirmation")
.HtmlAttributes(new { style = "width:40%" });
}).Width("15%");
})
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.HtmlAttributes(new { style = "height:550px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Read(read => read.Action("Orders_Read", "Grid"))
.Destroy(read => read.Action("Orders_Read", "Grid"))
)
)
</div>
</div>
#(Html.Kendo()
.Dialog()
.Name("DeleteConfirmation")
.Modal(true)
.Title("Confirm Delete")
.Content("Are you sure you want to delete this item?")
.Visible(false)
.Actions(a =>
{
a.Add().Text("No").Action("cancelDelete");
a.Add().Text("Yes").Action("confirmDelete").Primary(true);
})
)
<script>
var modelToDelete;
function showDeleteConfirmation(e) {
var grid = $("#grid").data("kendoGrid");
var dialog = $('#DeleteConfirmation').data("kendoDialog");
modelToDelete = grid.dataItem($(e.target).parents('tr'));
dialog.content("Are you sure you want to delete this item with ID - " + modelToDelete.OrderID + "?");
dialog.open();
}
function confirmDelete(e) {
var grid = $("#grid").data("kendoGrid");
grid.dataSource.remove(modelToDelete);
grid.dataSource.sync();
$('#DeleteConfirmation').data("kendoDialog").close();
}
function cancelDelete() {
$('#DeleteConfirmation').data("kendoDialog").close();
}
</script>
I encountered a similar problem a long time ago. Unfortunately, I forgot exactly how I resolved it :(
SUGGESTION:
Try adding e.preventDefault(); to your custom command handler:'
https://www.telerik.com/forums/problem-expandrow()-causes-jump-to-top-of-window
https://stackoverflow.com/a/1253492/3135317

Adding custom buttons to Kendo grid toolbar in ASP.NET Core

I am using Kendo tools for my ASP.NET Core application. I have a grid and I want to add custom buttons to the grid tool bar. I can easily add the export to excel button but I'm having a really hard time adding my custom buttons.
Currently I just have my buttons displayed above the grid, here are those buttons:
<a href='#' class='k-button' id='saveState'>Save Grid Settings</a>
<a href='#' class='k-button' id='clearState'>Clear Grid Settings</a>
Here is my grid:
#(Html.Kendo().Grid<SylectusTL.ViewModels.Account.UserList>()
.Name("UserList")
.Columns(columns =>
{
columns.Bound(c => c.user_name).ClientTemplate(#"#: user_name #").Title("User Name");
columns.Bound(c => c.full_name).Title("Name");
columns.Bound(c => c.main_phone).Title("Phone").Width(150);
columns.Bound(c => c.main_phone_ext).Title("Ext").Width(100);
columns.Bound(c => c.email).Title("E-Mail");
columns.Bound(c => c.admin).ClientTemplate("#= admin ? 'Y' : 'N' #").Title("Admin").Width(100).HeaderHtmlAttributes(new { style = "text-align: center;" }).HtmlAttributes(new { style = "text-align: center;" });
columns.Bound(c => c.active).ClientTemplate("#= active ? 'Y' : 'N' #").Title("Active").Width(100).HeaderHtmlAttributes(new { style = "text-align: center;" }).HtmlAttributes(new { style = "text-align: center;" });
columns.Bound(c => c.last_login).Title("Last Login").Format("{0:MM/dd/yyyy}");
})
.ToolBar(tools =>
{
tools.Excel();
})
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(new int[] { 10, 20, 50 })
.ButtonCount(5))
.Sortable(sortable => sortable
.AllowUnsort(true)
.SortMode(GridSortMode.MultipleColumn)
.ShowIndexes(true))
.Scrollable()
.Reorderable(reorder => reorder.Columns(true))
.Filterable()
.ColumnMenu()
.Excel(excel => excel
.FileName("User List.xlsx")
.Filterable(true)
.ProxyURL(Url.Action("Excel_Export_Save", "Account"))
)
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Read(read => read.Action("Users_Read", "Account").Data("additionalData"))
)
)
Is there a way to add a template of soemthing to the toolbar property, I want the buttons to display next to the export to excel button. I've looked up some tutorials and everything is showing using tools.template in my toolbar property but when I try that it says Template does not exist.
Add a tools.Custom() statement after the tools.Excel(). This example creates a toolbar with the standard create button and a custom button for duplicating a row.
...
.ToolBar(toolbar =>
{
toolbar.Create();
toolbar.Custom()
.HtmlAttributes ( new { onclick="master_duplicate(); return false;" } )
.Name("duplicate")#* creates a button with class k-grid-duplicate *#
.Text("Duplicate")
.IconClass("k-icon k-i-copy")
.Url("#")
;
})
...
and javascript
var dup_select_id; * used later in databound handler to automatically select the new duplicate;
function master_duplicate() {
var grid = $('#master').data('kendoGrid');
var data = grid.dataItem(grid.select());
$.ajax({
url: "#Url.Action("Duplicate")",
type: "POST",
data: { masterID: data.id }
})
.done(function (data, status, jqXHR) {
if (data.Data && data.Data.id) {
dup_select_id = data.Data.id;
grid.dataSource.read();
}
})
;
}
and there is other logic to hide the button when there is no selected row.
We can use ClientTemplate to add more than one column menu in existing. Below line of code we can refer for the same
.ToolBar(tools => {
tools.ClientTemplate("<a class='column_Menu' style='float:right' id='columnMenuButton' href='\\#' />"+"<label for='HideEmptyIndicatores' style='float:right;padding-right: 20px;padding-left: 3px;'> Hide Empty Indicators</label> <input type='checkbox' style='height:15px;min-width:15px; float:right'; id = 'HideEmptyIndicatores' onchange='hideEmptyRateIndicators(this)'/> "); })
this line of code result in the below SS

Template error when doing 3 levels deep of kendo grids (i.e. a detail grid for a detail grid of a main grid)

If I have a main Kendo cshtml view with a kendo grid that has a detail that is another grid which then has a detail that is another grid, an invalid template error occurs. An example is shown below with the code not essential to the issue at hand replaced by '.......' for simplification purposes (it is not shown but the data source is sql using ajax).
File 1: Index.cshtml
<div id="dvFileGroupSummaryGrid" style="width: auto;">
#(Html.Kendo().Grid<OverallSummary>()
.Name("FileGroupSummaryGrid")
.Columns(columns =>
{
.........
}
.AutoBind(true)
.ClientDetailTemplateId("fileGroupFilesTemplate")
.........
</div>
<script id="fileGroupFilesTemplate" type="text/kendo-tmpl">
#Html.Partial("_FileGroupFilesSummary")
</script>'
File 2: _FileGroupFilesSummary.cshtml
#(Html.Kendo().TabStrip()
.Name("TabStrip_#=FileGroupID#")
.SelectedIndex(0)
.Items(items =>
{
items.Add().Text("File Group Files Summary").Content(#<text>
#(Html.Kendo().Grid<FileGroupSummary>()
.Name("FileGroupFilesSummaryGrid_#=FileGroupID#")
.Columns(columns =>
{
...........
})
........
.AutoBind(true)
.ClientDetailTemplateId("fileResultsTemplate")
.ToClientTemplate()
)
</text>
);
})
.ToClientTemplate()
)
<script id="fileResultsTemplate" type="text/kendo-tmpl">
#Html.Partial("_FileResults")
</script>
File 3: _FileResults.cshtml
#(Html.Kendo().TabStrip()
.Name("TabStrip_#=MonitoredFileKey#")
.SelectedIndex(0)
.Items(items =>
{
items.Add().Text("File Results").Content(#<text>
#(Html.Kendo().Grid<MonitoredFileResults>()
.Name("MonitoredFileResultsGrid_#=MonitoredFileKey#")
.Columns(columns =>
{
...........
})
.........
.AutoBind( true )
.ToClientTemplate()
)
</text>
);
})
.ToClientTemplate()
)
The key to this problem turned out to be that the partial view reference to the 3rd level detail grid had to be in the top level view (index.cshtml) instead of in the partial view that actually referenced it. The code adjusted for this change is shown below.
File 1 Index.cshtml
<div id="dvFileGroupSummaryGrid" style="width: auto;">
#(Html.Kendo().Grid<OverallSummary>()
.Name("FileGroupSummaryGrid")
.Columns(columns =>
{
.........
}
.AutoBind(true)
.ClientDetailTemplateId("fileGroupFilesTemplate")
.........
</div>
<script id="fileGroupFilesTemplate" type="text/kendo-tmpl">
#Html.Partial("_FileGroupFilesSummary")
</script>'
<script id="fileResultsTemplate" type="text/kendo-tmpl">
#Html.Partial("_FileResults")
</script>
File 2 _FileGroupFilesSummary.cshtml
#(Html.Kendo().TabStrip()
.Name("TabStrip_#=FileGroupID#")
.SelectedIndex(0)
.Items(items =>
{
items.Add().Text("File Group Files Summary").Content(#<text>
#(Html.Kendo().Grid<FileGroupSummary>()
.Name("FileGroupFilesSummaryGrid_#=FileGroupID#")
.Columns(columns =>
{
...........
})
........
.AutoBind(true)
.ClientDetailTemplateId("fileResultsTemplate")
.ToClientTemplate()
)
</text>
);
})
.ToClientTemplate()
)
File 3 _FileResults.cshtml
#(Html.Kendo().TabStrip()
.Name("TabStrip_#=MonitoredFileKey#")
.SelectedIndex(0)
.Items(items =>
{
items.Add().Text("File Results").Content(#<text>
#(Html.Kendo().Grid<MonitoredFileResults>()
.Name("MonitoredFileResultsGrid_#=MonitoredFileKey#")
.Columns(columns =>
{
...........
})
.........
.AutoBind( true )
.ToClientTemplate()
)
</text>
);
})
.ToClientTemplate()
)

MVC Kendo Grid with custom popup editor using MultiSelect - can't get selected items in model

The title says it all.
POPUP FORM:
#using Kendo.Mvc.UI
#using Batc.AgileApp.Web.Areas.ProductReuse.Models
#model BomViewModel
#Html.HiddenFor(m => m.BomId)
#Html.HiddenFor(m => m.Row)
#Html.HiddenFor(m => m.UserWorkSessionId)
<div class="container-fluid">
<div class="form-group row">
<div class="col-xs-4 col-sm-4">
<span>
#Html.LabelFor(model => model.ProductClass)
</span>
<br/>#(Html.Kendo().DropDownListFor(m => m.ProductClass)
.DataTextField("Text")
.DataValueField("Value")
.HtmlAttributes(new {style = "width:125px"})
.DataSource(source =>
{
source.Read(read => { read.Action("GetDropDownLookups", "AjaxProductReuse", new {id = "ProductClass"}); });
})
)
<div style="font-weight: normal;">
#Html.ValidationMessageFor(model => model.ProductClass)
</div>
</div>
<div class="col-xs-4 col-sm-4">
<span>
#Html.LabelFor(model => model.ProgramSelectedList)
</span>
#(Html.Kendo().MultiSelectFor(m => m.ProgramSelectedList)
.Placeholder("Select program...")
.HtmlAttributes(new {style = "width:200px"})
.DataSource(source =>
{
source.Read(read => { read.Action("GetLookups", "AjaxProductReuse", new {id = "Program"}); });
})
)
<div style="font-weight: normal;">
#Html.ValidationMessageFor(model => model.ProgramSelectedList)
</div>
</div>
</div>
</div>
GRID FORM (cshtml view):
#using Batc.AgileApp.Web.Areas.ProductReuse.Models
#using Kendo.Mvc.UI
#model AssemblyViewModel
#using (Html.BeginForm("Assembly", "ProductReuse", FormMethod.Post, new {id = "frmStartScreen"}))
{
#Html.HiddenFor(m => m.Status)
#Html.HiddenFor(m => m.UserWorkSessionId)
#Html.HiddenFor(m => m.GlobalPartNum)
#(Html.Kendo().Grid<BomViewModel>()
.Name("bom-prGrid-kendoGrid")
.HtmlAttributes(new {#class = "prGrid"})
.ClientRowTemplate("")
.Columns(columns =>
{
columns.Command(cmd => cmd.Edit()).Width(80);
columns.Bound(g => g.BomId).Hidden();
columns.Bound(g => g.IsEditable).Hidden();
columns.Bound(g => g.Row).Width(75).Title("Row");
columns.Bound(p => p.Program).Width(100).Title("Program");
columns.Bound(p => p.ProductClass).Width(100).Title("Product<br/>Class");
columns.Bound(p => p.ResponsibleEng).Width(120).Title("Resp Eng");
columns.Bound(p => p.ProjectNum).Width(100).Title("Project<br/>No");
columns.Bound(p => p.AccessControl).Width(150).Title("Access Control");
})
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => { model.Id(g => g.BomId); })
.PageSize(100)
.Read(r => r.Action("GetCloneAssembly", "AjaxProductReuse").Data("ProductReuseGridReadData"))
.Update(u => u.Action("UpdateBomItem", "AjaxProductReuse").Type(HttpVerbs.Post))
.Events(e => e.Error("ajax_error").Sync("dataSource_sync").Change("dataSource_change"))
)
.Events(e => e.DataBound("onDataBound").Edit("onEdit"))
.Pageable(pager => pager
.Input(true)
.Numeric(true)
.Info(true)
.PreviousNext(true)
.Refresh(true)
.PageSizes(new int[] {100, 250, 500, 1000})
)
.Sortable()
.Scrollable()
.Filterable()
.Editable(editable => editable.Mode(GridEditMode.PopUp).TemplateName("BOMForm").Window(w => w.Title("Manage BOM Item").Name("BOMForm")))
.Resizable(resizing => resizing.Columns(true)).Reorderable(reorder => reorder.Columns(true))
)
}
Model (properties of interest):
[MetadataType(typeof(BomViewModelMetaData))]
public class BomViewModel: BomModel
{
public int BomId { get; set; }
public int Row { get; set; }
public int UserWorkSessionId { get; set; }
public string ProductClass { get; set; }
public string Program { get; set; }
public List<string> ProgramSelectedList { get { return Program.ToList(); } set { Program = value.ToDelimitedString(); } }
}
My (ajax) controller looks like:
public JsonResult UpdateBomItem([DataSourceRequest] DataSourceRequest request, BomViewModel bomViewModel) // [Bind(Prefix = "models")]
{
var command = _mapper.Map<BomModel>(bomViewModel);
var commandResponse = _productReuseService.UpdateBomItem(command);
var response = _mapper.Map<List<BomViewModel>>(commandResponse);
return Json(ToDataSourceResult(response, request, modelState: ModelState));
}
The problem I am encountering is the data being posted to my controller. It looks like this in fiddler (where the first 3 items map to the first object in the controller, the remainder being the model):
sort=
&group=
&filter=
&Program=PROGRAM_ORIGINAL
&ProgramSelectedList[0]=PROGRAM_01
&ProgramSelectedList[1]=PROGRAM_02
&UserWorkSessionId=45
&Row=10
&ProductClass=1
&BomId=151927
What I expected was:
sort=
&group=
&filter=
&Program=PROGRAM_01, PROGRAM_02
&ProgramSelectedList=PROGRAM_01
&ProgramSelectedList=PROGRAM_02
&UserWorkSessionId=45
&Row=10
&ProductClass=1
&BomId=151927
Is there a "special" setting in Kendo or JQuery or .NET to make this list behave correctly? I currently am using Kendo in MVC HTML Helper mode only. This means I have almost no JS propping up my desired actions on the UI side of things.
This is an internal LOB app, low usage, minimal users.
After much digging and frustration the answer is pretty simple. I needed to add a JS helper to put the data into a format the MVC Model Binder could understand.
<script>
function getUpdatedBomRowData() {
var program = $("#ProgramSelectedList").data("kendoMultiSelect").value().toString();
return {
program: program
}
}
</script>
And then on the grid's datasource update action I added a Data(...) method:
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => { model.Id(g => g.BomId); })
.PageSize(100)
.Read(r => r.Action("GetCloneAssembly", "AjaxProductReuse").Data("ProductReuseGridReadData"))
.Update(u => u.Action("UpdateBomItem", "AjaxProductReuse").Type(HttpVerbs.Post).Data("getUpdatedBomRowData"))
.Events(e => e.Error("ajax_error").Sync("dataSource_sync").Change("dataSource_change"))
)
The JS will then put a comma delimited string into the Program property before sending to the controller. Since Program is being used as (A) a DB representation of the table field, and (B) a backing field for List ProgramSelectedList, my code seems to be happy now.

How to add two button in grid.mvc control in mvc

I want to add two button control in one column. currently i can able to add Download button on one column . but i want to add delete button beside to download button in same columns.
please suggest on the same.
I have given code..
#using (Html.BeginForm("DownloadFile", "Download", FormMethod.Post))
{
#Html.Grid(Model).Columns(columns =>
{
columns.Add()
.Encoded(false)
.Sanitized(false)
.SetWidth(0)
.RenderValueAs(o => #<input id="id" name="IsChecked" value= #o.id , type="checkbox"/>);
columns.Add(data => data.FileName).Titled("File Name").SetWidth(50);
columns.Add(data => data.DisplayedDate).Titled("Uploaded Date").SetWidth(40);
columns.Add(data => data.User_Name).Titled("User Name").SetWidth(50);
columns.Add()
.Encoded(false)
.Sanitized(false)
.SetWidth(80)
.RenderValueAs(data => #<button type="submit" value ="">Download</button>);
}).WithPaging(10).Sortable(true).Filterable(true)}
One of the overload for RenderValueAs accepts IHtmlString.
So you can do:
.RenderValueAs(data => new HtmlString
(
"<button type='submit' value=''>Download</button>
<button type='button' value=''>Upload</button>"
)
);
Or you can do:
.RenderValueAs(data => "<button type='submit' value=''>Download</button>
<button type='button' value=''>Upload</button>"
);
If you need more control, there is a Custom Layout rendering feature that you can use.
columns.Add(c => c.PrecioVenta).Titled("Precio de Venta").Filterable(true);
columns.Add(c => c.Cantidad).Titled("Cantidad").Filterable(true);
columns.Add()
.Encoded(false)
.Sanitized(false)
.SetWidth(30)
.RenderValueAs(o => Html.ActionLink("Editar", "Edit", new { id = o.IdProducto }, new { #class = "btn btn-primary" }));
columns.Add()
.Encoded(false)
.Sanitized(false)
.SetWidth(30)
.RenderValueAs(o => Html.ActionLink("Detalles", "Details", new { id = o.IdProducto }, new { #class = "btn btn-info" }));