Post kendo grid values - model-view-controller

Below is the Kendo grid
#(Html.Kendo().Grid<CS.Web.Models.People.GroupDetailModel>()
.Name("Grid")
.Events(e => e.DataBound("LineItems_Databound"))
.HtmlAttributes(new { style = "overflow:hidden;", #class = "normalgrid" })
.Columns(columns =>
{
columns.Bound(p => p.GroupID).Hidden();
columns.Bound(p => p.GroupName).Title("Group Name").Width(30);
columns.Bound(p => p.Department).Title("Department Name").Width(30);
columns.Bound(p => p.IsBlindSettingsEnable).Title("Blind Group")
.ClientTemplate("<input type=\"checkbox\" #= IsBlindSettingsEnable ? \"checked=checked\": \"\" # enabled=\"enabled\" />")
.Width(30);
columns.Bound("Department").Title("Remove")
.ClientTemplate("<a href='javascript:void(0)' Title='Remove' onclick='return removeUserGroupRelation(+#=GroupID#+);'> <img alt='Remove' src='" + #Url.Content("~/Content/Images/delete_icon.png") + "' /></a>")
.Width(30);
})
.Sortable()
.Scrollable(scrollable => scrollable.Virtual(false))
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("getAssignedGroups", "People")
.Data("setRoutesValues")
)
//new { MerchantId = ViewBag.MerchantId, StartDate = Model.StartDate, EndDate = Model.EndDate }
)
.TableHtmlAttributes(new { #class = "grid_1" })
)
Below is the javascript code
var userID = '#ViewBag.UserID'
$.ajax({
url: '#Url.Action("SaveGroupsUserDetails")',
type: "POST",
dataType: "json",
data: { models: kendo.stringify($("#Grid").data("kendoGrid").dataSource.view()), UserID: userID },
success: function (result) {
}
});
Here in my kendo grid there is checkbox column.When i check or uncheck checkbox at CLIENT sied(in browser).And Do post via give javascript $.ajax post,it will not post the values of checkboxes which I have changed on client browser,it shows the values which it was binded from server side.
so,my question is to I want updated values to post on server which are modified on client browser.
I shall be very thankfull if you provide me answer.

You should just update your datasource on checkbox checked :
...
.ClientTemplate("<input type=\"checkbox\" #= IsBlindSettingsEnable ? \"checked=checked\": \"\" # enabled=\"enabled\" onclick='setChecked(this)' />")
...
function setChecked(cb) {
var row = $(cb).closest("tr");
var item = grid.dataItem(row);
item.IsBlindSettingsEnable = cb.checked;
}
and now your datasource is synced with the view

I believe this is because your looking at the actual value of the dataSource and not the grid itself. Your grid is non-editable. You are manually throwing the inputs into your grid and these will not effect the dataSource.
You can take two approaches do this kind of update.
You can leave the grid the way you have it set up and handle this update solely though Java Script.
To do this you will need to look up all the dataItems you need to update manually with JQuery.
You can lookup all of your check boxes with in that grid that are check, then get the relevant dataItem manually. Here is a short example showing how to get a dataItem from a row in the grid.
//checkbox is a JQuery object referencing one of your checkboxes
var row = $(checkbox).closest("tr");
var grid = $("#grid").data("kendoGrid");
var data = grid.dataItem(row);
Once you have all of your dataItems that are relevant you can then post your update. You would then have to reload your grid to get the updated status of these items.
Overall this is not the preferred way to do this kind of update with a kendo grid.
I suggest this second method.
This is the site where I will be pulling examples from: http://demos.telerik.com/aspnet-mvc/grid/editing
First you will need to make your kendo grid editable .Editable(editable => editable.Mode(GridEditMode.InCell)). You will not need the custom template that adds the checkbox anymore. It will automatically add them when you are editing your grid now.
You will need to then set the datasource to have an update function and have your server expect this update.
Your dataSource binding
.DataSource(dataSource => dataSource
.Ajax()
.Batch(true)
.Read("Editing_Read", "Grid")
.Update("Editing_Update", "Grid")
)
And your server side code
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Editing_Update([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<ProductViewModel> products)
{
if (products != null && ModelState.IsValid)
{
foreach (var product in products)
{
productService.Update(product);
}
}
return Json(products.ToDataSourceResult(request, ModelState));
}
By returning this Json object your grid will auto update to the new values. This is the preferred way to edit a grid.

Related

Get dataitem in transport.read.data() function from kendo Dropdownlist inline editor on a grid

I have a kendo dropdownlist on a Kendo grid (more specifically, it is using the Telerik MVC wrappers). When the "Edit" button is clicked on the row for the grid, the dropdownlist gets its data from an ajax jsonresult DataSource in my controller. I want to pass an Id to this datasource method so I can filter the results based on this id. However, this ID exists against the row in the table which contains the inline dropdownlist editor.
I'm looking to get the dataItem of the row which contains the dropdownlist through it's transport.read.data() function. I passed in e as a parameter to the function, but it doesn't seem to contain anything useful like e.sender. The this object doesn't reference the element, therefore I can't seem to use it for anything useful either. The best I've done so far is to get a reference to the grid (so I have access to the grid.dataItem function, but I can't pass anything meaningful into it to get the dataItem of the currently active row.
Here's a simplified version of the grid, excluding other unnecessary fields, etc.
#(Html.Kendo().Grid<Grants.ViewModels.ScheduleOfWorkItemViewModel>()
.Name("NewScheduleOfWorkItems")
.Columns(columns =>
{
columns.Bound(col => col.ScheduleOfWorkItemID).Visible(false);
columns.Bound(col => col.PercentageItemComplete).HtmlAttributes(new { #class = "cell-percentage-item-complete" }).Title("% Comp").Width(100).Format("{0:P2}").EditorTemplateName("SORREFPercentageItemComplete");
columns.Command(commandCol =>
{
commandCol.Edit();
commandCol.Destroy();
}).Width(100);
})
.Sortable()
.Pageable(pageable => pageable.Refresh(true).PageSizes(new List<object> { 10, 20, "all" }).ButtonCount(5))
.DataSource(dataSource => dataSource
.Ajax()
.Create(create => create.Action("Add_ScheduleOfWorkItem", "ScheduleOfWork"))
.Update(create => create.Action("Add_ScheduleOfWorkItem", "ScheduleOfWork"))
.Read(read => read.Action("GetScheduleOfWorkItems", "ScheduleOfWork").Data("GetIDForGetScheduleWorkItems"))
.Model(model =>
{
model.Id(c => c.ScheduleOfWorkItemID);
model.Field(c => c.ConcatenatedRenderedDescription).Editable(false);
model.Field(c => c.UnitTypeName).Editable(false);
model.Field(c => c.Cost).Editable(false);
model.Field(c => c.AdjustedTotal).Editable(false);
})
.Destroy(delete => delete.Action("RemoveScheduleItemFromScheduleOfWork", "ScheduleOfWork"))
.Sort(sort => sort.Add("ScheduleItemOrderNo").Ascending()) // <-- initial sort expression
)
.Editable(editable => editable.Mode(GridEditMode.InLine))
.Events(events =>
{
events.Edit("onSORREFEdit");
events.Save("onSORREFSave");
events.DataBound("onSORREFDataBound");
})
)
Here's the Dropdown list editor template
#(Html.Kendo().DropDownList()
.Name("SORREFPercentageItemCompleteId")
.DataTextField("PercentageGrantItemCompleteText")
.DataValueField("PercentageGrantItemCompleteId")
.DataSource(source => {
source.Read(read =>
{
read.Action("GetPercentageGrantItemCompleteLookups", "ScheduleOfWork").Data("SORREFPercentageItemCompleteData");
});
})
.HtmlAttributes(new { style = "width: 100%" })
.OptionLabel("Percentage complete...")
.Events(events =>
{
events.Select("onSORREFPercentageItemCompleteSelect");
})
)
and here's my JS function for returning data, so far, which doesn't work.
var SORREFPercentageItemCompleteData = function (e) {
var $tr = $($(this)[0].element).closest("tr"); // "this" is useless? - how can i get my tr?
var grid = $("#NewScheduleOfWorkItems").data("kendoGrid"); // grid id ok
var dataItem = grid.dataItem($tr);
return { scheduleOfWorkItemId: dataItem.ScheduleOfWorkItemID };
}
Change the dropDownList dataSource transport read from a URL string to a configuration item that contains
the URL
a custom container field that refers to the edit row container
the data item as a function that returns the additional parameters for the URL
the function will use the container to find the row to find the grid and the rows model ID value
The following code is in dojo https://dojo.telerik.com/#RichardAD/uZIguWAn which is based on demo https://demos.telerik.com/kendo-ui/grid/editing-custom.
The end-game is that the drop down ajax data query will contain the extra parameter productID = productID of row selected
function categoryDropDownEditor(container, options) {
$('<input required name="' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
autoBind: false,
dataTextField: "CategoryName",
dataValueField: "CategoryID",
dataSource: {
type: "odata",
transport: {
// originally
// read: "https://demos.telerik.com/kendo-ui/service/Northwind.svc/Categories"
// magical tweakage
read:
{
container: container, // make container available to data function
url: "https://demos.telerik.com/kendo-ui/service/Northwind.svc/Categories"
// see API documentation for transport.read.data
// https://docs.telerik.com/kendo-ui/api/javascript/data/datasource/configuration/transport.read#transport.read.data
, data: function (e) {
grid = this.container.closest(".k-grid").data("kendoGrid");
rowuid = this.container.closest("tr").data("uid");
rowIdField = grid.dataSource.options.schema.model.id;
result = {};
result [rowIdField] = grid.dataSource.getByUid(rowuid)[rowIdField];
return result;
}
}
What I do for this case is just use the Edit event of the grid.
When the user goes and tries to edit a row the event will give you the id you want.
Pass it to a global variable in your js like
var selectedRowId = // the row id
and add this parameter to be returned on your dropdownlist read.
return { scheduleOfWorkItemId: selectedRowId };
I know it is not the most elegant solution but it has worked for me and I believe is quite easy.

Kendo DataSource requestEnd event gets fired multiple times

I am using Telerik UI for ASP.NET MVC and i have grid defined as below
#(Html.Kendo().Grid<GridModel>()
.Name("grid")
.Columns(col =>
{
col.Bound(o => o.ID)
.ClientTemplate("<input class = 't-checkbox-selectrow' type='checkbox' value='#=ID#'/><label></label>")
.HeaderTemplate("<input class = 't-checkbox-selectallrows' type='checkbox' id='selectAll'/><label></label>")
.Sortable(false)
.Filterable(false)
.HtmlAttributes(new { #class = "t-gridcol-selectrow" })
.Width(40)
.Locked(true).Lockable(false);
col.Bound(o => o.StatusName).Width(150);
col.Bound(o => o.Deadline).Width(120);
col.Bound(o => o.Cost).Width(150);
})
.AutoBind(false)
.Pageable(x => x.PageSizes(UIConstants.PageSizes))
.Sortable(x => x.AllowUnsort(false))
.Resizable(resizing => resizing.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
.Scrollable(s => s.Height("Auto"))
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(UIConstants.DefaultPageSizeMax)
.Read(read => read
.Action("GetData", "DataProvider"))
.ServerOperation(false))
)
Then in the JS file i am resetting the grid's page to 1 onRequestEnd, So user always goes back to first page whenever i fetch the data from remote service
$(function(){
var ds = $("#grid").data("kendoGrid").dataSource;
ds.bind("requestEnd", function (e){
e.sender.page(1);
})
})
As per the kendo's documentation
requestEnd
Fired when a remote service request is finished.
However the requestEnd event also gets fire on page change (and sorting). So when i change the page programmatic it fires the requestEnd event again and goes into loop. ( note requestEnd also gets fired when i change Page or Sort manually on UI)
Is this is by design or wrong documentation?
i did something like below. e.response will be only populated when requestEnds as part of response from server. In all other cases it will null.
dataSource.bind("requestEnd", function (e) {
if (e.status != "error" && e.response != null) {
// do soemething here
}
I would really like kendo team either fix the issue or create new event
This question was asked 3 years ago, but I am coming across it while looking up some other information. While I am here, I will answer it for others, as LP13 is likely not concerned about this anymore.
In the HTML Razer code, add the RequestEnd event to the DataSource. Here is an example:
#(Html.Kendo().Grid<GridModel>()
.Name("grid")
// (snip)
.DataSource(dataSource => dataSource
.Ajax()
.Events(o => o.DataBound("onDataBound"))
.PageSize(UIConstants.DefaultPageSizeMax)
.Read(read => read
.Action("GetData", "DataProvider"))
.ServerOperation(false))
)
Now in your jquery, you would write your event handler:
function onRequestEnd(e) {
console.log('onRequestEnd: e.response Object(The raw remote service response) = ', e.response);
console.log('onRequestEnd: e.sender kendo.data.DataSource(The data source instance which fired the event) = ', e.sender);
console.log('onRequestEnd: e.type String (The type of the request) = ', e.type);
}

Kendo Grid: Toolbar template issue

I have a grid that lists Road information and want a Toolbar Template that will allow me to filter the roads by choosing a Concession from a DropDownList. Something like this
My code:
CSHTML
<div id="datagrid">
#(Html.Kendo().Grid<SustIMS.Models.RoadModel>()
.Name("datagrid_Roads")
.Columns(columns =>
{
columns.Bound(r => r.RoadCode).Title(ViewBag.lblCode).Width(140);
columns.Bound(r => r.RoadType).Title(ViewBag.RoadType).Width(140);
columns.Bound(r => r.RoadMediumDescription).Title(ViewBag.lblDescription);
columns.Bound(r => r.ConcessionCode).Title("CCode").Hidden();
columns.Bound(r => r.ConcessionMediumDescription).Hidden().Title(ViewBag.Concession);
})
.ToolBar(toolbar =>
{
toolbar.Template(#<text>
<div class="toolbar">
<label class="category-label" for="category">Concessão:</label>
#(Html.Kendo().DropDownList()
.Name("concessions")
.OptionLabel("All")
.DataTextField("ConcessionMediumDescription")
.DataValueField("CCode")
.AutoBind(false)
.Events(e => e.Change("concessionChange"))
.DataSource(ds =>
{
ds.Read("ConcessionFiltering", "MasterData");
})
)
</div>
</text>);
})
.HtmlAttributes(new { style = "height: 534px;" })
...
)
)
</div>
<script type="text/javascript">
function concessionChange() {
var value = this.value(),
grid = $("#datagrid_Roads").data("kendoGrid");
if (value) {
grid.dataSource.filter({ field: "ConcessionMediumDescription", operator: "eq", value: value });
} else {
grid.dataSource.filter({});
}
}
Controller
public ActionResult ConcessionFiltering()
{
ConcessionModel cm = new ConcessionModel();
var aux = cm.getConcessions();
return Json(aux.concessions.Select(c => c.concession.mediumDescription).Distinct(), JsonRequestBehavior.AllowGet);
}
This is the current result:
The list is filled with the word "undefined" 16 times, which is the number of concessions I currently have. When I select one of the undefined options, it shows the actual name of the concession, refreshes the grid but doesn't filter it.
I want the list to show the concession names and to filter the grid by concession as I select one of them. What am I missing?
change this
return Json(aux.concessions.Select(c => c.concession.mediumDescription).Distinct(), hJsonRequestBehavior.AllowGet);
to
return Json(aux.concessions.Select(c => new ConcessionModel { Description = c.concession.mediumDescription }).Distinct(), JsonRequestBehavior.AllowGet);
First, double check what Json you are returning from the controller method. It looks like your ConcessionMediumDescriptions may have no data in them.
Second, it looks like, in your controller, that you are returning a list of "ConcessionMediumDescription" data objects.
I am guessing it looks like this...
{ConcessionMediumDescription: {
CCode: 'mycode',
...
}
}
You may consider returning a title field as a part of this Json and to use that for the text field of your dropdown. This is just me guessing from what you are returning in that controller.
Ideal Json would be somting like this...
[{
{{id: 'id1'},{text: 'text1'}},
{{id: 'id2'},{text: 'text2'}}
}]
And you defind your dropdown as such.
.DataTextField("text")
.DataValueField("id")
You have to do json return line like this.
return Json(aux.concessions.Select(c => new { Value = c.concession.DATAVALUE, Text = c.concession.DATATEXT }), JsonRequestBehavior.AllowGet);
Just change DATAVALUE and DATATEXT

Binding a grid to a drop down list

I have a grid that I want to show depending on the result of the drop down list. I can't seem to be able to send the values to the select("controller", "action", data) method. How can I do that? I can't get my javascript to handle it.
This is the drop down list
<select id="workoutType" onchange="changed(value)">
#{ foreach (var type in Model.WorkoutTypes)
{
<option value="#type"> #type </option>
}
}
</select>
and here is the grid
#(Html.Telerik().Grid(Model.Approvers)
.Name("Orders")
.DataBinding(dataBinding => dataBinding
//Ajax binding
.Ajax()
//The action method which will return JSON
.Select("__AjaxBinding", "AssetResearch", new { workoutType = ViewData["dropDownValue"] })
)
.Columns(columns =>
{
columns.Bound(o => o.InvestorName).Width(125);
columns.Bound(o => o.ApproverType).Title("Type").Width(100);
columns.Bound(o => o.Email).Title("E-mail Address");
})
.ClientEvents(events => events
.OnDataBinding("onDataBinding")
)
.Pageable()
.Sortable()
)
I tried using Viewbag and sadly I can't seem to pull it off.
$(document).ready(function() {
$('#workoutType').change(function(){
//bind your data here
var data = $(this).value;
// pass into your C# stuff here
});
});
Would something like this work?
this is not the right way to achieve it because the RouteValue cannot be set on the server (when you are rendering the Grid)
One way to achieve it is to use the change event of the DropDOwnList which Phonixblade9 mentioned to make the Grid perform request and fetch its data from the server. This could be achieved through the ajaxRequest method of the Grid.
Here is what I mean:
$(document).ready(function() {
$('#workoutType').change(function(){
var data = $(this).value;
var gridClientObject = $('#Orders').data().tGrid;
gridClientObject.ajaxRequest({workoutType :data});// do not forget to name the parameter in the action again method again 'workoutType'
});
});

Custom Button in a ClientRowTemplate on the Telerik MVC Grid

Sorry if this is a repeat. I did a search and didn't find anything that exactly matched my situation.
I have a grid that requires a ClientRowTemplate. I have the template working very well.
I need a button in that RowTemplate that calls back to a controller method through ajax. The controller method needs to perform some complex logic and then return a new set of data to the grid which the grid will then need to bind to. I thought this should work in the same fashion as an ajax binding. For instance, when you do a save or delete (using the built in buttons) an ajax method that is attributed with [GridAction] is called and then has an IQueryable returned. The grid automatically binds to this IQueryable.
How do I do the same thing with a custom button? Is it even possible to add a custom button when using a ClientRowTemplate?
Put a link in the clienttemplate of your grid row
#(Html.Telerik().Grid<myModel>()
.Name("myGrid")
.Columns(columns =>
{
#* You can put a link in your client template to trigger a refresh function *#
columns.Bound(o => o.Id).ClientTemplate("<a href='javascript:refreshGrid(<#= Id #>);'>Refresh</a>");
columns.Bound(e => e.col1);
columns.Bound(e => e.col2);
columns.Bound(e => e.col3);
})
.ClientEvents(events => events.OnDataBinding("myGrid_onRowDataBinding"))
.DataBinding(dataBinding => dataBinding.Ajax().Select("Action", "Controller", new { param1 = ..., param2 = ... } )))
Write your code to refresh grid
<script type="text/javascript">
//parameters needed for grid
var x = ...;
var y = ...;
//grid refresh function
function refreshGrid(id) {
//make a call to server
$.post("/controller/action/" + id, function() {
//after making a successfull call to server
//you may update parameters
x = ...;
y = ...;
//and rebind your grid
$('#myGrid').data('tGrid').rebind();
})
}
//grid on row data binding event
function myGrid_onRowDataBinding(e) {
e.data = $.extend(e.data, { param1: x, param2: y });
}
</script>
That's it
EDIT:
ClientRowTemplate example
You need to change only the grid code. The rest is same.
#(Html.Telerik().Grid<myModel>()
.Name("myGrid")
.ClientRowTemplate(grid => "<div class='firstcolumn'><a href='javascript:refreshGrid(<#= Id #>);'>Refresh</a></div><div class='secondcolumn'>Content....</div>")
.ClientEvents(events => events.OnDataBinding("myGrid_onRowDataBinding"))
.DataBinding(dataBinding => dataBinding.Ajax().Select("Action", "Controller", new { param1 = ..., param2 = ... } )))

Resources