I want to build one template with telerik grid, which is invoking by other page as an partial view.
the template code like this:
#model IEnumerable<object>
#using System.Collections;
#using System.Collections.Generic;
#using System.Reflection;
#{
ViewBag.Title = "UserView2";
}
<div>
#{Html.Telerik().Grid(Model)
.Name("UserConfiguration")
.DataKeys(keys => keys.Add(o => o.GetType().GetProperty("ConfigurationItemId").GetValue(o)))
.Columns(
columns =>
{
Type t = Model.GetType().GetGenericArguments().FirstOrDefault();
foreach (var prop in t.GetProperties())
{
columns.Bound(prop.PropertyType, prop.Name);
}
columns.Command(commands => commands.Edit()).Width(100);
}
)
.DataBinding(
dataBinding => dataBinding.Server()
.Update("UpdateUser", "Configuration")
)
.Pageable(paging => paging.PageSize(20))
.Sortable()
.Scrollable(o => o.Height(500))
.Filterable()
.Resizable(resizing => resizing.Columns(true))
.Render();
}
The other view page Invoke the template view like this:
#Html.Partial("UserView2", Model.UserList)
And when i run it, the page open successfully and display all the data successfully. so i think it works well through reflecting get the columns name and columns data. But when i click "Edit" button, it will throw an exception:
Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
anyone can help me solve this?
Related
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>");
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 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!
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.