Too often I find myself including a list of options in a view model, each option being a view model itself of the raw option, with an added Selected property. Then, when processing the posted view model in an action, I need to iterate over the options list to find the selected item(s). Is there no tidier way of doing this, or is that what my spare time this Sunday afternoon is for?
One option is to use a combination of the selected value along with an associated SelectList on your view model.
For example, if you have a product which needs to be assigned a category, you might have a view model that looks similar to this:
public class ProductViewModel
{
public int SelectedCategoryId { get; set; }
public IEnumerable<CategoryViewModel> AllCategories { get; set; }
public SelectList CategorySelectList
{
get
{
return new SelectList(this.AllCategories, "Id", "Name", this.SelectedCategoryId);
}
}
//Other properties
}
public class CategoryViewModel
{
public int Id { get; set; }
public string Name { get; set; }
//Other properties
}
And an Html input helper in your view that looks like this:
#Html.DropDownListFor(mod => mod.SelectedCategoryId, Model.CategorySelectList, "---")
Because the CategorySelectList property on the ProductViewModel is given the SelectedCategoryId as the selectedValue parameter, you don't need to worry about manually setting the selected value anymore--it will do it for you when it renders the drop-down list.
Related
I am new to MVC and I have got a list of students in my action method and i want to pass each student instance to a view inside a foreach loop something like that
foreach(var student in Students)
{
return View(student);
// instead of return i have also tried this View(student) but it also doesnt work
}
Is it possible?
Actually i dont want to pass complete list to view instead of it I want to pass each student instance to a view by [httpget]and after getting its updated information like marks and grades in [httppost] i would like to send next student to view and get its updated information. It would be much easier for user to enter details of one student at a time instead of dealing with a complete list
You can pass it as object to method
// from your controller
List<yourobject> list = new List<yourobject>();
return View(list);
// in your view
#model List<yourobject>
// and property Model is type of List<yourobject>
#foreach(var item in Model)
{
<span>#item.Name</span>//example
}
Also you can use the dynamic object ViewBag to pass data from Controllers to Views.
example :
ViewBag.MyStudentList = myStudentList;
#ViewBag.MyList
// e.g.
#foreach (var item in ViewBag.MyStudentList ) {
//you get data here
}
Else:
Declare a list in model class , and assign the student details to it , and include that model in view and access it
public class yourviewmodelStudent
{
public SubjectGradesViewModel()
{
Subjects = new List<Student>();
}
public List<Student> Studentdetails { get; set; }
}
//class that represnt your Student model
public class Student
{
public int Classnumber { get; set; }
public string Name { get; set; }
public List<Student> Studentdetails { get; set; }
}
//then in controller
var model = new yourviewmodelStudent();
model.Studentdetails =//assign your list
then
return View(model);
In view you get this list simply:
Suppose I have a Vehicle class and two child classes like so:
public class Vehicle
{
public string Model { get; set; }
public string Color { get; set; }
}
public class Car : Vehicle
{
public string Seats { get; set; }
}
public class Truck : Vehicle
{
public string MaxLoad { get; set; }
}
My view to create a car or a truck contains a drop down list where you choose car or truck and depending on what you choose the correct form loads into the div with query.
Here is how I implemented this:
I created a partial view containing a form to create a car with Model, Color and Seats inputs.
Another partial view with a form to create a Truck with Model, Color and MaxLoad inputs.
Each form submits to its own controller method i.e:
[HttpPost]
public ActionResult CreateCar(Car newCar)
{
....
}
and same for CreateTruck.
I have a createVehicle view that contains the drop down list, an empty div with an id and some jquery code that loads one of the car or truck partial views into the div.
Now everything works but if i need to change something in my vehicle model, i would then have to change each partial view and each controller method.
So what i'm asking is how do I go about to implement the most optimal way to submit the models in this case?
Optimally I would have:
One controller method onto which I post the models
The createVehicle view containing the Vehicle properties and each partial view only containing its own additional properties.
If you have a ViewModel like:
public class VehicleViewModel
{
public Vehicle Vehicle { get; set; }
public string Action { get; set; }
}
public class AddTruckModel
{
public Truck Truck { get; set; }
}
public class AddCarModel
{
public Car Car { get; set; }
}
In the controller you did (seriously rough example):
public ActionResult(int? vehicleType)
{
var model = new VehicleViewModel;
if (!vehicleType.hasValue || vehicleType.Value == 1)
{
model.Vehicle = new Car();
model.Action = "AddCar";
}
else
{
model.Vehicle = new Truck()
model.Action = "AddTruck";
}
if (Request.IsAjaxRequest())
{
return Partial(model);
}
return View(model);
}
public ActionResult AddCar(AddCarModel model)
{
}
public ActionResult AddTruck(AddTruckModel model)
{
}
And you use a view like:
#model VehicleViewModel
#using(html.BeginForm(Model.Action, "Vehicle", new { id="vehicleForm" }))
{
<div id="vehicle-editor">
//very hacky, I normally return json with embedded html
#Html.HiddenFor(m => m.Action)
#Html.EditorFor(m => m.Vehicle)
</div>
}
You'll notice that the Editor creates html inputs for Car not just Vehicle. You can use this to your advantage.
I would wrap the EditorFor in a html element (div for example) and when the drop down changes, Ajax a call to pull a partial for another vehicle html fragment (say using jQuery). As for the post back, I would also in the same javascript/jquery event for the drop down, change the action for the form.
Please note this is just a prototype/spike, I would not actually write it like this.
I am going to develop a search page where I will have multiple fields comming from differenet models (entity). Also, I have multiple DropDownLists on the same screen whose values will be populated from a lookup table.
I would like to know (in this scenario) what is the best approach. Should I create a ViewModel and pass that model to my view? Or do I need a different approach?
But I am not sure how I should handle my dropdown field, which is populating from lookup table.
Also, on submitting the page, how should I get those values in my next search details screen to get all the records from db?
I am using MVC3 with EF 4.2
Having a ViewModel with necessary properties ( your search criteria) is the way to go.
When you do a HttpGet action for your search load all datas from the look up tables and load to the properties ( ex : States etc..).
public ActionResult Search()
{
SearchViewModel objVM=new SearchViewModel();
objVM.States=MyService.GetStates();
objVM.Type=MyService.GetUserTypes();
return objVM.
}
[HttpPost]
public ActionResult Search(SearchViewModel objVM)
{
if(ModelState.IsValid)
{
//Go for the search and return results
}
return View(objVm);
}
Absolutely, the best approach is definitely to use a ViewModel. Something like this would suffice:
public class Model1
{
public string Prop1 { get; set; }
}
public class Model2
{
public string Prop2 { get; set; }
}
public class ViewModel1
{
public Model1 Model1 { get; set; }
public Model2 Model2 { get; set; }
public SelectList DropDownItems { get; set; }
}
You'd populate the SelectList with an amount of SelectListItem objects in your Controller's Action Method that will pass this ViewModel to the View.
I have something like this in my code and I am getting error: Exception Details: System.ArgumentException: Value cannot be null or empty.
Parameter name: name . What am I doing wrong ? Thanks for help
#model IEnumerable<NHibernateFluentProject.Patient>
#Html.ListBoxFor(model => model, new SelectList(Model,"ID", "FirstName"));
#Html.ListBoxFor is used for your strong typed viewmodel. which could help to bind to your property. First part will take a lambda expression for a single item as a default seleced for your listbox, second part will take the item collections to dispaly all the listbox items.
For example: you have following two classes.
public class HospitalViewModel
{
public string SelectedPatient { get; set; }
public IEnumerable<Patient> AllPatients { get; set; }
}
public class Patient
{
public int Id { get; set; }
public string FirstName { get; set; }
}
From you view, you should do something like
#model HospitalViewModel
#Html.ListBoxFor(model => model.SelectedPatient, new SelectList(Model.AllPatients,"Id", "FirstName"));
OR if you only want to bind all your patients to a listbox, then use Html.ListBox instead
#model IEnumerable<Patient>
#Html.ListBox("ListBoxName", new SelectList(Model,"Id", "FirstName"));
You need to pass a lambda expression containing the property to bind the listbox to.
I'm after a little help with the techniques to use for Databinding. It's been quite a while since I used any proper data binding and want to try and do something with the DataGridView. I'm trying to configure as much as possible so that I can simply designed the DatagridView through the form editor, and then use a custom class that exposes all my information.
The sort of information I've got is as follows:
public class Result
{
public String Name { get; set; }
public Boolean PK { get; set; }
public MyEnum EnumValue { get; set; }
public IList<ResultInfos> { get; set; }
}
public class ResultInfos { get; set; }
{
public class Name { get; set; }
public Int Value { get; set; }
public override String ToString() { return Name + " : " Value.ToString(); }
}
I can bind to the simple information without any problem. I want to bind to the EnumValue with a DataGridViewComboBoxColumn, but when I set the DataPropertyName I get exceptions saying the enum values aren't valid.
Then comes the ResultInfo collection. Currently I can't figure out how to bind to this and display my items, again really I want this to be a combobox, where the 1st Item is selected. Anyone any suggestions on what I'm doing wrong?
Thanks
Before you bind your data to the grid, first set the DataGridViewComboBoxColumn.DataSource like this...
combo.DataSource = Enum.GetValues(typeof(YourEnum));
I generally do this in the constructor after InitializeComponent(). Once this is set up you will not get an exception from the combo column when you bind your data. You can set DataGridViewComboBoxColumn.DataPropertyName at design time as normal.
The reason you get an exception when binding without this step is that the cell tries to select the value from the list that matches the value on the item. Since there are no values in the list... it throws an exception.