I am trying to implement the Grid in ASP.NET MVC 5 app. I have use table in razor to test code and is pulling data properly, however i am trying to do server binding using provided Kendo helper classes but i am struggling to pull data to view. I am using Repository pattern and UnitOfWork.... the code is below ...
my 2nd question is, which is the best way to use Multiple Models in Single View???? I have also ViewModel but i havn't use in following code.. can i use #(Html.Kendo().Grid() and #(Html.Kendo().Grid() in same view... many thanks in advanced...
Repository Class:
public IEnumerable<FeeScheme> GetAllFeeScheme()
{
return getAllFeeSchemeFromRepository();
}
UnitOfWork class
private IEnumerable<FeeScheme> getAllFeeSchemeFromRepository()
{
IEnumerable<FeeScheme> query = new List<FeeScheme>();
query = (from b in _FeeScheme_Repository.GetAll()
select b).ToList();
return query;
}
public IEnumerable<FeeScheme> GetAllFeeScheme()
{
return getAllFeeSchemeFromRepository();
}
Controller class
public JsonResult GetAllFeeScheme([DataSourceRequest]DataSourceRequest request)
{
return Json(FeeScheme_UOF.GetAllFeeScheme().ToDataSourceResult(request));
}
View (Kendo )
#(Html.Kendo().Grid<DatabaseLayer.TableMappings.FeeScheme>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(c => c.FeeSchemeID);
columns.Bound(c=>c.FeeSchemeDescription);
columns.Bound(c => c.Fee);
})
.HtmlAttributes(new { style = "height: 380px;" })
.Scrollable()
.Groupable()
.Sortable()
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(true)
.ButtonCount(5))
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("GetAllFeeScheme", "Qualification"))
.Model(model => model.Id(c=>c.FeeSchemeID))
)
)
The simple question first: To use multiple "view models" in a single view, you would do something like this:
public class TestViewModel
{
public List<Object1> Object1List { get; set; }
public List<Object2> Object2List { get; set; }
public TestViewModel()
{
Object1List = new List<Object1>();
Object2List = new List<Object2>();
}
}
and then use the TestViewModel as the model for the view.
As far as changing your grid to server binding, it would look something like this:
#(Html.Kendo().Grid<>(Model.Object1List)
.Name("Grid")
.Columns(columns =>
{
columns.Bound(c => c.FeeSchemeID);
columns.Bound(c=>c.FeeSchemeDescription);
columns.Bound(c => c.Fee);
})
.HtmlAttributes(new { style = "height: 380px;" })
.Scrollable()
.Groupable()
.Sortable()
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(true)
.ButtonCount(5))
.DataSource(dataSource => dataSource
.Server()
.Model(model => model.Id(c=>c.FeeSchemeID))
)
)
which is the best way to use Multiple Models in Single View
First you can use one model that contains lists that you want like:
public Model()
{
public Ilist < Model1 > Model1List
{
get;
set;
}
public IList < Model2 > Model2List
{
get;
set;
}
}
And second you can use Tuple
Related
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?
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
}
I have create the asp.net MVC 4 application where i am using the entity framework and class "Data" is the model.
AdventureWorksTrainingEntities _dbContext = new AdventureWorksTrainingEntities();
Data _data = new Data(); //Model
Now i want to display the data of the table to the kendo grid. In the controller, i am using the following code:
public ActionResult Index()
{
List<Movie> dataForGrid= _dbContext.Movies.ToList();
return View(dataForGrid);
}
Now i have no idea for displaying the data in Kendo Grid (i am new to kendo and MVC). I have also tried the following but not working:
#model IEnumerable<MvcApp.Models.Data>
#using Kendo.Mvc.UI
#{
ViewBag.Title = "Index";
}
<h2>Grid For Data</h2>
Html.Kendo().Grid<Order>()
.Name("Grid")
.DataSource(dataSource => dataSource // Not implemented
)
Finally got answer:
View:
#(Html.Kendo().Grid<KendoUI.Models.EmployeeViewModel>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(p => p.name).Title("Name");
columns.Bound(p => p.gender).Title("Gender");
columns.Bound(p => p.designation).Title("Designation").Width("300px");
columns.Bound(p => p.department).Title("Department").Width("300px");
})
.Editable(editable => editable.Mode(GridEditMode.InLine))
.Navigatable()
.Pageable()
.Sortable()
.Scrollable()
.DataSource(dataSource => dataSource // Configure the grid data source
.Ajax()
.Model(model =>
{
model.Id(x => x.id);
})
.Read(read => read.Action("Employee_Read", "Home")) // Set the action method which will return the data in JSON format
)
)
Controller:
public ActionResult Employee_Read([DataSourceRequest]DataSourceRequest request)
{
IQueryable<Bhupendra_employees> Details = _dbContext.Bhupendra_employees;
DataSourceResult result = Details.ToDataSourceResult(request, p => new EmployeeViewModel
{
id = p.id,
name = p.name,
gender = p.gender,
designation = p.designation,
department = p.Bhupendra_Dept.Dept_Description
});
return Json(result, JsonRequestBehavior.AllowGet);
}
Model:
public class EmployeeViewModel
{
public Int32 id { get; set; }
public String name { get; set; }
public String gender { get; set; }
public String designation { get; set; }
public String department { get; set; }
//public DateTime dob { get; set; }
}
if your controller name is Data then you can use the following
Your Model
public ActionResult ReadDegrees([DataSourceRequest] DataSourceRequest request)
{
ViewBag.Countries = CommonController.CountryList();
ViewBag.DegreeTypes = CommonController.DegreeTypeList();
using (var _dbContext= new AdventureWorksTrainingEntities ())
{
return Json(_dbContext.Movies.ToList.ToDataSourceResult(request));
}
}
Your View
Just you need to add the following assuming that your Model has a Key called ID
Html.Kendo().Grid<Order>()
.Name("Grid")
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Model(model => model.Id(p => p.ID))
.Read(read => read.Action("ReadDegrees", "Data"))))
I'm trying to follow the docs on how to make my kendo mvc grid ajaxified and able to support some in cell editing.
The problem I have is on save, I'm seeing the grid make the following request which is apparently not available. I'm not familiar with the models prefix stuff but it looks like the object is modeled in the URL properly with each property prefixed with &models, then some hash, then the parameter name and then the value.
Why doesn't this URL map to my controller action method?
"NetworkError: 404 Not Found -
http://localhost/MySite/UI/Orders/Update
?models%5B0%5D%5BId%5D=18c12470-0ca3-4e9c-b6d7-af1d6120e03f
&models%5B0%5D%5BNumber%5D=231413+
&models%5B0%5D%5BMod%5D=8ccbf70a-f368-434c-8c05-2e2f5278215d
&models%5B0%5D%5BModName%5D=M6G+++++++++++++++++++++++++++++++++++++++++++++++
&models%5B0%5D%5BDescription%5D=M6G+LMU+TTU1200
&models%5B0%5D%5BPart%5D=105442
&models%5B0%5D%5BPartDescription%5D=M6H+TELEMATICS+CONTROL+UNIT
&models%5B0%5D%5BQuantity%5D=20
&models%5B0%5D%5BDeliveryDate%5D=Tue+Apr+30+2013+00%3A00%3A00+GMT-0400+(Eastern+Daylight+Time)&_=1366818145016"
The Update method sig in the controller looks like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Update([Kendo.Mvc.UI.DataSourceRequest] Kendo.Mvc.UI.DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<Order> order)
{
//do update
}
And the sample Order object looks like this
public class Order
{
public Guid Id { get; set; }
public string Number{ get; set; }
public Guid Mod{ get; set; }
public string ModName{ get; set; }
public string Description { get; set; }
public int Part{ get; set; }
public string PartDescription { get; set; } // View Model Purposes Only
[Required]
[UIHint("QuantityEditor")] //QuantityEditor is the name of the custom editor template
public int Quantity { get; set; }
public DateTime DeliveryDate{ get; set; }
}
Here's the grid code ala MVC:
#(Html.Kendo().Grid(Model)
.Name("my-grid")
.Columns(columns =>
{
columns.Bound(m => m.Id)
.Hidden(true)
.HtmlAttributes(new { #class = "some-class" });
columns.Bound(m => m.Mod)
.Hidden(true)
.HtmlAttributes(new { #class = "some-class" });
columns.Bound(m => m.ModName)
.Hidden(true)
.HtmlAttributes(new { #class = "some-class" });
columns.Bound(m => m.Description).HtmlAttributes(new { #class = "some-class" });
columns.Bound(m => m.Part).HtmlAttributes(new { #class = "part can-edit" });
columns.Bound(m => m.PartDescription).HtmlAttributes(new { #class = "can-edit" });
columns.Bound(m => m.DeliveryDate).Format("{0:yyyy-MM-dd}").HtmlAttributes(new { #class = "date can-edit" });
columns.Bound(m => m.Quantity).HtmlAttributes(new { #class = "quantity can-edit" }).FooterTemplate("Total:");
})
.Scrollable(s => s.Height("auto"))
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Events(events => events.DataBound("onDataBound"))
.DataSource(dataSource => dataSource
.Ajax()
.Batch(true)
.Update(update => update.Action("Update", "Orders"))
.Read(read => read.Action("GetAllOrders", "Orders").Data("getAdditionalData"))
.Aggregates(aggregates => { aggregates.Add(p => p.Quantity).Sum(); })
.Model(model =>
{
model.Id(m => m.Id);
model.Field(m => m.Id).Editable(false);
model.Field(m => m.Part).Editable(true);
model.Field(m => m.Quantity).Editable(true);
model.Field(m => m.DeliveryDate).Editable(true);
model.Field(m => m.PartDescription).Editable(true);
})
)
)
At 1st glance it would look like,
.Read(read => read.Action("GetAllOrders", "Controller").Data("getAdditionalData"))
Instead of Controller you need to put in the actual name of the Controller so for example "PersonController" would be "Person".
Edit- Ok from the looks of it then you've setup your Read from datasource but not your Update and instead tried to do it in events.
http://demos.kendoui.com/web/grid/editing-inline.html
I find it easier not to use inline edits and instead create a template button to redirect to an edit page thus keeping the kendo related code simple.
Looks like your grid is being called from within an MVC area. If you have Areas setup within your MVC application, it's always a good practice to reference those when making calls with Kendo UI Widgets.
Below assumes an Area called "UI":
.Update(update => update.Action("Update", "Orders", new { Area = "UI" }))
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")
))
)