KendoUI MVC: Sorting with a ViewModel - kendo-ui

I am using a ViewModel Class to bind to a KendoUI grid and it call works well until I try to sort (or filter). It all works ok until I try sort on UserName. I am sure it is because UserName is not a property of my entity model (ErrorLog)
public ActionResult ListErrors([DataSourceRequest]DataSourceRequest request)
{
IQueryable<ErrorLog> errorLogs = (IQueryable<ErrorLog>)db.ErrorLogs.Include(e => e.User).OrderByDescending(e => e.ErrorLogId);
DataSourceResult result = errorLogs.ToDataSourceResult(request, errorLog => new ErrorLogViewModel
{
ErrorLogId = errorLog.ErrorLogId,
Message = errorLog.AdditionalMessage,
UserName = errorLog.User.UserName
});
return Json(result);
}
This scenario doesn't seem to covered in the Kendo MVC documentation.

Solved by invoking ToDataSourceResult after my db query had run:
public ActionResult ListErrors([DataSourceRequest]DataSourceRequest request)
{
IQueryable<ErrorLog> errorLogs = (IQueryable<ErrorLog>)db.ErrorLogs.Include(e => e.User).OrderByDescending(e => e.ErrorLogId);
DataSourceResult result = errorLogs.Select(errorLog => new ErrorLogViewModel
{
ErrorLogId = errorLog.ErrorLogId,
Message = errorLog.AdditionalMessage,
Timestamp = errorLog.Timestamp,
UserName = errorLog.User.UserName
}).ToDataSourceResult(request);
return Json(result);
}

Please try the KendoGridBinderEx project instead of [DataSourceRequest], together with AutoMapper this scenario should be work fine.
For a demo see here.

Related

KendoUI for ASPMVC TreeView: display the Json response on behalf of the Tree

I am trying to display a tree of categories with remote data binding.
here is the Controller method:
public JsonResult KendoTree(Guid? id)
{
var categoriesBO = _categoryManager.GetAllCategory().
Where(c=> id==null ? c.ParentId==null : c.ParentId == id).
Select(c=> new
{
id = c.Id,
Name = c.Name,
hasChildren = c.CategoryChilds.Any()
});
return Json(categoriesBO, JsonRequestBehavior.AllowGet);
}
here is the cshtml file
#{
ViewBag.Title = "KendoTree";
}
<h2>KendoTree</h2>
#Html.Kendo().TreeView().Name("Categories").DataSource(dataSource => dataSource
.Read(read => read.Action("KendoTree", "CategoryManagement")
)).DataTextField("Name")
The browser display the Json result(an array) on behalf of the tree.
Am I missing something?
I got it: I have to have a Controller action that returns a view then call the kendo Html helper from inside the related view.

Restrict Kendo Grid to Current Route Id

I'm trying to include a Kendo UI ASP.NET MVC Grid on the Edit page of my MVC application and I would like to restrict that grid to only return values from the current route id. I've been researching ways to do this, but can't find anything that's exactly what I need, or I'm just too new at this to connect the dots.
My ideas so far are to either apply a filter to the DataSource or send a parameter to the controller and have it restrict the DataSourceResult.
For the DataSource filter in the view, I can do this:
.Filter(filters => { filters.Add(d => d.CompanyId).IsEqualTo(2); })
But I can't figure out how to replace the hardcoded 2 with the value from, say, #ViewContext.RouteData.Values["id"], or something.
Passing a parameter to the controller, I can get the following:
public ActionResult Divisions_Read([DataSourceRequest]DataSourceRequest request, int id)
{
using (var db = new AppContext())
{
IQueryable<Division> divisions = db.Divisions;
DataSourceResult result = divisions.ToDataSourceResult(request, division => new DivisionViewModel
{
DivisionId = division.DivisionId,
CompanyId = division.CompanyId,
CountryId = division.CountryId,
DivisionName = division.DivisionName
});
return Json(result);
}
}
But I have no idea how to use that id to basically add a "where CompanyId = Id" statement to the result.
Any ideas on what the best way to do this would be? Am I missing something really obvious?
Thanks!
ETA: Passing the parameter to the Controller through the Read action, as suggested by mmillican and other places in my research, and changing
DataSourceResult result = divisions.ToDataSourceResult(request, division => new DivisionViewModel
to
DataSourceResult result = divisions.Where(c => c.CompanyId == companyId).ToDataSourceResult(request, division => new DivisionViewModel
did the trick. That extra bit in the controller was what I was looking for, but couldn't seem to find anywhere.
Assuming you have a model for your page that looks like this:
public class MyViewModel
{
public int Id { get; set; } // assuming Id is what you want to filter by
// .. other VM properties
}
you can do something like this in your grid data binding
.DataSource(ds => ds
.Ajax()
.Model(mdl => mdl.Id(x => x.Id))
.Read("Divisions_Read", "Divisions", new { id = Model.Id })
)
in your controller, you would set the model's Id property to whatever ID that is in the route.

Rendering same View after Http Post in MVC

Trying to repost a view but im getting null to the field I want.
Heres the controller...
public ActionResult Upload()
{
VMTest vm = new VMTest();
return View(vm);
}
[HttpPost]
public ActionResult Upload(VMTest vm, String submitButton)
{
if (submitButton == "Upload")
{
//do some processing and render the same view
vm.FileName = "2222"; // dynamic creation of filename
vm.File.SaveAs(#vm.FileName); // save file to server
return View(vm);
}
else if (submitButton == "Save")
{
//read the file from the server
FileHelperEngine engine = new FileHelperEngine(typeof(PaymentUploadFile));
PaymentUploadFile[] payments = (PaymentUploadFile[])engine.ReadFile(#vm.FileName); // the problem lays here #vm.FileName has no value during upload
//save the record of the file to db
return View("Success");
}
else
{
return View("Error");
}
}
I already had a #Html.HiddenFor(model => Model.FileName) inside my view.
But still I got a null value for Model.FileName.
Any help pls
Thanks
If you intend to modify some values of your view model in the POST action you need to remove the old value from modelstate first:
ModelState.Remove("FileName");
vm.FileName = "2222";
The reason for this is that Html helpers such as TextBox, Hidden, ... will first use the value in the modelstate when binding and after that the value in your view model.
Also instead of:
#Html.HiddenFor(model => Model.FileName)
you should use:
#Html.HiddenFor(model => model.FileName)
Notice the lowercase m in the expression.
The above answer is a good one. You can also do the following
public ActionResult Upload()
{
VMTest vm = new VMTest();
ModelState.Clear();
return View(vm);
}
I usually call ModelState.Clear() before loading a new view. The sytntax for HiddenFor should be
#Html.HiddenFor(m => m.FileName);
I hope this helps.

"The ObjectContext instance has been disposed" - even with a using(context) statement and ToList()

I have an MVC3 Project running with EF Code First.
Here is my code for Home/Index:
public ActionResult Index()
{
var IndVM = new IndexVM();
using (QuoteContext QDomain = new QuoteContext())
{
IndVM.Quotes = QDomain.Quotes.Include("Tags").Include("Author").OrderByDescending(x => x.CreatedOn).Take(5).ToList();
IndVM.Tags = QDomain.Tags.OrderByDescending(x => x.Quotes.Count).ToList();
IndVM.Authors = QDomain.Authors.OrderByDescending(x => x.Quotes.Count).Take(5).ToList();
}
return View(IndVM);
}
As you can see I have the Querying stuff inside a using statement, and I am also calling the ToList(), but I still get the error:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
Is this a bug in EF Code First?
You have to turn off lazy loading, otherwise the serializer will try to traverse navigation properties and throw this exception.
public ActionResult Index()
{
var IndVM = new IndexVM();
using (QuoteContext QDomain = new QuoteContext())
{
QDomain.ContextOptions.LazyLoadingEnabled = false;
// Query and populate IndVM here...
}
return View(IndVM);
}

Pass a value from one controller to another in asp.net mvc

I've been new to ASP.NET MVC. This is what I'm doing. I've 2 Controllers:Home and Customerservice.
Now I have a Customer list where when I click details gets redirected to the products he acquired.
So, I need to pass in the id so that the products of that customer can be displayed. So, my home consists of customer details. Now i need to pass that id to CustomerService controller ,Index action. This is what I've done in Home:
public ActionResult Customers()
{
var dc = new ServicesDataContext();
var query = (from m in dc.Customers
select m);
return View(query);
}
public ActionResult Details(int id)
{
var datacontext = new ServicesDataContext();
var serviceToUpdate = datacontext.Customers.First(m => m.CustomerId == id);
ViewData.Model = serviceToUpdate;
// return View();
return Redirect("/CustomerService");
}
[HttpPost]
public ActionResult Details(FormCollection form)
{
var id = Int32.Parse(form["CustomerID"]);
var datacontext = new ServicesDataContext();
var service = datacontext.Customers.First(m => m.CustomerId == id);
return Redirect("Customers");
}
}
Now I'm not sure whether I need to pass an id as parameter for index in CustomerService. SO can you please guide me in finishing this?
If you are using any Redirect (such as RedirectToAction) you can use TempData to store any parameters. The semantics have slightly changed in MVC 3 but TempData is designed to pass data between actions in a POST-Redirect-GET scenario.
Passing it as a parameter is probably your best option. Try using something like return RedirectToAction(ActionName, ControllerName, RouteValues);.

Resources