Kendo DataSource How to define a Model.Id when using DataTable - kendo-ui

When defining a DataSource within #(Html.Kendo().Grid(Model), I have successfully used
.DataSource( dataSource => .Ajax( ).Model( model => model.Id( m => m.PROPERTY ) ) )
where PROPERTY is a property of the object that is the model. What is the correct syntax for defining Model.Id if the Model is a System.Data.DataTable and the Id column in the DataTable is TableId?
In other words, model.Id( m => ??? ).
I have tried, model.Id( m => Model.PrimaryKey ), which seems to satisfy the requirement that model.Id be set, but the Update Action (.Update(update => update.Action("MyUpdateMethod", "MyController")) doesn't ever hit, so I think there must still be something wrong.

You can bind to a DataTable. In fact, we do a lot of dynamic grids and DataTable is our only recourse. Binding is a little different, though.
A snippet for one of ours is like this:
#model System.Data.DataTable
#(Html.Kendo().Grid(Model)
.Name("SomeGrid")
.Columns(columns=>
{
foreach(System.Data.DataColumn column in Model.Columns)
{
columns.Bound(column.ColumnName).Title(column.Caption).Width(200);
}
}
)
.Selectable(selectable=>selectable
.Type(GridSelectionType.Row)
)
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
foreach(System.Data.DataColumn column in Model.Columns)
{
model.Field(column.ColumnName,column.DataType);
}
}
)
.Read(read=>Action("SomeMethod", "SomeController"))
.PageSize(20)
)

I have an answer, although it's not real slick. There are several parts to it.
First, in order to Edit, I must set a Model.Id, how to do which was my original question. The answer to that is simply, model.Id( "KEY_COLUMN_NAME" ) in the .DataSource.Model method. However, that is not enough to solve the problem that Update does not occur. Telerik Support suggested that I needed to define a custom data object (POCO) that had all the same properties as the DataTable has columns. That POCO becomes the type for the update
public ActionResult MyUpdate( [DataSourceRequest] DataSourceRequest _request, MyPOCO _data ){...}
The Editor can then map the DataRow columns to the POCO properties, and then MyUpdate can work.

Related

Binding dynamic data to kendo Dropdownlist

I am trying to bind a kendo dropdownlist with the model but I am getting undefined in each option.
Model:
public SelectList CountriesTemp { get; set; }
public int Country{get;set;}
Controller:
public ActionResult Registration()
{
RegistrationModel Model = new RegistrationModel();
Model.CountriesTemp = new SelectList(ObjService.GetCountries(), "CountryID", "Country_Name");
return View(Model);
}
View Page
#(Html.Kendo().DropDownListFor(m => m.Country)
//The name of the dropdownlist is mandatory. It specifies the "id" attribute of the widget.
.DataTextField("Country_Name") //Specifies which property of the Product to be used by the dropdownlist as a text.
.DataValueField("CountryID") //Specifies which property of the Product to be used by the dropdownlist as a value.
.BindTo(Model.CountriesTemp ) //Pass the list of Products to the dropdownlist.
)
Can somebody please guide me where I am wrong because if I bind a simple dropdownlist of MVC , It works well. Just one line change as below in ViewPage and it's Working.
#Html.Dropdownlist("CountriesTemp")
It looks like you've got a conflict (so-to-speak going on here). Try something like this:
#(Html.Kendo().DropDownListFor(m => m.Country)
.DataTextField("Text")
.DataValueField("Value") // These may be optional now
.BindTo(Model.CountriesTemp))
Alternatively, you can not use a SelectList and do a property like IEnumerable<Country> Countries { get; set; } on your Model. Then the binding would look something like:
#(Html.Kendo().DropDownListFor(m => m.Country)
.DataTextField("Country_Name")
.DataValueField("CountryID")
.BindTo(Model.Countries))

Dynamically create random number of dropdownlists in MVC

I need to create a random number of dropdownlists in my view, based on the selected value of another dropdownlist. This is all done but my problem comes when I need to make the httppost because i never know how much data i need to save in my db.
In my model I have a list
public List<RoomToBooking> RoomsToBooking { get; set; }
that will get filled with x number of RoomToBooking when the Create view is rendered after the user makes a selction of dropdownlist 1:
var dogs = from d in db.Dogs
where d.Customer_ID == id
select d;
foreach (Dog item in dogs)
{
roomToBooking = new RoomToBooking();
roomToBooking.Customer_ID = id;
roomToBooking.Dog = item;
roomsToBookingList.Add(roomToBooking);
}
So I would like to create the same number of dropdownlist in my Create view
#Html.DropDownListFor(model => model.Booking.RoomToBooking, new SelectList(ViewBag.DeliveryTypes), new { #class = "selectbox" })
#Html.ValidationMessageFor(model => model.Booking.RoomToBooking)
So I in the end can be able to save it to my db
[HttpPost]
public ActionResult Create(EditBookingPensionViewModel model)
{
foreach (RoomToBooking item in objViewModel.RoomsToBooking)
{
//Save to db
}
}
I assume that I should use jquery to create the dropdownlists, but how do i create the dropdownlists so the selected values can be found in my viewmodel??
You may take a look at the following article. I slight adaption might be necessary for your scenario because you don't have add and remove buttons but instead you use the selected value of a dropdownlist to determine the number of dynamic rows to be added. But the concept is the exactly the same.

MVC - ViewModel

I need to create a linq statement that combines 2 tables and send that to the view.
Do I need to create a ViewModel for this.
Say the output will be the following
Table1.Vendor Table1.VendorName Table2.Address
It depends what your result type is.
If you return a dynamic object an anonymous type then you can't put that into the ViewBag directly (see: Stuffing an anonymous type in ViewBag causing model binder issues). But if you're returning something that's strongly typed, you can just put that straight into the ViewBag and bypass having a model.
That said, I'd always lean towards having a strongly typed model!
Yes You Should use View-model because if u want to send more than one table you may
use ViewBag or something equivalent viewdata[] that's wrong etc..
Because ViewBag for example is dynamic type it can't be sent to view with 2 table
For example if you do something like this
ViewBag.Workers=db.Workers.Join(idb.AspNetUsers, e => e.UserID, i => i.Id, (e, i) => new { UserName = i.UserName, SBIN = e.SBIN, }).ToList();
You will Get error 500 when you use this viewbag in your View
<span>#ViewBag.Workers.Anything</span>
Even in this example you should use for-each you still get error becausethe ViewBag is internal
So You could use something like that in the controller for this issue
var Workers=db.Workers.Join(idb.AspNetUsers, e => e.UserID, i => i.Id, (e, i) => new WorkerViewCardModelcs{ UserName = i.UserName, SBIN = e.SBIN, }).ToList();
return PartialView("_WorkerCard", Workers);
and Don't for get to use #model in the View or Partial View
#model IEnumerable<FinalProject.ViewModels.WorkerViewCardModelcs>
#foreach (var item in Model)
{
What ever logic you wish
}

DropDownListFor & Navigation Properties

I'm running into an issue trying to use #Html.DropDownListFor().
I have a model with a navigation property on it:
public class Thing {
...
public virtual Vendor Vendor { get; set; }
}
In the controller I'm grabbing the vendor list to throw into the ViewBag:
public ActionResult Create() {
ViewBag.Vendors = Vendor.GetVendors(SessionHelper.CurrentUser.Unit_Id);
return View();
}
The html item in the view looks like this:
#Html.DropDownListFor(model => model.Vendor, new SelectList(ViewBag.Vendors, "Id", "Name"), "---- Select vendor ----")
#Html.ValidationMessageFor(model => model.Vendor)
The dropdown list is being rendered, and everything seems fine until I submit the form. The HttpPost Create method is returning false on the ModelState.IsValid and throwing a Model Error: The parameter conversion from type 'System.String' to type '...Models.Vendor' failed because no type converter can convert between these types.
If I let the page post through, I end up with a server error:
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: items
After searching high and low I haven't been able to find a reason that the #Html.DropDownListFor() isn't properly auto-binding a Vendor object to the navigation property.
Any help would be greatly appreciated.
EDIT:
I ended up having to explicitly set the ForeignKey attributes so that I could directly access "Vendor_Id" then I changed the DropDownListFor to point to "Vendor_Id" instead of the navigation property. That seems to work.
I have found that the best way to do this is as follows. Change the controller to create the SelectListItems.
public ActionResult Create() {
ViewBag.Vendors = Vendor.GetVendors(SessionHelper.CurrentUser.Unit_Id)
.Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.Name),
Value = option.Id.ToString()
});
return View();
}
Then modify the view as follows:
#Html.DropDownListFor(model => model.Vendor, (IEnumerable<SelectListItem>)ViewBag.Vendors, "---- Select vendor ----")
#Html.ValidationMessageFor(model => model.Vendor)
You have to cast the ViewBag.Vendors as (IEnumerable).
This keeps the views nice and neat. You could also move the code that gets the SelectListItems to your repo and put it in a method called something like GetVendorsList().
public IEnumerable<SelectListItem> GetVendorsList(int unitId){
return Vendor.GetVendors(unitId)
.Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.Name),
Value = option.Id.ToString()
});
}
This would separate concerns nicely and keep your controller tidy.
Good luck
I have replied similar question in following stackoverflow question. The answer is good for this question too.
Validation for Navigation Properties in MVC (4) and EF (4)
This approach doesn't publish the SelectList in controller. I don't think publishing SelectList in controller is good idea, because this means we are taking care of view part in controller, which is clearly not the separation of concerns.

ActionResult Details needs to resolve FK from List to display Name?

I have a FK in my Details ViewModel and when the View binds to the ViewModel I only get the FK back (expected). The FK is a reference to a simple ID/Name type table. I also have a Strongly typed List in the VM representing that FK-referenced table. I want to do something like
<div class="display-field">#Model.ManufacturersList.Find(x => x.ID == Model.softwaremanufacturerid))</div>
While this will return the the instance I want...I can't figure out how to get the "Name" attribute to display.
Sorry if this is more a Lamda question but thought I'd try all the same
Thanks
If .ManufacturersList.Find(x => x.ID == Model.softwaremanufacturerid) returns what you want, don't do it in the View. The View should only display data, while the model layer should really be doing the searching (.Find)
In your view model, add a string property for ManufacturerName
public string ManufacturerName { get; set; }
In your controller,
MyViewModel vm = new MyViewModel()
{
ManufacturerName = .ManufacturersList
.Find(x => x.ID == theFKAlreadyInTheViewModel)
};
return View(vm);
Then in your view,
#Model.ManufacturerName
OR, more simply, you could use the ViewBag
ViewBag.ManufacturerName = YourManufacturersList
.Find(x => x.ID == theFKAlreadyInTheViewModel);
Then in your View,
#ViewBag.ManufacturerName

Resources