What "EditorViewData" is for in Telerik MVC Grid column definition? - asp.net-mvc

i have a telerik grid as follow:
Html.Telerik().Grid<MatchViewModel>().Name("Matches").Columns(cols =>
{
cols.Bound(e => e.Name);
cols.Bound(e => e.Date);
cols.Bound(e => e.GuestTeamId);
cols.Bound(e => e.HostTeamId);
cols.Bound(e => e.PostponedDate);
==> cols.Bound(e => e.RefereeId).EditorViewData(new { RefereeName = '' });
cols.Bound(e => e.StatusId);
})
in the column reffered by arrow i wanna send referee name as additional data for EditorTemplate.i inferred from the EditorViewData method name that it can help me doing this.but i can't get it working.can anyone help me with this?
thanks.

If you have a well defined Model for your page you should not ever need to use ViewBag or ViewData, they are sloppy. EditorViewData allows you to create ViewData on-the-fly to pass extra data to your EditorTemplate.
For example, say you want to have different DropDownList values in the EditorTemplate for each item in your grid, you will need to pass extra data to do this. With EditorViewData you can add additional values from your Model for exactly that purpose without having to resort to coding up any ViewBag or ViewData objects in your Controller.
The first place I used it was a People grid that allowed editing of defined Qualifications added to a Qualifications grid inside a nested TabStrip. The trick was I didn't want the DropDownList for each person to contain any of the qualifications they already had earned. Like this...
People Grid
#using Kendo.Mvc.UI
#model PeopleViewModel
#(Html.Kendo().Grid<PersonModel>()
.Name("PersonGrid")
.Columns(columns => {
columns.Bound(b => b.LastName).EditorTemplateName("_TextBox50");
columns.Bound(b => b.FirstName).EditorTemplateName("_TextBox50");
...
columns.Command(cmd => { cmd.Edit(); cmd.Destroy(); }).Width(180);
})
.ClientDetailTemplateId("personTemplate")
.ToolBar(toolbar => toolbar.Create())
.Selectable()
.Editable(editable => editable.Mode(GridEditMode.InLine))
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(a => a.Id);
})
.Create(create => create.Action("CreatePerson", "People"))
.Read(read => read.Action("ReadPeople", "People"))
.Update(update => update.Action("UpdatePerson", "People"))
.Destroy(destroy => destroy.Action("DestroyPerson", "People"))
)
.Events(events => events.DataBound("dataBound"))
)
<script type="text/javascript">
function dataBound() {
this.expandRow(this.tbody.find("tr.k-master-row").first());
}
</script>
<script id="personTemplate" type="text/kendo-tmpl">
#(Html.Kendo().TabStrip()
.Name("TabStrip_#=Id#")
.Items(items =>
{
...
items.Add().Text("Edit Qualifications")
.LoadContentFrom("PersonQualifications", "People", new {personId = "#=Id#"});
...
})
.ToClientTemplate()
)
</script>
PeopleViewModel
Ignore the inheritance stuff, it is beyond this discussion. But note that I use this same Model on all the sub Views related to this top level View.
public class PeopleViewModel : PageViewModel
{
public int PersonId { get; set; }
public PersonModel Person { get; set; }
public IList<QualificationModel> AllQualifications { get; set; }
...
public PeopleViewModel(BaseViewModel baseViewModel) : base(baseViewModel)
{}
}
PersonQualifications Controller
The data providers are injected elsewhere, but note the POCO to Model flattening - just a static method that applies a List to the Model constructor.
public ActionResult PersonQualifications(int personId)
{
SetBaseContext(HttpContext);
var model = new PeopleViewModel(BaseViewModel)
{
PersonId = personId,
AllQualifications = QualificationModel.FlattenToThis(_qualificationDataProvider.Read())
};
return View(model);
}
Nested Grid (View Loaded Inside TabStrip)
#using Kendo.Mvc.UI
#model PeopleViewModel
#{
Layout = null;
}
#(Html.Kendo().Grid<PersonQualificationModel>()
.Name("QualificationEditGrid_" + Model.PersonId)
.Columns(columns =>
{
columns.ForeignKey(f => f.QualificationId, Model.AllQualifications, "Id", "Display")
===> .EditorViewData(new {personId = Model.PersonId})
.EditorTemplateName("PersonQualificationDropDownList");
columns.Command(cmd =>
{
cmd.Edit();
cmd.Destroy();
}).Width(180);
})
.ToolBar(toolbar => toolbar.Create())
.DataSource(dataSource => dataSource
.Ajax()
.Events(events => events.Error("error_handler"))
.Model(model => {
model.Id(a => a.Id);
})
.Create(create => create.Action("CreatePersonQualification", "People"))
.Read(read => read.Action("ReadPersonQualifications", "People", new {personId = Model.PersonId}))
.Destroy(destroy => destroy.Action("DestroyPersonQualification", "People"))
)
)
The EditorTemplate (Finally!)
Ignore the first ViewData reference that helps make this EditorTemplate shared. The one we are interested in is a little further down.
#using Kendo.Mvc.UI
#(Html.Kendo().DropDownList()
.Name(ViewData.TemplateInfo.GetFullHtmlFieldName(""))
.DataValueField("Id")
.DataTextField("Name")
.OptionLabel("Select...")
.DataSource(dataSource => dataSource
===> .Read(read => read.Action("ReadDdlQualifications", "People", new {personId = ViewData["personId"]}))
)
)
Controller Method (Just to be Thorough)
public JsonResult ReadDdlQualifications(int personId)
{
var qualification = _qualificationDataProvider.ReadAvailableToPerson(personId);
IList<IdNamePair> results = IdNamePair.FlattenToThis(qualification);
return Json(results, JsonRequestBehavior.AllowGet);
}
Obviously there is a lot of other stuff going on in this example (I hope I left enough code in for it to make sense), but it should get across the point of when it is needed - and it is REALLY needed.
Enjoy.

I ran into the same issue as Chad and as Trey mentioned, this cannot be done via passing information to EditorViewData. There is no way to pass the row data item, only page data.
As an alternative you can add this script to the editor template. Then you can access a field value from the grid row and pass it to the datasource call, filtering the dropdownlist based on each rows data.
<script type="text/javascript">
function getParentId() {
var row = $(event.srcElement).closest("tr");
var grid = $(event.srcElement).closest("[data-role=grid]").data("kendoGrid");
var dataItem = grid.dataItem(row);
return { EmployeeId: dataItem.EmployeeId };
}
</script>
And then add the data item to the read method on the data source.
#(Html.Kendo().DropDownList()
.Name("Product")
.DataValueField("ProductId")
.DataTextField("ProductName")
.DataSource(ds => ds
.Read(read => read.Action("ProductsRead", "Home")
.Data("getParentId")
))
)

Related

How to open a modal using Kendo UI grid that has a list inside it

I am using Kendo UI in my asp.net mvc project.
I have an issue for displaying modal. In my grid, I want to add an extra column that has a button in it.
When the user clicks that button, I need to show a list from another table that has the ID of the current table, and show it in modal.
I would really appreciate if you could help me.
#(Html.Kendo().Grid<ClinicManagement.Models.Reagent>().Name("PersonGrid")
.Name("PersonGrid")
.Columns(columns =>
{
columns.Bound(p => p.Name).Filterable(ftb => ftb.Cell(cell => cell.Operator("contains").SuggestionOperator(FilterType.Contains))).Width(90);
columns.Bound(p => p.Family).Filterable(ftb => ftb.Cell(cell => cell.Operator("contains").SuggestionOperator(FilterType.Contains))).Width(90);
columns.Bound(p => p.CardNumber).Filterable(ftb => ftb.Cell(cell => cell.Operator("contains").SuggestionOperator(FilterType.Contains))).Width(90);
columns.Command(command => command.Custom("ViewDetails").Click("showDetails")).Width(150);
})
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Events(events => events.Error("error_handler"))
.Sort(sort => sort.Add(p => p.Name).Ascending())
.Model(model => model.Id(p => p.Id))
.Create(update => update.Action("Create", "Reagents"))
.Read(read => read.Action("ReadReagent", "Reagents"))
.Update(update => update.Action("Edit", "Reagents"))
.Destroy(destroy => destroy.Action("Delete", "Reagents"))
))
OK, your code looks similar to the demo here. You just need to finish it up:
First, create a modal on the page:
#(Html.Kendo().Window().Name("Details")
.Title("Customer Details")
.Visible(false)
.Modal(true)
.Draggable(true)
.Width(300)
)
The sample uses a kendo template to display the details, so you could add a kendo list in there (you would need to use .ToHtmlString() since it is a nested control). I prefer a different approach where I can use a partial view with a view model:
Create a view model with the list items and other properties to display:
public class DetailsViewModel
{
public int PersonId { get; set; }
public string Name { get; set; }
... etc
public List<string> MyListItems;
}
Create a partial view for the details with a list (or grid) on it:
#model DetailsViewModel
<div>
... // Show fields, etc.
#(Html.Kendo().ListBox()
... other list options
.BindTo(Model.MyListItems)
.Deferred() // Need for nested control
</div>
Create a controller action to return the partial:
public PartialViewResult GetDetailsView(int personId)
{
// fetch data
// Fill the viewmodel
var vm = new DetailsViewModel
{
PersonId = data.PersonId,
Name = data.Name,
MyListItems = context.Items.Where(i => i.PersonId == personId).ToList()
}
return PartialView("_Details", vm);
}
The javascript code for the button click will open the window and tell it to load the partial view from controller action:
<script type="text/javascript">
function showDetails(personId) {
var wnd = $("#Details").data("kendoWindow");
wnd.refresh({
url: '#Url.Action("GetDetailsView","Person", new { personId = "__personid__" })'
.replace("__personid__", personId )
});
wnd.open();
}
</script>
Finally, change the custom command to pass in the Id:
.Click("showDetails(PersonId)")
EDIT - or use a template for your button:
columns.Template(t => { }).Width(150)
.ClientTemplate(#"<a class='btn btn-info btn-xs' onclick="showDetails(PersonId)">Details</a>");

Using Kendo Grid in PartialView

I have two <section> in the Index view of my MVC application and I want to render two partial views in these sections. There is no problem rendering a Kendo grid to one Index. However, in order to render data on Kendo Grid, could I use the two methods returning Json in the controller as shown below. Could you give me an example how to achieve this?
Controller:
public ActionResult Index()
{
return View();
}
public ActionResult Issues_Read([DataSourceRequest]DataSourceRequest request)
{
IQueryable<Issue> issues = db.Issues;
DataSourceResult result = issues.ToDataSourceResult(request, c => new IssueViewModel
{
ID = c.ID,
ProjectID = c.ProjectID
});
return Json(result);
}
View:
#(Html.Kendo().Grid<IssueViewModel>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.ProjectID);
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(180);
})
.ColumnMenu()
.Editable(editable => editable.Mode(GridEditMode.PopUp))
.Pageable()
.Navigatable()
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id(p => p.ID))
.Read(read => read.Action("Issues_Read", "Issue"))
.Create(create => create.Action("Issues_Create", "Issue" ))
.Update(update => update.Action("Issues_Update", "Issue"))
.Destroy(destroy => destroy.Action("Issues_Destroy", "Issue"))
)
)
In order to use the same partial view multiple times, grid ID should be unique so passing the ID in partial view data is one possible solution. In your case
Partial view first call:
#Html.Partial("grid", new ViewDataDictionary { { "id", "grid1" }})
Partial view second call:
#Html.Partial("grid", new ViewDataDictionary { { "id", "grid2" }})
Partial view content:
#(Html.Kendo().Grid<IssueViewModel>()
.Name(#ViewData["id"].ToString())
...

Kendo UI for ASP.Net MVC. Grid sorting error with additional entity property

I have a sorting problem with kendo ui grid.
I have a Entity class Port, in partial class I added additional property:
public partial class Port {
[NotMapped]
[XmlIgnore]
[ScriptIgnore]
public string CountryName { get; set; }
}
I am using this property in other program parts.
In controller I have:
public ActionResult Index()
{
if (!CanViewPorts())
return new EmptyResult();
ViewBag.CanEditPorts = CanEditPorts();
return View();
}
public ActionResult Ports([DataSourceRequest] DataSourceRequest request)
{
if (!CanViewPorts())
return new EmptyResult();
var all = _classificatoryService.GetAllPorts();
return Json(all.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
I'am using method Ports in my view to populate kendo ui grid.
My view:
#(Html.Kendo().Grid<Port>()
.Name("Ports")
.ToolBar(toolbar => toolbar.Template(Toolbar().ToString()))
.Columns(columns =>
{
columns.Bound(c => c.PortId);
columns.Bound(c => c.Code);
columns.Bound(c => c.Name);
columns.Bound(c => c.AlternativeName);
columns.Bound(c => c.SubDivision);
columns.Template(#<text></text>).ClientTemplate("<a class='k-button k-button-icontext' href='" + Url.Action("Details", "Port") + "/#=PortId#'><span class='glyphicon glyphicon-edit mr5'></span>Details</a>").Width(110); //"<#=PortId#>"
columns.Template(#<text></text>).ClientTemplate("<a class='newPortBtn k-button k-button-icontext' href='" + Url.Action("NewPort", "Port") + "/?portId=#=PortId#'><span class='glyphicon glyphicon-edit mr5'></span>Edit</a>").Visible(canEditPorts).Width(110);
})
.Sortable()
.ColumnMenu()
.Filterable()
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(true)
.ButtonCount(5))
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id(x => x.PortId))
.Read(read => read.Action("Ports", "Port"))
.Sort(sort => sort.Add(x => x.ChartererId).Descending())
.Create(c => c.Action("NewPort", "Port"))
))
As you can see I'a not using additional property Countryname in this view.
Ok, grid gets ports and show it properly.
Then I'am trying to sort and click column header.
First click (ASC) - Ok, grid sorted by this column in ascending order.
Second click (DESC) - Ok, grid sorted by this column in descending order.
Third click (unsort) - Grid must be unsorted, but I have 500 (Internal Server Error).
In chrome/Network/Preview I have:
Server Error in '/' Application. The specified type member 'CountryName' is not supported in LINQ to Entities. Only initializers,
entity members, and entity navigation properties are supported.
How to fix this problem?

Adding DropDownList to kendo grid in MVC

I'm trying to add a dropdownlist to a kendo grid by the help of this documentation
:
http://demos.telerik.com/aspnet-mvc/grid/editing-custom
Actually I followed exactly the same way but no chance I'm wonder how the kendo grid understand it has to place a dropdownlist in the clientTemplate ?!
does clientTemplate has to be defined somewhere?
You have to define a clientTemplate by adding this to the Grid .ClientDetailTemplateId("template")
Then you can add DropDownList into the template
<script id="template" type="text/kendo-tmpl">
#(Html.Kendo().DropDownList()
//build the dropdownlist
.ToClientTemplate()
)
</script>
Demo: http://demos.telerik.com/aspnet-mvc/grid/detailtemplate
Just to add to the mix of answers, here is a late one...
Create a List in your ViewModel
Treat your Model.PropertyId as a ForeignKey
For example...
columns.ForeignKey(x => x.ChangeTypeId, Model.ChangeTypes, "Id",
"ChangeTypeName")
SAMPLE VIEW:
#(Html.Kendo().Grid<ChangeRequest>()
.Columns(columns =>
{
columns.Bound(x => x.Id)
.Visible(false);
columns.Bound(x => x.Description)
.Title("Description")
.Width(100);
columns.ForeignKey(x => x.ChangeTypeId, Model.ChangeTypes, "Id", "ChangeTypeName")
.Title("Data Type")
.Width(50);
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(100);
})
.Name("gridChangeRequest")
.ToolBar(toolbar => toolbar.Create())
.Editable(editable => editable.Mode(GridEditMode.InLine))
.Pageable()
.Sortable()
.Scrollable()
.BindTo(Model.RTUDeviceCustomRegisterModbuses)
.DataSource(dataSource => dataSource.Ajax()
.ServerOperation(true)
.PageSize(50)
.Model(model => { model.Id(m => m.Id); })
.Create(update => update.Action("Create", "ChangeRequest", new { Area = "Documents" }))
.Update(update => update.Action("Update", "ChangeRequest", new { Area = "Documents" }))
.Destroy(update => update.Action("Destroy", "ChangeRequest", new { Area = "Documents" }))
)
.HtmlAttributes(new { #class = "", #style = "height: 400px;" }))
SAMPLE VIEW MODEL:
public class ChangeRequestFormViewModel : ViewModelBase
{
#region <Constructors>
public ChangeRequestFormViewModel(IApplication application) : base(application)
{
InitializeCreateEmpty();
}
#endregion
#region <Properties>
public ChangeRequestDocument Entity { get; set; }
#region lookups
public List<ChangeType> ChangeTypes { get; set; }
#endregion
#endregion
#region <Methods>
private void InitializeCreateEmpty()
{
var builder = Application.ChangeRequestDocumentXmlDataSetBuilder; //<-- This object is specific to my (particular) application
var dataset = builder.CreateEmpty();
Entity = dataset.Form;
ChangeTypes = dataset.ChangeTypes;
}
#endregion
}

Kendo UI Filter is empty

I want to use Kendo UI grid with filter option in APS.NET MVC.
In my example I use database as datasource and a student table
When I use student class as
public ActionResult Index()
{
var std = (from p in db.Students
select p).ToList();
return View("Student", std);
}
everything is ok.
But when I want use ViewModel as datasource, in runtime when I click in filter icon filter window open but I can't see anything in dropdown list of filter.
I use automapper and value injecter.
Any suggestion to solve this problem?
Appended
PersonController.cs
public class PersonController : Controller
{
Adventureworks2012DataContext db = new Adventureworks2012DataContext();
public ActionResult Index()
{
/*var prs = (from p in db.Person
select p).ToList();*/
return View(GetPersonViewModel());
}
public ActionResult PersonViewModel_Read([DataSourceRequest]DataSourceRequest request)
{
return Json(GetPersonViewModel().ToDataSourceResult(request));
}
private IList<PersonViewModel> GetPersonViewModel()
{
return db.Person.Project().To<PersonViewModel>().ToList();
}
}
Index.cshtml
#model IList<DevartLinqTestMVC.ViewModel.PersonViewModel>
#{
ViewBag.Title = "Person List";}
<br />
#(Html.Kendo().Grid(Model)
.Name("Grid")
.Columns(columns =>
{
columns.Bound(p => p.Businessentityid);
columns.Bound(p => p.Persontype);
columns.Bound(p => p.Namestyle);
columns.Bound(p => p.Title);
columns.Bound(p => p.Firstname);
columns.Bound(p => p.Middlename);
columns.Bound(p => p.Lastname);
columns.Bound(p => p.Emailpromotion);
})
.Groupable()
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.Selectable()
.DataSource(dataSource => dataSource
.Ajax()
.Model(m => m.Id(s => s.Businessentityid))
.PageSize(20)
.Read(read => read.Action("PersonViewModel_Read", "Person")))
)
everything is good also ajax work perfectly
but where is filter dropdown list?!!!
If you pass a list in your view it only works you want a static list that is loaded once. If you want server side paging or a toolbar, you need to load your data using a server side function that returns a JSON object and link it to your grid with .Read().
For example, in your controller (code not tested):
public ActionResult StudentGrid_Read([DataSourceRequest] DataSourceRequest request)
{
return Json((from p in db.Students select p).ToDataSourceResult(request));
}
And on your grid:
#(Html.Kendo()
.[other stuff]
.DataSource(dataSource => dataSource
.[other stuff]
.Read("StudentGrid_Read", "Controller")
)
)
See the kendo ui grid with toolbar demo for the complete coding example: http://demos.kendoui.com/web/grid/toolbar-template.html
Edit: just noticed there is a filtering demo as well, but the idea is the same:
http://demos.kendoui.com/web/grid/filter-menu-customization.html

Resources