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));
}
Related
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.
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.
I'm trying to use Teleric's Kendo Grid in ASP.NET MVC 5. I'm following the example here, but the grid is not populating with data. The columns show up, but it says "No items to display".
http://docs.telerik.com/kendo-ui/getting-started/using-kendo-with/aspnet-mvc/helpers/grid/ajax-binding
This is my Words/Read function:
public ActionResult Read([DataSourceRequest] DataSourceRequest request)
{
var items = db.Words.Take(1).ToList();
//this code was necessary to get the correct JSON result
JsonSerializerSettings jsSettings = new JsonSerializerSettings();
jsSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
var converted = JsonConvert.SerializeObject(items, null, jsSettings);
return Content(converted);
}
I got the following JSON result from Words/Read:
[{"WordId":1,"Rank":1,"PartOfSpeech":"article","Image":"Upload/29/1/Capture1.PNG","FrequencyNumber":"22038615","Article":null,"ClarificationText":null,"WordName":"the | article","MasterId":0,"SoundFileUrl":"/UploadSound/7fd752a6-97ef-4a99-b324-a160295b8ac4/1/sixty_vocab_click_button.mp3","LangId":1,"CatId":null,"IsActive":false}]
Finally, my view page:
#(Html.Kendo().Grid<NextGen.Models.Word>
()
.Name("grid")
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(15)
.Read(read => read.Action("Read", "Words"))
)
.Columns(columns =>
{
columns.Bound(c => c.WordName);
columns.Bound(c => c.PartOfSpeech);
})
.Pageable()
.Sortable()
)
I've seen some similar questions to this one, but most are using Javascript rather than Html helpers. Am I doing something dumb?
I found an alternative way to get around the circular reference problem I was having. Basically, the answer is here: A circular reference was detected while serializing an object of type 'SubSonic.Schema .DatabaseColumn'.
For people with the same problem: I took the two properties I needed - WordName and PartOfSpeech, and passed only those attributes to the toDataSource function Kendo provides.
My new read function looks like this:
public ActionResult Read([DataSourceRequest] DataSourceRequest request)
{
var items = db.Words.Select(w => new WordL{
WordName = w.WordName,
PartOfSpeech = w.PartOfSpeech
});
return Json(items.ToDataSourceResult(request));
}
where WordL is a model with just PartOfSpeech and WordName attributes, rather than all the attributes of my class.
It is probably because you are not using 2 methods in your controller. While your page view is first ActionResult you should use second one as in the grid as you did in your example. I hope it is obvious.
public ActionResult ReadPage()
{
return View();
}
public ActionResult Read([DataSourceRequest] DataSourceRequest request)
{
var items = db.Words.Take(1).ToList();
//this code was necessary to get the correct JSON result
JsonSerializerSettings jsSettings = new JsonSerializerSettings();
jsSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
var converted = JsonConvert.SerializeObject(items, null, jsSettings);
return Content(converted);
}
I'm new to kendo Ui. I've used the scheduler control in my ASP.Net MVC 4 project and implemented using Ajax calls as defined in following tutorial.
http://docs.telerik.com/kendo-ui/getting-started/using-kendo-with/aspnet-mvc/helpers/scheduler/ajax-editing.
My problem is when I try to edit an event, it will edit the event, plus creates one or more duplicate records in the database with the same data. How should I avoid it.
Following is my Index.cshtml
#(Html.Kendo().Scheduler<Portal.Presentation.Web.BoundedContext.QC.MVC.Areas.Razor.Models.LeavePlan>()
.Name("scheduler")
.Date(DateTime.Now)
.Height(600)
.AllDaySlot(true)
.Views(views =>
{
views.DayView();
views.WeekView(weekView => weekView.Selected(true));
views.MonthView();
})
.Timezone("Etc/UTC")
.Resources(resource =>
{
resource.Add(m => m.PlanTypeId)
.Title("Plan Type")
.DataTextField("Text")
.DataValueField("Value")
.DataColorField("Color")
.BindTo(new[] {
new { Text = "Annual Leave", Value = 1, Color = "#f8a398" } ,
new { Text = "Casual Leave", Value = 2, Color = "#51a0ed" } ,
new { Text = "Sick Leave", Value = 2, Color = "#55a098" } ,
new { Text = "Travel", Value = 3, Color = "#56ca85" }
});
})
.DataSource(d => d
.Model(m => {
m.Id(f => f.TaskID);
m.Field(f => f.ResourceId).DefaultValue(1);
//Set the recurrence ID field from the model:
//m.RecurrenceId(f => f.RecurrenceID);
})
.Read("Tasks_Read", "LeavePlan")
.Create("Tasks_Create", "LeavePlan")
.Destroy("Tasks_Destroy", "LeavePlan")
.Update("Tasks_Update", "LeavePlan")
))
Following is my update method.
public ActionResult Tasks_Update([DataSourceRequest]DataSourceRequest request, LeavePlan leave)
{
if (ModelState.IsValid)
{
// Create a new Task entity and set its properties from the posted TaskViewModel
var entity = new ResourceLeavePlan
{
StartDate = leave.Start
,Title = leave.Title
,EndDate = leave.End.ToUniversalTime()
,ResourceLeavePlanId = (int)leave.TaskID
,IsAllDay=leave.IsAllDay
,RecurrenceId=leave.ResourceId
,Description=leave.Description
,RecurrenceException=leave.RecurrenceException
,LeaveTypeId=(int)leave.PlanTypeId
,ResourceId = resourceId
};
_resourceLeavePlanService.Update(entity);
}
return Json(new[] { leave }.ToDataSourceResult(request, ModelState));
}
And help on this would be appreciated.
The model is same as the model in the tutorial in the above link.
and also would be grateful if some one can explain me the use of "RecurrenceId" in the scheduler
You are just missing unique TaskID in your entity object.
var entity = new ResourceLeavePlan
{
TaskID = leave.TaskID // Just try adding this line please and it would work
,StartDate = leave.Start
,Title = leave.Title
,EndDate = leave.End.ToUniversalTime()
,ResourceLeavePlanId = (int)leave.TaskID
,IsAllDay=leave.IsAllDay
,RecurrenceId=leave.ResourceId
,Description=leave.Description
,RecurrenceException=leave.RecurrenceException
,LeaveTypeId=(int)leave.PlanTypeId
,ResourceId = resourceId
};
I am using mvc4. On one of my page, it has Kendo Grid. I want to show 5 rows per page. I have no problem doing it using pure javascript, however, If I am using mvc helper. I got lost, couldn't find any samples online.
here's my javascript code.
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$("#grid").kendoGrid({
dataSource: {
type: "json",
serverPaging: true,
pageSize: 5,
transport: { read: { url: "Products/GetAll", dataType: "json"} },
schema: { data: "Products", total: "TotalCount" }
},
height: 400,
pageable: true,
columns: [
{ field: "ProductId", title: "ProductId" },
{ field: "ProductType", title: "ProductType" },
{ field: "Name", title: "Name" },
{ field: "Created", title: "Created" }
],
dataBound: function () {
this.expandRow(this.tbody.find("tr.k-master-row").first());
}
});
});
now if i am using mvc helper
#(Html.Kendo().Grid(Model)
.Name("Grid") //please help me to finish the rest
Update:
Adding the action code.
[HttpPost]
public ActionResult GetAll([DataSourceRequest]DataSourceRequest request, int id)
{
var products= ProductService.GetAll(id);
return Json(products.ToDataSourceResult(request));
}
GetAll method in the service layer:
public IQueryable<Product> GetAll(int id)
{
var products= ProductRepository.Get(p => p.Id== id && p.IsActive == true, null, "ProductionYear")
.OrderBy(o => o.Name); //.ToList();
return Product.Select(p => new ProductVM()
{
Name = p.Name,
ProductionYear= p.ProductionYear.Year.ToString()
Id = p.Id
}).AsQueryable();
}
now, if I run the app, i will get following error:
"LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression."}
in the GetAll method, I comment out the "ToList()". If I use ToList, everything works. but I will query all the rows back instead just those rows I needed for that page.
You can set the PageSize inside the DataSource method. So you will need something like:
#(Html.Kendo().Grid(Model)
.Name("Grid")
.DataSource(dataSource => dataSource.Ajax()
.PageSize(5)
.Read(c => c.Action("GetAll", "Products")
.Model(s => s.Id(m => m.Id)))
.Columns(columns =>
{
columns.Bound(m => m.ProductId).Title("ProductId");
//other colums
})
.Events(g => g.DataBound("somefunction"))
.Pageable(true))
You can find more info the KendoUI Grid's Asp.NET MVC wrappers documentation.
If you are not using Kendo's ASP.NET MVC wrappers and are using the Kendo JavaScript objects directly and you are trying to do server side paging, then you need to create your datasource as follows:
var dataSource = {
"type":"aspnetmvc-ajax",
"serverSorting": true,
"serverPaging": true,
"page": 1,
"pageSize": 8,
"schema": {
"data":"items",
"total":"count",
"errors":"errors"
}
};
And your Read controller method will look something like:
public ActionResult List_Read([DataSourceRequest]DataSourceRequest request) {
try {
var model = null /* prepare your model object here contain one page of grid data */;
// using Json.NET here to serialize the model to string matching the
// schema expected by the data source
var content = JsonConvert.SerializeObject(new { count = model.Count, items = model.Items }, Formatting.None);
return Content(content, "application/json");
}
catch (Exception exception) {
// log exception if you need to
var content = JsonConvert.SerializeObject(new { errors = exception.Message.ToString() }, Formatting.None);
return Content(content, "application/json");
}
}
type, serverSorting and serverPaging are important to make sure paging and sorting happens server-side. type must be aspnetmvc-ajax, otherwise the query data will not be recognized by the model binder that has been specified by the [DataSourceRequest] attribute in the Read method. You cannot omit that attribute unless you want to write your own custom modelbinder to parse the query data sent by the kendo dataSource, which does not conform to the modelbinding conventions used by the DefaultModelBinder in ASP.NET MVC.
The other answer will work if you are using Kendo UI for ASP.NET MVC. If you don't you need to implement paging yourself. The Kendo DataSource will send pageSize and current page when making a request. You can use that to do the paging. It also sends "take" and "skip" which makes things even easier (hint Linq).
The error
"LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression."}
is self explanatory, to gat around this, you should do something like
return Product.**AsEnumerable**.Select(p => new ProductVM()
{
Name = p.Name,
ProductionYear= p.ProductionYear.Year.ToString()
Id = p.Id });
using AsEnumerable brings all records from the db, so best to use after any filtering
products.where(x => x.active = true).AsEnumerable
rather then
products.AsEnumerable.where(x => x.active = true)
Download kendo examples, then unzip and follow
<your directory>\Kendo UI for ASP.NET MVC Q1 2013\wrappers\aspnetmvc\Examples\Areas\razor\Views\web\grid\
for the view index
and
<your directory>\Kendo UI for ASP.NET MVC Q1 2013\wrappers\aspnetmvc\Examples\Controllers
for IndexController
in your view you might also want .ServerOperation(true) as bellow to avoid
Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.
If you have big data to fetch
#(Html.Kendo().Grid(<yourmodel>)
.Name("Grid")
.Columns(columns =>
...
})
.Filterable()
.Pageable()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(8)
.ServerOperation(true) )
.Model(model =>
{
model.Id(p => p.Id);
...
})
)
)
also in controller in ActionResult Products_Read consider
DataSourceResult result = GetProducts().ToDataSourceResult(request, o => new { Id = o.Id, ... } );
return Json(result , JsonRequestBehavior.AllowGet);