I have a problem with edit template data bind for kendo grid.
I have binded my grid to model which is DataTable(it must be DataTable because all cloumns must be generated dynamic - I do not know the schema), I added export, sortable, pages etc. I also added edit button, and defined another cshtml file with edit template. It all works almost perfect. One problem is that I receive the empty model for edit template.
View:
#(Html.Kendo().Grid(Model.Data)
.Name("OpertionalViewGrid")
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(false)
.Events(events => events.Error("error_handler"))
.Model(model =>
{
model.Id(p => p.Row[0]);
if (Model.Data != null)
{
foreach (System.Data.DataColumn column in Model.Data.Columns)
{
var field = model.Field(column.ColumnName, column.DataType);
}
}
})
.PageSize(20)
.Read(read =>
read.Action("Export_Read","OperationalView").Data("getRow"))
.Update(up => up.Action("UpdateRow", "OperationalView").Data("getRow"))
)
.Columns(c =>
{
if (Model.Data != null)
{
int index = 0;
foreach (System.Data.DataColumn column in Model.Data.Columns)
{
var col = c.Bound(column.ColumnName).Width("300px");
if (index < 2)
{
col.Locked(true).Lockable(false);
}
index++;
}
c.Command(command => { command.Edit();}).Width(100);
}
})
.Editable(editable => editable
.Mode(GridEditMode.PopUp)
.TemplateName("OperationalViewEditor")
)
.Scrollable()
.Reorderable(reorder => reorder.Columns(true))
.Resizable(r => r.Columns(true))
.Filterable(ftb => ftb.Mode(GridFilterMode.Row))
.HtmlAttributes(new { style = "height:100%" })
.Pageable()
.Navigatable()
.Sortable()
.Groupable(g => g.ShowFooter(true))
.ToolBar(tools => tools.Excel())
.Excel(excel => excel.AllPages(true))
.ToolBar(tools => tools.Pdf())
.Pdf(pdf => pdf
.AllPages()
.AvoidLinks()
.PaperSize("A4")
.Scale(0.8)
.Margin("2cm", "1cm", "1cm", "1cm")
.Landscape()
.RepeatHeaders()
.TemplateId("page-template")
.FileName("Export.pdf")
)
)
I have also my getRow function:
<scriprt>
function getRow()
{
var grid = $('#OpertionalViewGrid').data('kendoGrid');
var selectedItem = grid.dataItem(grid.select());
return selectedItem;
} </script>
In my controler I have:
public ActionResult Export_Read([DataSourceRequest]DataSourceRequest request)
{
var ovs = new OperationalViewService();
return Json(ovs.Read()/*.ToDataSourceResult(request)*/);
}
public ActionResult UpdateRow([DataSourceRequest] DataSourceRequest dsRequest, DataRowView row)
{
var t = 5;
return Json(row/*ModelState.ToDataSourceResult()*/);
}
And my edit template:
#model System.Data.DataRowView
<h3>Customized edit template</h3>
#if(Model == null)
{
<label> null</label>
}
else
{
<label> not null!!!!!!</label><br />
#Html.Label(Model.DataView.Table.Columns.Count.ToString())<br />
#Html.Label(Model.ToString())<br />
#Html.Label(Model.Row.Table.Columns.Count.ToString())<br />
}
#for (int i = 0; i < Model.DataView.Table.Columns.Count; i++)
{
#Html.LabelFor(model => model.DataView.Table.Columns[i].ColumnName.ToString())
#Html.LabelFor(model => model.Row[i].ToString())
<br />
}
So.. when I click Edit button, I get a window with proper header, with note "01234 not null!! 0 DataRowView 0 "
So I conclude that model is of proper type, one problem is to pass my selected row.
I am very new to web and Kendo/telerik so my question: how to send my selected grid row to edit template?
Another question is: why when I click "edit" i do not get into UpdateRow action in my controler?
I have ommited the problem by using edit mode InCell - one important note is to specify the column type, as shown here: http://www.telerik.com/forums/inline-batch-crud-fails-with-datatable-model
Related
I am new to ReactiveUI along with DynamicData
Declaration
ReadOnlyObservableCollection<Employee> itemSource;
public ReadOnlyObservableCollection<Employee> ItemSource
{
get => itemSource;
}
SourceList<Employee> Employees = new SourceList<Employee>();
Implementation
Employees
.Connect()
.Sort(SortExpressionComparer<Employee>.Ascending(emp => emp.ID))
.Bind(out itemSource)
.ObserveOn(RxApp.MainThreadScheduler)
.Do(_ =>
{
this.RaisePropertyChanged(nameof(ItemSource));
})
.DisposeMany()
.Subscribe()
.DisposeWith(disposable);
this.WhenAnyValue(x => x.itemSource)
.Do(_ =>
{
Debug.Print("Called");
});
But whenever I am calling
Employees.Add(new Employee
{
Name = "Hello" + DateTime.Now.ToShortDateString(),
ID = random.Next(1,1000)
});
I expect it to print "Called" in debug window as this.WhenAnyValue should be called, but apparently this is not the case.
Could you please help me to understand if I am doing any mistake?
Thanks Glen. I was able to fix it by using below code
this.WhenAnyValue(x => x.itemSource.Count)
.Do(_ =>
{
Debug.Print("Called");
});
I added the Bootstrap dual listbox plugin on my project and it's working fine, but how can I pass the contents of the selected listbox to my controller? It's already inside a form but if I try to get it through FormCollection it returns as null.
View:
<div class="form-group col-md-7" style="margin-left: -15px;">
<select style="display: none;" multiple="multiple" size="10" name="dualListbox" id="dualListbox" class="demo2">
#if (ViewData["Customers"] != null)
{
foreach (var item in ViewData["Customers"] as List<Testbox.Models.Customer>)
{
<option value="customer">#item.NAME #item.LName - #item.PHONE11</option>
}
}
</select>
</div>
Well you can do it as below:
I'll assume that your form id is demoform and below is how the post action method will look like:
[HttpPost]
public ActionResult GetForm()
{
string values = Request.Form["dualListbox"];
//Form[key] will be 'name' property of your select box
//You will get values as comma ',' separated values like option 1,
//option 2, option 4 etc., and I hope you know how you can get each
//options by splitting the comma separated values.
......
......
}
Here is an example to your question. Maybe this will help people in the future.
The trick is in the JS.
Let's say you want to use Bootstrap Dual Listbox in conjuction with ASP.NET MVC 4 and Kendo framework.
We will use the Razor syntax and C#.
First, we write in the view the placeholder for the code. We will be linking a kendo control and the Bootstrap Dual Listbox
<script>
var urlGetCascadeMultiSelectBrandTypeByBrand = "#(Url.Action("GetCascadeMultiSelectBrandTypeByBrand", "DropDownList"))";
</script>
<div class="col-md-12 col-sm-12 col-xs-12 padding-0 ">
<div class="col-md-6 col-sm-6 col-xs-12">
#Html.LabelFor(m => m.BrandId)<br />
#(Html.Kendo().DropDownListFor(m => m.BrandId)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetCascadeDdlBrandBySegment", "DropDownList")
.Data("filterSegments");
})
.ServerFiltering(true);
})
.DataTextField("BrandName")
.DataValueField("BrandId")
.Filter(FilterType.Contains)
.CascadeFrom("SegmentId")
.OptionLabel("Select brand")
.Events(evt => evt.Change("onBrandIdDdlChange"))
.HtmlAttributes(new { #style = "width: 100%;" }))
#Html.ValidationMessageFor(m => m.BrandId)
</div>
<div class="col-md-6 col-sm-6 col-xs-12">
</div>
</div>
<div class="clear height10"></div>
<div class="col-md-12 col-sm-12 col-xs-12 padding-0 ">
<div class="col-md-12 col-sm-12 col-xs-12">
#Html.LabelFor(m => m.BrandTypeIdList)<br />
#if (Model.IsEdit)
{
#Html.ListBoxFor(m => m.BrandTypeIdList, Html.GetBrandTypeByBrandIdSelectListItemsList(Model.BrandId))
}
else
{
#Html.ListBoxFor(m => m.BrandTypeIdList, new List<SelectListItem>())
}
#Html.ValidationMessageFor(m => m.BrandTypeIdList)
</div>
</div>
Then, we create the C# helper code to go with it.
public static IEnumerable<SelectListItem> GetBrandTypeByBrandIdSelectListItemsList(this HtmlHelper htmlHelper, int brandId)
{
using (var dbContext = new Entities())
{
return dbContext.BrandType.Where(x => x.Active == true && x.BrandId == brandId).Select(BrandTypeToDdlSelector).ToList();
}
}
public static Func<BrandType, SelectListItem> BrandTypeToDdlSelector
{
get
{
return (x => new SelectListItem()
{
Value = x.BrandTypeId.ToString(),
Text = x.Name
});
}
}
public JsonResult GetCascadeMultiSelectBrandTypeByBrand(int? brandId)
{
var brandTypesList = DbContext.BrandType.Where(p => p.Active == true);
if (brandId != null)
{
brandTypesList = brandTypesList.Where(p => p.BrandId == brandId);
}
return Json(brandTypesList.Select(x => new { BrandTypeId = x.BrandTypeId, BrandTypeName = x.Name }), JsonRequestBehavior.AllowGet);
}
Then we create the JS code to manipulate the HTML at runtime and bind the selected values to the MVC model.
var brandTypeIdDualListbox = new Object();
$(document).ready(function ()
{
//we create the dual list control
brandTypeIdDualListbox = $('select[name="BrandTypeIdList"]').bootstrapDualListbox({
nonSelectedListLabel: 'Non-selected',
selectedListLabel: 'Selected',
preserveSelectionOnMove: 'moved',
moveOnSelect: false,
});
//we setup the change event for the control
$('select[name="BrandTypeIdList').on('change', function (args)
{
//we traverse every option
$("#BrandTypeIdList option").each(function (index,element)
{
//we check if the element has the `data-sortindex` attribute
if (!!$(element).attr('data-sortindex'))
$(element).attr('selected', 'selected');
else
$(element).removeAttr('selected');
});
})
});
function filterBrands()
{
var brandId = $("#BrandId").val();
if (brandId == "")
brandId = "-1";
return {
BrandId: brandId
};
}
function populateBrandTypeIdDualListbox()
{
$.getJSON(urlGetCascadeMultiSelectBrandTypeByBrand, filterBrands(), function (data)
{
var items;
$.each(data, function (i, item)
{
brandTypeIdDualListbox.append("<option value=" + item.BrandTypeId/*Value*/ + ">" + item.BrandTypeName/*Key or Text*/ + "</option>");
});
brandTypeIdDualListbox.trigger('bootstrapDualListbox.refresh', true); // we refresh the control
});
}
function onBrandIdDdlChange(evt)
{
var brandIdDropDownList = $("#BrandId").data("kendoDropDownList");
$('#BrandTypeIdList').empty();
brandTypeIdDualListbox.trigger('bootstrapDualListbox.refresh', true);
if ($("#BrandId").val() == "" || $("#BrandId").val() == "-1")
{
//if no value is selected we disable the control
$(".bootstrap-duallistbox-container").find("*").prop("disabled", true);
}
else
{
populateBrandTypeIdDualListbox();
$(".bootstrap-duallistbox-container").find("*").prop("disabled", false); // we enable the control
}
}
I am using the Kendo grid in my ASP.Net MVC application. If I have the following grid definition,
#(Html.Kendo().Grid(Model) //Bind the grid to ViewBag.Products
.Name("grid")
.Columns(columns =>
{
columns.Bound(p => p.FullName);
columns.Bound(p => p.MyEnum)
})
.Groupable()
.Pageable()
.Sortable()
.Scrollable(scr => scr.Height(600))
.Filterable()
)
where one of the column is an Enum. My enum definition is:
public enum MyEnum
{
[Display(AutoGenerateField = false, Name = "My enum 1", Description = "My Enum 1")]
EnumOne,
[Display(Name = "My Enum 2")]
EnumTwo
}
How do I make it display "My Enum 1" or "My Enum 2" for each row?
Thanks in advance!
I recently ran into this problem and solved it by using
var someArrayOfValueAndText = new[] {new {
Id = 0, Description = "Foo"
}, new {
Id = 1, Description = "Bar"
}
.Columns(c.ForeignKey(m=> m.MyEnum, someArrayOfValueAndText, "Id","Description"))
instead of the .Bound method
I created an helper class containing some extension methods a while back:
public static class EnumExtensions
{
public static string GetDisplayName(this Enum enu)
{
var attr = GetDisplayAttribute(enu);
return attr != null ? attr.Name : enu.ToString();
}
public static string GetDescription(this Enum enu)
{
var attr = GetDisplayAttribute(enu);
return attr != null ? attr.Description : enu.ToString();
}
private static DisplayAttribute GetDisplayAttribute(object value)
{
Type type = value.GetType();
if (!type.IsEnum)
{
throw new ArgumentException(string.Format("Type {0} is not an enum", type));
}
// Get the enum field.
var field = type.GetField(value.ToString());
return field == null ? null : field.GetCustomAttribute<DisplayAttribute>();
}
}
It contains two methods for extracting the Name and Description of a Display attribute. The display name:
columns.Bound(p => p.MyEnum.GetDisplayName())
And for a description:
columns.Bound(p => p.MyEnum.GetDescription())
You have to add a using statement in your Web.config or in your view.
Update
What if you create a property for it in your model:
public string MyEnumName
{
get { return MyEnum.GetDisplayName(); }
}
Now you should be able to use:
columns.Bound(p => p.MyEnumName);
Henk's solution is good. But you can use filtering capability if you use ClientTemplate:
col.Bound(m => m.MyEnum) // this provides you filtering
.ClientTemplate("#: MyEnumName #") // this shows a name of enum
For more information about kendo ui templates see: http://docs.telerik.com/kendo-ui/framework/templates/overview
I use #user1967246 method and would like to explain more how to i do.
i created array in top of my kendo grid
var statusLikeEntityStatus = new[]
{
new {Id = 0, Status = EntityStatus.Passive},
new {Id = 1, Status = EntityStatus.Active},
new {Id = 2, Status = EntityStatus.Draft},
new {Id = 3, Status = EntityStatus.ReadyToLive},
new {Id = -1, Status = EntityStatus.Freezed},
new {Id = -2, Status = EntityStatus.Blocked}
};
Then i use ForeignKey property instead of Bound.
columns.ForeignKey(m => m.Status, statusLikeEntityStatus, "Id", "Status").Title(Resources.General.Status);
Here is my columns attribute
.Columns(columns =>
{
columns.Bound(m => m.InventoryID).Title("Id");
columns.Bound(m => m.ERPCode).Title(Resources.Products.ProductCode);
columns.Bound(m => m.Price).Title(Resources.Products.ListPrice);
columns.Bound(m => m.Discount).Title(Resources.Products.
columns.Bound(m => m.Stock).Title(Resources.Products.TotalStock); // todo: Resources
columns.ForeignKey(m => m.Status, statusLikeEntityStatus, "Id", "Status").Title(Resources.General.Status);
columns.Command(commandConf =>
{
commandConf.Edit();
commandConf.Destroy();
});
})
Hope it will help to you.
I have a kendoUI grid.
#(Html.Kendo().Grid<EntityVM>()
.Name("EntitesGrid")
.HtmlAttributes(new { style = "height:750px;width:100%;scrollbar-face-color: #eff7fc;" })
.Columns(columns =>
{
columns.Bound(e => e.Id).Hidden().IncludeInMenu(false);
columns.Bound(e => e.EntityVersionId).Hidden().IncludeInMenu(false);
columns.Bound(e => e.Name).Width("70%").Title("Entity Name");
columns.Bound(e => e.EIN).Width("30%");
})
.ToolBar(toolBar => toolBar.Template("<a class='k-button k-button-icontext k-grid-add' id='addEntity'><span class='k-icon k-add'></span>Entity</a>" +
"<a class='k-button k-button-icontext' id='editEntity'><span class='k-icon k-edit'></span>Edit</a>"))
.DataSource(dataSource => dataSource
.Ajax().ServerOperation(false)
.Model(model => model.Id(e => e.Id))
.Read(read => read.Action("GetEntities", "Entity", new { projectId = Request.QueryString[DataKeyNameConstants.ProjectId] })))
.Sortable()
.Scrollable()
.Filterable()
.Resizable(resize => resize.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
.ColumnMenu()
.Selectable(s => s.Mode(GridSelectionMode.Multiple))
.Events(events => events.Change("entSelChange"))
)
now, I need to get the value of EntityVersionId from the selected Row. but not sure how to do it.
here's my javascript function
$("#editEntity").click(function () {
var entityGrid = $("#EntitesGrid").data("kendoGrid");
// what should I do from here
});
UPDATE: add code to loop all rows.
function loadPreviousEntityVersion() {
alert("sdfsdfsdf");
var entityGrid = $("#EntitesGrid").data("kendoGrid");
var data = entityGrid.dataSource.data();
for(var i = 0; i<data.length; i++) {
var currentDataItem = data[i];
alert(dataItem.EntityVersionId);
}
}
One way is to use the Grid's select() and dataItem() methods.
In single selection case, select() will return a single row which can be passed to dataItem()
var entityGrid = $("#EntitesGrid").data("kendoGrid");
var selectedItem = entityGrid.dataItem(entityGrid.select());
// selectedItem has EntityVersionId and the rest of your model
For multiple row selection select() will return an array of rows. You can then iterate through the array and the individual rows can be passed into the grid's dataItem().
var entityGrid = $("#EntitesGrid").data("kendoGrid");
var rows = entityGrid.select();
rows.each(function(index, row) {
var selectedItem = entityGrid.dataItem(row);
// selectedItem has EntityVersionId and the rest of your model
});
There is better way. I'm using it in pages where I'm using kendo angularJS directives and grids has'nt IDs...
change: function (e) {
var selectedDataItem = e != null ? e.sender.dataItem(e.sender.select()) : null;
}
I think it needs to be checked if any row is selected or not?
The below code would check it:
var entityGrid = $("#EntitesGrid").data("kendoGrid");
var selectedItem = entityGrid.dataItem(entityGrid.select());
if (selectedItem != undefined)
alert("The Row Is SELECTED");
else
alert("NO Row Is SELECTED")
If you want to select particular element use below code
var gridRowData = $("<your grid name>").data("kendoGrid");
var selectedItem = gridRowData.dataItem(gridRowData.select());
var quote = selectedItem["<column name>"];
I have a partial view where I render, if the user has choosen an option, a button that permit the user to generate automatically a value for a certain field. Please give a look at this picture to understand what I mean:
This is achieved using the following markup on the partial view
<%= Html.LabelFor( model => model.IssueCode )%>
<br />
<% if ( Model.HasCodeGenerator ) { %>
<%= Html.TextBoxFor( model => model.IssueCode, new { style = "width:120px;background-color:#eeeeee;border: solid 2px #dfdfdf", #readonly = "readonly" } )%>
<% if (Model.ModelState == ModelStateEnum.Add) { %>
<button id="codeGenerator" style="font-size: 0.7em;margin-right: 10px">Genera codice fascicolo</button>
<% } %>
<% } else { %>
<%= Html.TextBoxFor(model => model.IssueCode, new { style="width: 120px" })%>
<% } %>
<%= Html.ValidationMessageFor(model => model.IssueCode, "*")%>
As you can see I append always an Html.ValidationMessageFor() at the end of the input field and a ValidationSummary aut the end of the view.
When the user submits the form the first block of code executed by the action is the following
if ( !ModelState.IsValid ) {
//Invalid - redisplay form with errors
return PartialView( "IssueCodeGenerator", model );
}
and this is the result I am getting in all of the three cases
Why the markup code for the button disappear?
Thanks for helping!
1st EDIT:
After validation the IssueCode textbox loose it's readonly="readonly" attribute. This means that the first condition is not meet, I think....
2nd EDIT:
As per the Darin comment I am including
The action that show the Partial View
An extract of the partial that show that the ModelState variable is kept as an hidden control inside the form
The controller Action called by the Partial
The jQuery code that submit the partial
1 - This is the action that shows the partial
[HttpGet]
public ActionResult Create()
{
IssueModel im = new IssueModel()
{
ModelState = ModelStateEnum.Add,
FirmID = _firmManager.GetMyFirmID(),
CreatedDate = DateTime.Now,
LastUpdateDate = DateTime.Now,
HasCodeGenerator = _optionManager.HasIssueCodeGenerator()
};
return PartialView("Issue", im);
}
2 - Extract of the partial Issue.ascx
<% using (Html.BeginForm("SaveOrDelete", "Issue", FormMethod.Post, new { id = "crudForm" })) { %>
<%= Html.HiddenFor(model => model.FirmID) %>
<%= Html.HiddenFor(model => model.IssueID) %>
<%= Html.HiddenFor(model => model.ModelState) %>
3 - This is the controller action called when the form is submitted
[HttpPost]
public ActionResult SaveOrDelete( IssueModel model ) {
if ( !ModelState.IsValid ) {
//Invalid - redisplay form with errors
return PartialView( "Issue", model );
}
try {
Issue i = null;
if ( model.ModelState == ModelStateEnum.Add )
i = new Issue();
else
i = _manager.FindIssueByIssueID( model.IssueID );
if ( model.ModelState != ModelStateEnum.Delete ) {
_manager.BindIssueModel( i, model );
if ( model.ModelState == ModelStateEnum.Add )
i.FirmID = _contactManager.GetMyContact().FirmID;
i.LastUpdateDate = DateTime.Now;
_manager.SaveIssue( i );
} else {
_manager.DeleteIssue( i );
}
return PartialView( "ActionCompleted" );
}
catch ( Exception ex ) {
return PartialView( "ActionError",
new ActionErrorModel() { Message = ex.Message } );
}
}
4 - This is the jQuery code that submit the form
$("#crudForm").submit(function(event) {
event.preventDefault();
$("#crudForm").block();
$.ajax({
type: "post",
dataType: "html",
url: "/Issue/SaveOrDelete",
sync: true,
data: $("#crudForm").serialize(),
success: function(response) {
$("#crudForm").parent().html('').html(response);
$("#crudForm").unblock();
},
error: function(response) {
$("#crudForm").unblock();
}
});
});
Hope that this would help in finding the problem. Thank you.
Because Model.ModelState == ModelStateEnum.Add evals to false?
MVC won't turn off your button html...
Even without seeing the form its pretty clear that Darin is right and your Modelstate enum is getting set to null.