I'm trying to set up batch edit on a grid in Kendo like the sample on their demo site- http://demos.kendoui.com/web/grid/editing.html . Everything seems set up correctly and it's posting the data correctly (it would seem) from the grid to the server. When I look at the post data in firebug it is all correct, but on the server when debugging the models sent back all contain null or empty string values. The number of models is showing correctly in the .Count, but they are empty. Here is my code and output, sorry I can't post images yet, not enough points on site yet:
aspx page:
<%: Html.Kendo().Grid<Thread.Site.Models.ModelSummary>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(m => m.ModelID).Hidden();
columns.Bound(m => m.ModelNumber).Width(100).ClientTemplate("#= (ModelNumber === 'null') ? ' ' : ModelNumber #");
columns.Bound(m => m.ModelName);
columns.Bound(m => m.Content).Width(160);
columns.Bound(m => m.Bullet1);
columns.Bound(m => m.Bullet2);
columns.Bound(m => m.Bullet3);
columns.Bound(m => m.Bullet4);
columns.Bound(m => m.Bullet5);
columns.Bound(m => m.Bullet6);
columns.Bound(m => m.AlertCount).ClientTemplate("# if (AlertCount > 0) { # <span class='icons icons-alert viewCheck' title='#= AlertCount # Alert(s)'></span> #}#").Title("Attention");//"#= (AlertCount === 0) ? ' ' : AlertCount #").Title("Attention");//
})
.Pageable()
.ToolBar(
toolbar => {toolbar.Save();}
)
.Editable(edit => { edit.Mode(Kendo.Mvc.UI.GridEditMode.InCell); })
.Navigatable(n => { n.Enabled(true);})
.Sortable()
.Scrollable(s=>s.Height(500))
.Selectable(selectable => selectable.Mode(Kendo.Mvc.UI.GridSelectionMode.Single))
.Filterable()
.Events(events =>
{
events.DataBound("dataBound");
events.Edit("edit");
events.Change("change");
})
.DataSource(dataSource => dataSource
.Ajax()
.Batch(true)
.ServerOperation(false)
.PageSize(15)
.Events(events => events.Error("error_handler"))
.Model(model =>
{
model.Id(j => j.ModelID);
model.Field(j => j.ModelID).Editable(false);
model.Field(j => j.ModelNumber).Editable(false);
})
.Read(read => read.Action("ModelList_Read", "Models", new { jobID = job.JobID }))
.Update(update => update.Action("ModelList_SaveAll", "Models").Type(HttpVerbs.Post))
)
%>
controller:
[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ModelList_SaveAll([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")] IEnumerable<Thread.Site.Models.ModelSummary> modelSummary)
{
if (modelSummary != null)
{
foreach (Thread.Site.Models.ModelSummary _modelSummary in modelSummary)
{
ModelRepository.SetModelCopies(CurrentUser.ProfileID, modelCopiesSend);
}
}
return Json(new[] { modelSummary }.ToDataSourceResult(request, ModelState), JsonRequestBehavior.AllowGet);
}
Post Data Going to the Server:
models[0][ActiveFlag] false
models[0][AlertCount] 0
models[0][Bullet1ID] 0
models[0][Bullet1] test bullet 1
models[0][Bullet2ID] 0
models[0][Bullet2] test bullet 2
models[0][Bullet3ID] 0
models[0][Bullet3]
models[0][Bullet4ID] 0
models[0][Bullet4]
models[0][Bullet5ID] 0
models[0][Bullet5]
models[0][Bullet6ID] 0
models[0][Bullet6]
models[0][CompanyID] 16
models[0][Complete] false
models[0][ContentID] 0
models[0][Content] test description here
Debug model (_modelSummary in controller) on server, all data is empty or null:
modelSummary.Count = 1
Bullet1 null string
Bullet1ID 0 int
Bullet2 null string
Bullet2ID 0 int
Bullet3 null string
Bullet3ID 0 int
Bullet4 null string
Bullet4ID 0 int
Bullet5 null string
Bullet5ID 0 int
Bullet6 null string
Bullet6ID 0 int
CompanyID 0 int
Thanks for any help on this.
I modified your DataSource Model. Your primary ID must be defaultvalue .
.Model(model =>
{
model.Id(j => j.ModelID);
model.Field(p => p.ModelID).DefaultValue(16000000);
model.Field(j => j.ModelID).Editable(false);
model.Field(j => j.ModelNumber).Editable(false);
})
Related
So I've got a grid that I believe is all set up correctly. I've confirmed that the data is coming through, and I've even checked that the AJAX call returns a success with the "ToDataSourceResult" JSON data.
Unfortunately, the only problem is that the data doesn't display. This seems to only be an issue on read, as update, create and delete all work. Just can't retrieve the list of all items afterwards.
My controller action looks like this:
public IActionResult Blog_Read([DataSourceRequest] DataSourceRequest request)
{
var blogs = _blogService.GetPosts().Select(post => new BlogPostModel
{
Id = post.Id,
Title = post.Title,
Author = post.Author,
ShortDescription = post.ShortDescription,
Contents = post.Contents,
LastSaved = post.LastSaved,
Published = post.Published,
PublishedOn = post.PublishedOn
});
var result = blogs.ToDataSourceResult(request);
return Json(result);
}
And my Grid View looks like this:
#(Html.Kendo().Grid<BlogPostModel>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(p => p.Title);
columns.Bound(p => p.Author).Width(120);
columns.Bound(p => p.LastSaved).Width(120);
columns.Bound(p => p.Published).Width(120);
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(250);
})
.ToolBar(toolbar => toolbar.Create())
.Editable(editable => editable.Mode(GridEditMode.PopUp))
.Pageable()
.Sortable()
.Scrollable()
.HtmlAttributes(new { style= "height:600px;"})
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Events(events => events.Error("error_handler"))
.Model(model => model.Id(p => p.Id))
.Create(update => update.Action("Blog_Create", "BlogAdmin"))
.Read(read => read.Action("Blog_Read", "BlogAdmin"))
.Update(update => update.Action("Blog_Update", "BlogAdmin"))
.Destroy(update => update.Action("Blog_Delete", "BlogAdmin"))
)
.Deferred()
)
The correct JSON is returned, no javascript errors in the console, so I'm a little confused as to what this could be. Any help would be greatly appreciated.
I solved this by adding
services.AddMvc().AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
to my Startup.cs ConfigureServices method.
By default it looks like Telerik Grid for MVC3 submits only the rows marked as "dirty" to my controller. I need to be able to submit all rows on a Telerik Grid to my controller. In other words I think I need to mark all rows as changed so the grid will send all rows to my controller.
I am using Ajax data binding as in:
.DataBinding(dataBinding => dataBinding
.Ajax()
.Select("GetData", "ModuleAccess", new { roleId = #ViewBag.RoleId, appId = #ViewBag.AppId })
.Update("SaveBatchEditing", "ModuleAccess")
#(Html.Telerik().Grid<BarcodeListModel>()
.Name("orders-grid")
.ClientEvents(events => events.OnDataBinding("onDataBinding"))
.DataKeys(keys =>
{
keys.Add(x => x.Id);
})
.ToolBar(commands =>
{
commands.SubmitChanges();
})
.DataBinding(dataBinding =>
dataBinding.Ajax()
.Select("BulkEditSelect", "ProductVariant")
.Update("BulkEditSaveBarcode", "ProductVariant")
.Delete("DeleteBarcode", "ProductVariant")
)
.Columns(columns =>
{
columns.Bound(x => x.Id).ReadOnly();
columns.Bound(x => x.SKU);
columns.Bound(x => x.barcode);
//columns.Bound(x => x.Id)
// .Template(x => Html.ActionLink(T("Admin.Common.View").Text, "DeleteBarcode", new { id = x.Id }))
// .ClientTemplate("" + "Delete" + "")
// .Width(50)
// .Centered()
// .HeaderTemplate("DeleteBarcode")
// .Filterable(false)
// .Title("Delete");
columns.Command(commands => commands.Delete()).Width(180);
})
.Pageable(settings => settings.PageSize(gridPageSize).Position(GridPagerPosition.Both))
.DataBinding(dataBinding => dataBinding.Ajax().Select("BarcodeList", "ProductVariant", Model))
.Editable(editing => editing.Mode(GridEditMode.InCell))
.EnableCustomBinding(true)
)
use like this code
I found the answer:
function ModuleAccessGridHasChanges() {
var grid = $("#ModuleAccessGrid").data("tGrid");
if (grid != null) {
var additionalValues = grid.data;
if (!$.telerik.trigger(grid.element, 'submitChanges', { values: additionalValues })) {
grid.sendValues($.extend({}, additionalValues), 'updateUrl', 'submitChanges');
}
}
}
Fiddler shows all the data for the grid coming accross:
So I can make this work fine in newer browsers, but in IE9 when a date is clicked on the datepicker the cell turns back as unselected, empty and not dirty.
An example of my code is
MODEL
public string name { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}", NullDisplayText = "")]
[Display(Name = "Actual Start")]
public DateTime? ActualStartDate { get; set; }
public DateTime? ActualEndDate { get; set; }
GRID
Html.Kendo().Grid<MilestoneDto>()
.Name("editMilestoneList")
.Columns(columns =>
{
columns.Bound(m => m.Name).Title("Name");
columns.Bound(m => m.Status).EditorTemplateName("_milestoneStatus");
columns.Bound(m => m.PlannedStartDateStringValue);
columns.Bound(m => m.ProjectedStartDateStringValue);
columns.Bound(m => m.ActualStartDate).EditorTemplateName("GenericDatePicker");
columns.Bound(m => m.PlannedEndDateStringValue);
columns.Bound(m => m.ProjectedEndDateStringValue);
columns.Bound(m => m.ActualEndDateStringValue).EditorTemplateName("GenericDatePicker");
columns.Bound(m => m.CommentCount).ClientTemplate("#=CommentCount#</span>#}else{#<span class=\"fa fa-plus-circle\"></span>#}#").Title("Comments").Sortable(false).IncludeInMenu(false);
})
.HtmlAttributes(new { #class = "hidden results table-responsive" })
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("DataSource", "Milestone").Data("additionalParams"))
.Update(update => update.Action("BatchEdit", "Milestone"))
.Batch(true)
.Events(e => e.Sync("SyncGrid"))
.ServerOperation(false)
.Model(m => {
m.Id(mf => mf.Id);
m.Field(f => f.Name).Editable(false);
m.Field(f => f.Status).Editable(ViewBag.IsBaselined);
m.Field(f => f.PlannedStartDateStringValue).Editable(false);
m.Field(f => f.PlannedEndDateStringValue).Editable(false);
m.Field(f => f.CommentCount).Editable(false);
m.Field(f => f.ProjectedStartDateStringValue).Editable(false);
m.Field(f => f.ProjectedEndDateStringValue).Editable(false);
m.Field(f => f.ActualStartDate).Editable(ViewBag.IsBaselined);
m.Field(f => f.ActualEndDate).Editable(ViewBag.IsBaselined);
})
)
.Editable(editable => editable.Mode(GridEditMode.InCell))
.ColumnMenu()
.Filterable()
.Sortable();
}
EDITOR TEMPLATE
#model DateTime?
#Html.TextBoxFor(model => model, new { #class="k-textbox bootStrapDatePicker form- control" })
<script type="text/javascript">
$('.bootStrapDatePicker').datepicker({ startDate: '0', format: "m/d/yyyy", autoclose: true });
</script>
You have two (better) options that will automatically set up the DateTimePicker for you:
1) In the grid columns/models, use your ActualStartDate properties. Then you can use the .Format() method on your columns to format it how you'd like.
2) I don't know what the exact syntax is, but when you're defining the Model in the Grid, I I believe there is a DataType() or similar method to set it as a date time.
It's been a while but it turns out the problems was the version of jquery was incorrect.
I have Kendo Grid with delete command. When I click delete and then click "save change" on the left top of grid, real data is not sent to server. data has key/create date/other fields. I used Odata service. In debug mode, key = 0 and create date = 1/1/0001. Anyone got a clue what is happening here?
#(Html.Kendo().Grid<OData.proxySvc.table1>()
.Name("MyGrid")
.Columns(columns =>
{
columns.Bound(f => f.key).Visible(false);
columns.Bound(f => f.UserName).Title("Name");
columns.Command(command => {
command.Destroy();
}).Title("Action").Width(90);
})
.ToolBar(toolbar =>
{
toolbar.Save();
})
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Sortable()
.Scrollable(s => s.Height("100px"))
.Filterable()
.DataSource(ds => ds
.Ajax()
.Batch(true)
.ServerOperation(false)
.Model(model => model.Id(p => p.key))
.Destroy("Delete","Home")
))
in control file, there is action:
// no [Httppost] attributes. if [HttpPost] attributes exist, no event fire
public ActionResult Delete([DataSourceRequest]DataSourceRequest request,
[Bind(Prefix = "models")]IEnumerable<table1> tbl1)
{
var context = CreateOdataServiceContext();
foreach (var t1 in tbl1)
{
var x = context.table1.Where(r => r.key == t1.key).FirstOrDefault();
if (x!=null)
{
context.DeleteObject(x);
context.SaveChanges();
}
}
}
I am using Ajax binding and so I am assuming that if I want the total to update after the user edits a change, I need the ClientFooterTemplate as opposed to just the FooterTemplate which works.
Here is my grid which works with FooterTemplate:
#{
GridEditMode mode = (GridEditMode)ViewData["mode"];
GridButtonType type = (GridButtonType)ViewData["type"];
GridInsertRowPosition insertRowPosition = (GridInsertRowPosition)ViewData["insertRowPosition"];
Html.Telerik().Grid<RedFile.Models.QuickQuoteItemView>("items")
.Name("QuoteItems")
.DataKeys(k => k.Add(o => o.Id))
.ToolBar(commands => commands.Insert().ButtonType(type).ImageHtmlAttributes(new { style = "margin-left:0" }))
.Columns(c =>
{
c.Bound(o => o.Id).ReadOnly().Hidden();
c.Bound(o => o.ItemID);
c.Bound(o => o.Description);
c.Bound(o => o.ItemQty);
c.Bound(o => o.ItemPrice).Format("{0:c}");
c.Bound(o => o.LineTotal)
.Width(100)
.Aggregate(ag => ag.Sum())
.FooterTemplate(result => (result.Sum == null ? "0.00" : result.Sum.Format("{0:c}")))
.Format("{0:c}");
c.Command(s =>
{
s.Edit();
s.Delete();
});
})
.Editable(editing => editing.Mode(mode).InsertRowPosition(insertRowPosition))
.DataBinding(b => b.Ajax()
.Select("GridSelect", "QuickQuote")
.Insert("GridInsert", "QuickQuote", new { qqid = Model.Id })
.Update("GridUpdate", "QuickQuote", new { qqid = Model.Id })
.Delete("GridDelete", "QuickQuote", new { qqid = Model.Id })
)
.Footer(true)
.Render();
}
If I change the footer template to something like this: (I have tried multiple variations with the same result)
.ClientFooterTemplate("<#= $.telerik.formatString('{0:c}', Sum) #>")
The total simply disappears.
All I want is a total that updates after the user changes something. Any idea what I'm doing wrong?
Thanks
columns.Bound(p => p.ItemPrice)
.FooterTemplate(
#<text>
Total:#string.Format("{0:c}", Model.ItemPrice)
</text>
)
.Width(100)
.Format("{0:c}");
Refer to Teleriks MVC grid Documentation