Kendo Grid MVC Server Side wrappers with Web API 2 - asp.net-mvc

I setup Kendo Grid along with MVC server side wrapper using Web API. Here is my code in view
#(Html.Kendo().Grid<Models.UserViewModel>()
.Name("UserGrid")
.Columns(column =>
{
column.Bound(c => c.FirstName);
column.Bound(c => c.LastName);
column.Bound(c => c.Email);
})
.DataSource(ds => ds
.Ajax()
.Model(m => m.Id(u => u.Id))
.Read(read => read.Url("/api/..").Type(HttpVerbs.Get))
)
)
Here is my web api controller and the problem which I found it is I am getting null is request parameter. I am not sure why it is happening, any suggestionj please
public DataSourceResult GetAllUsers
([ModelBinder(typeof(DataSourceRequestModelBinder))] DataSourceRequest request)
{
var users= _userRepository.GetAllUsers();
return users.ToDataSourceResult(request, s => new UserViewModel
{
Id = s.Id,
FirstName = s.FirstName,
LastName = s.LastName,
Email = s.Email
});
}

I bet you need to allow get on your controller method:
public DataSourceResult GetAllUsers
([ModelBinder(typeof(DataSourceRequestModelBinder))] DataSourceRequest request)
{
var users= _userRepository.GetAllUsers();
return users.ToDataSourceResult(request, s => new UserViewModel
{
Id = s.Id,
FirstName = s.FirstName,
LastName = s.LastName,
Email = s.Email
}).JsonRequestBehavior.AllowGet;
}

Related

I have list of objects and want to display in dimensions in mvc pivot grid in mvc

I have one table which stored questions as column names and answers as column values and want to display those data in PivotGrid2. For that, I have created the below model which stores the collection of values. Want to display that in pivotgrod2. I Can see data in PivotGrid2 but not in the proper format as a below-attached link.
Model -
public class WorkFlowReportDataModel
{
public string AllQuestions { get; set; }
public string AllResponses { get; set; }
}
Controller -
{
var workFlowReportData = _workflowServices.GetWorkflowReportData(WorkFlowKey);
var workFlowReportDataModelList = new List<WorkFlowReportDataModel>();
foreach (DataRow dr in workFlowReportData.Rows)
{
foreach (DataColumn dc in workFlowReportData.Columns)
{
var workFlowReportDataModel = new WorkFlowReportDataModel();
workFlowReportDataModel.AllQuestions = dc.ColumnName.ToString();
workFlowReportDataModel.AllResponses = dr[dc].ToString();
workFlowReportDataModelList.Add(workFlowReportDataModel);
}
}
View -
#(Html.Kendo().PivotContainer()
.Name("container")
.ConfiguratorPosition("left")
.Content(#<text>
#(Html.Kendo().PivotConfiguratorV2()
.Name("configurator")
.Sortable(true)
.Filterable(true))
#(Html.Kendo().PivotGridV2<InvestrackV2.Controllers.WorkFlowController.WorkFlowReportDataModel>()
.Name("pivot grid")
.HtmlAttributes(new { #class = "hidden-on-narrow" })
.Configurator("#configurator")
.ColumnWidth(120)
.Height(570)
.BindTo(Model)
.DataSource(dataSource => dataSource
.Custom()
.Schema(schema => schema
.Model(m => m.Field("AllQuestions", typeof(string)).From("AllQuestions"))
.Cube(cube => cube
.Dimensions(dimensions =>
{
dimensions.Add(model => model.AllQuestions).Caption("AllQuestions");
dimensions.Add(model => model.AllResponses).Caption("AllResponses");
})
//.Measures(measures =>
//{
// measures.Add("Sum").Format("{0:c}").Field(model => model.SECTISUBSRange).AggregateName("sum");
//})
))
.Columns(columns =>
{
columns.Add("AllQuestions").Expand(true);
columns.Add("AllResponses").Expand(true);
})
.Rows(rows => rows.Add("AllResponses").Expand(true))
//.Measures(measures => measures.Values("Sum"))
//.Events(e => e.Error("onError"))
)
)
#(Html.Kendo().PivotConfiguratorButton()
.Name("Button")
.Configurator("configurator")
)
</text>))
Output- Want to display All questions(COlumn names)Fields section so I can select the question name and see the answers for it. as below.
[1]: https://i.stack.imgur.com/XucBI.png

Kendo MVC Server Side Paging

I'm trying to display a grid using Kendo and want to add server side paging. This is how my view looks like
#(Html.Kendo().Grid<Models.Employee>()
.Name("empGrid")
.Columns(column =>
{
column.Bound(emp => emp.Tickets).Title("Tickets").Filterable(false).Sortable(false)
.ClientTemplate("<div style='display:flex;align-items:center;'> " +
" #= getLateTicketIcon(DueDate) # "
"</div>").Width(100);
column.Bound(emp => emp.EmpID).Hidden();
column.Bound(emp => emp.DeptID).Hidden();
column.Bound(emp => emp.Name).Title("Name#").Width(100);
column.Bound(emp => emp.TicketNumber).Width(150).ClientTemplate("#= getEempTickets(EmpID, DeptID) # ");
column.Bound(emp => emp.DueDate).Width(150)
.ClientTemplate("#: DueDate === null ? '' : kendo.toString(getDateAsUTC(kendo.parseDate(DueDate)), 'MM/dd/yyyy') #");
})
.NoRecords("There are no records to display")
.Sortable()
.Scrollable(scrollable => scrollable.Height("auto"))
.Pageable(pager => pager
.PageSizes(new[] { 10, 25, 50, 100, 200 })
.Refresh(true)
.Input(true))
.Filterable()
.Resizable(resizable => resizable.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
.Excel(ex =>
{
ex.AllPages(true);
ex.Filterable(true);
})
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(50)
.ServerOperation(true)
.Read(read => read.Action("GetTickets", "Employee").Data("readFromServerWithParameters").Type(HttpVerbs.Get)))
.Events(ev => ev.DataBound("currentGridDataBound"))
.AutoBind(false))
and the controller looks like, the problem I'm facing is what ever the page number I select on UI, the page number is always 1.
[HttpGet]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult GetTickets([DataSourceRequest] DataSourceRequest request, long? empID, string[] searchOptions)
{
List<Employee> results = repo.GetTickets(empID, searchOptions,request.Page,request.PageSize);
JsonResult resultJson = Json(results.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
resultJson.MaxJsonLength = int.MaxValue;
return resultJson;
}
I believe you are paging the data twice, once in the GetTickets method (because page and page size are passed as parameters) and again in ToDataSourceResult. As a result, the ToDataSourceResult thinks that the whole set of data is a single page and returns an object where the total is equal to the page size.
To avoid this, either expose a method from your repo that returns the whole set of data
e.g.
public IQueryable<T> GetAllTickets(int empID)
{
return this.dbSet.Where(x=> x.id === empID);
}
Then use the method in the action as follows:
[HttpGet]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult GetTickets([DataSourceRequest] DataSourceRequest request, long? empID, string[] searchOptions)
{
List<Employee> results = repo.GetAllTickets(empID);
JsonResult resultJson = Json(results.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
resultJson.MaxJsonLength = int.MaxValue;
return resultJson;
}
Another option would be to skip calling the ToDataSourceResult method and create the DataSourceResult instance yourself.
e.g.
[HttpGet]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult GetTickets([DataSourceRequest] DataSourceRequest request, long? empID, string[] searchOptions)
{
List<Employee> results = repo.GetTickets(empID, searchOptions,request.Page,request.PageSize);
JsonResult resultJson = Json(new DataSourceResult {
Data = results,
Total = results.Count(),
...
}, JsonRequestBehavior.AllowGet);
resultJson.MaxJsonLength = int.MaxValue;
return resultJson;
}
I wouldn't recommend the second option as you will have to handle the rest of the operations like sorting, grouping, filtering and aggregating yourself, while the TodataSourceResult will do it for you.

Kendo Grid Inline Editing Get current row data when updating

I am using Inline editing in a Kendo Grid and I want to be able to get the current row data when doing an update.
Html.Kendo().Grid<WheresMyTool.Models.COMPANYADDRESS>()
.Name("ShipToLocationsGrid")
.Editable(editable => editable.Mode(Kendo.Mvc.UI.GridEditMode.InLine))
.Pageable(pager => pager.PageSizes(new List<object> { 5, 10, 20, 100 }))
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id(p => p.COMPANY))
.Read(read => read.Action("IndexShipToLocations", "Company", new { company = Model.company }))
.Update(update => update.Action("ShipToLocations_Update"))
.PageSize(20)
)
Here is my update method
public ActionResult ShipToLocations_Update([DataSourceRequest] DataSourceRequest request, COMPANYADDRESS ca)
{
Repository repo = new Repository();
repo.UpdateCompanyAddressRecord(ca, username);
return Json(ca);
}
I want to be able to access the current data. It seems like only the modified data is passed in.
[HttpPost]
public ActionResult EditTestStationInLine([DataSourceRequest] DataSourceRequest request, TestStationViewModel tsvm)
{
if(tsvm != null && ModelState.IsValid)
{
TestStation ts = _testStationService.Find(tsvm.Id);
ts.ProductionLineId = tsvm.ProductionLineId;
ts.ProdLine = _productionLineService.Find(tsvm.ProductionLineId);
ts.Name = tsvm.Name;
_testStationService.Update(ts);
tsvm.Id = ts.Id;
tsvm.ProductionLineId = ts.ProductionLineId;
}
return this.Json(new[] { tsvm }.ToDataSourceResult(request, ModelState));
}
This is an example of one of my InLine edits. Your view model is used to create a database model. Once your database model is created, you can pass back the hidden attributes, in my case the Id and CreateAt. Hope this helps answer your question.
Edit:
function Edit(e) {
var grid = $('#NAMEOFKENDOGRID').data('kendoGrid');
var dataItem = grid.dataItem($(e.target).parents('tr'))
var id = dataItem.id;
$.ajax({//Makes an ajax call
success: function (data) {
$('#NAMEOFDIV').load("/Controller/Update/" + id);
}
});
}
You can make a custom command, conveniently called Edit, which then gets the Id from that row. It also makes an ajax call to your update method. Modify the ajax to fit your needs.

KendoUI Grid not populating remote data in MVC 4

I am trying to implement Telerik's example on their site that binds to a remote data source. The grid displays, but there is never any data in it. I am getting a JSON result from my controller. I verified this by browsing directly to RemoteData/GetData and seeing the JSON string. It is populated with the correct data.
Also when I browse directly to localhost/RemoteData/RemoteData, I see it resolve correctly using Fiddler. (status code 200).
Here is the code from their example with my modifications to it. This is in my View
#(Html.Kendo().Grid<DataObjects.Car>()
.Name("grid")
.Columns(columns => {
columns.Bound(p => p.CarID);
columns.Bound(p => p.Make);
columns.Bound(p => p.Model);
columns.Bound(p => p.Year);
columns.Bound(p => p.Mileage);
})
.Pageable()
.Sortable()
.Scrollable()
.HtmlAttributes(new { style = "height:430px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Read(read => read.Action("GetData", "RemoteData"))
)
)
Code in the controller:
public ActionResult GetData()
{
var cars = new List<Car>();
cars.Add(new Car { CarID = 1, Make = "Chevrolet", Mileage = 259301, Model = "Cavalier", Year = 2000 });
cars.Add(new Car { CarID = 2, Make = "DeLorean", Mileage = 44087, Model = "DMC-12", Year = 1981 });
cars.Add(new Car { CarID = 3, Make = "Honda", Mileage = 183000, Model = "Del Sol", Year = 1993 });
return Json(cars, JsonRequestBehavior.AllowGet);
}
when you do return Json(cars, JsonRequestBehavior.AllowGet); you return a JSON array to your Kendo Grid DataSource(the requestor), exactly like below:
[
{
"CarID": 1,
"Make": "Chevrolet",
"Mileage":259301,
"Model":"Cavalier",
"Year":2000
},
{
"CarID": 2,
"Make": "DeLorean",
"Mileage":44087,
"Model":"DMC-12",
"Year":1981
},
]
but your kendo DataSource expects a javascipt array in a different pre-defined schema then returned by your method.
You need to return the javascript array json in exactly same format as required by the grid. Most simple way to do this is to make your grid_read ActionMethod like this:
public ActionResult GetData([DataSourceRequest] DataSourceRequest request)
{
///your usual code
return Json(cars.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
now your response is in acceptable schema definition by the kendo grid on the client side.
Also, if you don't wish or simply can't change the server side definition then you can directly bind the simple json array returned, to your kendoGrid by doing dataSource.read(response);
Please try with the below code snippet.
using Kendo.Mvc.UI;
using Kendo.Mvc.Extensions;
...............
...............
public ActionResult GetData([DataSourceRequest] DataSourceRequest request)
{
var cars = new List<Car>();
cars.Add(new Car { CarID = 1, Make = "Chevrolet", Mileage = 259301, Model = "Cavalier", Year = 2000 });
cars.Add(new Car { CarID = 2, Make = "DeLorean", Mileage = 44087, Model = "DMC-12", Year = 1981 });
cars.Add(new Car { CarID = 3, Make = "Honda", Mileage = 183000, Model = "Del Sol", Year = 1993 });
return Json(cars.ToDataSourceResult(request));
}

Kendo Grid model with an IEnumerable property not updating correctly after Create/Update when using AJAX binding

I'm having a problem where a property of my model is not being correctly updated when sending it to my controller for an Update or Create call from a Kendo Grid. The model looks like this:
public class ReleaseNotesModel
{
public int NoteID { get; set; }
public int ReleaseID { get; set; }
public List<TranslationModel> ReleaseNoteTranslations { get; set; }
public ReleaseNoteType ItemType { get; set; }
}
public class TranslationModel
{
public int TranslationID { get; set; }
public string Translation { get; set; }
public int LanguageID { get; set; }
public int ItemID { get; set; }
}
Here is the grid in my view:
#(Html.Kendo().Grid<ReleaseNotesModel>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(m => m.ItemType).Width(140);
columns.Bound(m => m.Description);
columns.Command(command =>
{
command.Edit();
command.Destroy();
}).Width(170);
})
.ToolBar(toolbar => toolbar.Create())
.Editable(editable => editable
.Mode(GridEditMode.PopUp)
.TemplateName("ReleaseNoteTemplate")
.Window(w => w.Width(620))
.DisplayDeleteConfirmation(true)
)
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(false)
//.Server()
.Events(e => e.Error("grid_error"))
.Model(model =>
{
model.Id(m => m.NoteID);
model.Field(m => m.ReleaseID).DefaultValue(Model.ReleaseID);
model.Field(m => m.ItemType).DefaultValue(ReleaseNoteType.NewFeature);
//defaultTranslationsList is a List<TranslationModel> with two empty objects in it
model.Field(m => m.ReleaseNoteTranslations).DefaultValue(defaultTranslationsList);
})
.PageSize(5)
.Read(read => read.Action("GetNotes", "ReleaseNotes", new { releaseID = Model.ReleaseID }))
.Create(create => create.Action("AddNote", "ReleaseNotes"))
.Update(update => update.Action("EditNote", "ReleaseNotes"))
.Destroy(destroy => destroy.Action("DeleteNote", "ReleaseNotes"))
)
)
So more specifically, the problem I am having is that in my controller action:
public async Task<ActionResult> EditNote(ReleaseNotesModel model)
model.ReleaseNoteTranslations always contains two empty objects (properties are null or 0), i.e. the default value which I set for this property. If I set no default value, then I won't have any fields to edit for this property in the popup editor. All the other properties are updated as expected.
What bugs me is that if I use server binding instead of AJAX, then all the data is correctly received. So I decided to check out the data in the request headers being sent in both cases:
// Using server binding
ReleaseID:300
NoteID:886
ItemType:1
ReleaseNoteTranslations[0].ItemID:886
ReleaseNoteTranslations[0].LanguageID:1
ReleaseNoteTranslations[0].TranslationID:869
ReleaseNoteTranslations[0].Translation:The module is now released!
ReleaseNoteTranslations[1].ItemID:886
ReleaseNoteTranslations[1].LanguageID:2
ReleaseNoteTranslations[1].TranslationID:870
ReleaseNoteTranslations[1].Translation:Le module est maintenant disponible!
NoteID:886
// Using AJAX binding
sort:
group:
filter:
NoteID:886
ReleaseID:300
ReleaseNoteTranslations[0][TranslationID]:869
ReleaseNoteTranslations[0][Translation]:The module is now released!
ReleaseNoteTranslations[0][LanguageID]:1
ReleaseNoteTranslations[0][ItemID]:886
ReleaseNoteTranslations[1][TranslationID]:870
ReleaseNoteTranslations[1][Translation]:Le module est maintenant disponible!
ReleaseNoteTranslations[1][LanguageID]:2
ReleaseNoteTranslations[1][ItemID]:886
ItemType:1
Now what I notice first here is the syntax of objectName[index].PropertyName vs objectName[index][PropertyName]
I wonder if this could be the cause of my problem, and if so, is there a way for me to go and directly manipulate the data being sent to fix it? Could this be a bug in the way Kendo Grid sends data through Ajax binding?
Either way, any help would be much appreciated!
So In case anyone stumbles on this in the future, I contacted Telerik support, who explained to me that:
The dataSource supports only value types and will not serialize the
arrays in the format that is expected by the model binder.
They also provided me with a workaround using the request Data function to call a JavaScript function which converts the data into the correct format.
In the view, modify the request functions by specifying the name of the JavaScript function to call:
.Create(create => create.Action("AddNote", "ReleaseNotes").Data("serialize"))
And then add in the functions which will do the conversion:
function serialize(data) {
for (var property in data) {
if ($.isArray(data[property])) {
serializeArray(property, data[property], data);
}
}
}
function serializeArray(prefix, array, result) {
for (var i = 0; i < array.length; i++) {
for (var property in array[i]) {
result[prefix + "[" + i + "]." + property] = array[i][property];
}
}
}
Another issue could be that the kendo.aspnet.mvc.js is not included in the project. It appears to do the serialization trick when included.
Something that I noticed is that you need to add if condition as you don't need to serialize if the count is 1, just one item works fine without serialization

Resources