MVC Radiobutton binding complex object - asp.net-mvc

I have MVC3 web application where we need to populate radio button list with validation. My Model is something like this:
public class EmployeesViewModel
{
public List<Employee> listEmployee { get; set; } //To persist during post
public IEnumerable<SelectListItem> selectListEmployee { get; set; }
[Required]
public Employee selectedEmployee { get; set; }
}
public class Employee
{
public int ID {get; set;}
public string Name {get; set}
public string Department {get; set}
}
I need to populate radiobutton list something like below:
Employee1ID - Employee1Name - Employee1Department // id - name - department
Employee2ID - Employee2Name - Employee2Department
Employee3ID - Employee3Name - Employee3Department
Selected Employee should be stored into "selectedEmployee" field. What is the best or clean way to populate these radio button List in MVC3?
Note: Mainly Looking for two task:
1. storing "Employee" object in each "Input" radio button tag, so that selected employee will be saved to "selectedEmployee" field
2. Best way to mark "Employee" object as required field
Much appreciate your help!
Thanks,

Here's what I would recommend you. Start with a clean view model, one that really expresses what the view contains as information:
public class EmployeesViewModel
{
public List<EmployeeViewModel> ListEmployee { get; set; }
[Required]
public int? SelectedEmployeeId { get; set; }
}
public class EmployeeViewModel
{
public int ID { get; set; }
public string Label { get; set; }
}
then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new EmployeesViewModel
{
ListEmployee = GetEmployees()
};
return View(model);
}
[HttpPost]
public ActionResult Index(EmployeesViewModel model)
{
if (!ModelState.IsValid)
{
// the model is invalid, the user didn't select an employee
// => refetch the employee list from the repository and
// redisplay the view so that he can fix the errors
model.ListEmployee = GetEmployees();
return View(model);
}
// validation passed at this stage
// TODO: model.SelectedEmployeeId will contain the id
// of the selected employee => use your repository to fetch the
// actual employee object and do something with it
// (like grant him the employee of the month prize :-))
return Content("thanks for submitting", "text/plain");
}
// TODO: This doesn't belong here obviously
// it's only for demonstration purposes. In the real
// application you have a repository, use DI, ...
private List<EmployeeViewModel> GetEmployees()
{
return new[]
{
new EmployeeViewModel { ID = 1, Label = "John (HR)" },
new EmployeeViewModel { ID = 2, Label = "Peter (IT)" },
new EmployeeViewModel { ID = 3, Label = "Nathalie (Sales)" },
}.ToList();
}
}
and finally a view:
#model EmployeesViewModel
#using (Html.BeginForm())
{
#Html.ValidationMessageFor(x => x.SelectedEmployeeId)
#foreach (var employee in Model.ListEmployee)
{
<div>
#Html.RadioButtonFor(x => x.SelectedEmployeeId, employee.ID, new { id = "emp" + employee.ID })
#Html.Label("emp" + employee.ID, employee.Label)
</div>
}
<input type="submit" value="OK" />
}

Related

how to get unique id from radiobuttonfor in mvc

I have a below model
public class category
{
[Key]
public long category_id { get; set; }
public string category_desc { get; set; }
public long? client_id { get; set; }
public long? display_sno { get; set; }
}
controller passing the model to view
public ActionResult category(long? client_id)
{
var category_type = db.category.Where(m => m.client_id == null).ToList();
if(client_id == 10)
{
category_type = db.category.Where(m => m.client_id == client_id).ToList();
}
return View(category_type);
}
In view populating the radion button
#foreach (var item in Model)
{
#Html.DisplayFor(modelItem => item.display_sno)<text>.</text>
#Html.RadioButtonFor(modelItem => item.category_id, item.category_id, new { id=item.category_id})#item.category_desc
}
post Method
public ActionResult Category(category g)
{
}
In post method g is coming as null.
What I am missing here?
Your misunderstanding how radio buttons work. They are for binding one of many options to a single property, in the same way a dropdownlist works. Your code is generating radio buttons that bind to itself. And if you inspect the html you will see that it generates name="item.category_id" which would not bind to your model anyway (that would only bind to a model containing a complex object named Item which contained a property named category_id).
Assuming you have a model for a Product which contained a property for its Category, and you wanted to assign one of the values of your category table to the Category property, then your view models would look like
public class ProductVM
{
[Required(ErrorMessage = "Please select a category")]
public int? Category { get; set; }
public IEnumerable<CategoryVM> CategoryOptions { get; set; }
}
public class CategoryVM
{
public int ID { get; set; }
public string Name { get; set; }
}
Note the use of a nullable property for Category is explained in What does it mean for a property to be [Required] and nullable?
Then the controller methods (for a Create view) would look like
public ActionResult Create()
{
ProductVM model = new ProductVM();
ConfigureViewModel(model);
return View(model);
}
public ActionResult Create(ProductVM model)
{
if (!ModelState.IsValid())
{
ConfigureViewModel(model);
return View(model);
}
.... // Initialize your Product data model, set its properties based on the view model
// Save and redirect
}
private void ConfigureViewModel(ProductVM model)
{
model.CategoryOptions = db.categories.Select(x => new CategoryVM
{
ID = x.category_id,
Name = x.category_desc
});
}
Then the view would be
#model ProductVM
....
#using (Html.BeginForm())
{
#Html.DisplayNameFor(m => m.Category)
foreach(var category in Model.CategoryOptions)
{
<label>
#Html.RadioButtonFor(m => m.Category, category.ID, new { id = "" })
<span>#category.Name</span>
</label>
}
#Html.ValidationMessageFor(m => m.Category)
<input type="submit" .... />
}
Note that the new { id = "" } is removing the id attribute which would otherwise be invalid html because of duplicates.

How can I create a list of checkboxes that tie back to my model? (MVC5) [duplicate]

I have many-to-many relationship between Student and Course. The linking entity set is Enrollment. For the sake of simplicity, they are all defined as follows.
Models
public class Course
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class Enrollment
{
public int Id { get; set; }
public int StudentId { get; set; }
public int CourseId { get; set; }
public virtual Student Student { get; set; }
public virtual Course Course { get; set; }
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
ViewModels
public class StudentCourseVM
{
public Student Student { get; set; }
public IEnumerable<Course> SelectedCourses { get; set; }
public IEnumerable<Course> AvailableCourses { get; set; }
}
Controllers
public IActionResult Create()
{
var availableCourses = context.Courses;
return View(new StudentCourseVM { AvailableCourses = availableCourses });
}
[HttpPost]
public async Task<IActionResult> Create(StudentCourseVM sc)
{
if (ModelState.IsValid)
{
// What should I do here?
// ======================
await context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(sc);
}
Views
#model MasterDetails.ViewModels.StudentCourseVM
<form asp-action="Create">
<div>
<label asp-for="#Model.Student.Name"></label>
<input asp-for="#Model.Student.Name" />
</div>
<div>
<label asp-for="#Model.Student.Enrollments"></label><br />
#foreach (var course in Model.AvailableCourses)
{
<input type="checkbox" name="#course.Title" id="#course.Id" /> #course.Title <br />
}
</div>
<input type="submit" value="Create" />
</form>
Questions
How to know the selected check boxes from within the HttpPost Create action method?
You can use Editor Templates to do this.
First, create a new class for the course selection and update your view model to have a collection of that class.
public class SelectedCourse
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
public class StudentCourseVM
{
public int StudentId { set; get; }
public IEnumerable<SelectedCourse> SelectedCourses { get; set; }
}
You do not need to copy and paste all the properties from your entity model to your view model. View model needs only those properties which the view absolutely need. I am assuming you want to assign courses to a specific student
Now go to your ~/Views/YourControllerName and create a directory called EditorTemplates. Create a new razor file there and give the name SelectedCource.cshtml
Paste this code to the new file
#model SelectedCourse
<label>#Model.Name</label>
<input asp-for="IsSelected"/>
<input type="hidden" asp-for="Id" />
Now in your GET action, create an object of the view model, load the SelectedCourses collection and send it to the view.
public IActionResult Create()
{
// I hard coded the student id and the courses here.
// you may replace it with real data.
var vm = new StudentCourseVM { StudentId = 12 };
//Assuming we are assigning courses to the student with id 12
vm.SelectedCourses = new List<SelectedCourse>()
{
new SelectedCourse {Id = 1, Name = "CSS"},
new SelectedCourse {Id = 2, Name = "Swift"},
new SelectedCourse {Id = 3, Name = "IOS"},
new SelectedCourse {Id = 4, Name = "Java"}
};
return View(vm);
}
Now in your main view(Create.cshtml) which is strongly typed to StudentCourseVM,Use EditorFor helper method on the SelectedCourses property.
#model StudentCourseVM
<form asp-action="Create">
#Html.EditorFor(f=>f.SelectedCourses)
<input type="hidden" asp-for="StudentId"/>
<input type="submit"/>
</form>
The Editor template will execute code in the editor template file for each item in the SelectedCourses collection. So you will have the course name and a checkbox visible to the user.
In your HttpPost action method, you can use the same view model as the parameter. When the form is submitted, you may loop through the items in SelectedCourses property check the IsSelected property value. The courses user selected in the ui will have a true value.
[HttpPost]
public IActionResult Create(StudentCourseVM model)
{
var studentId = model.StudentId;
foreach (var modelSelectedCourse in model.SelectedCourses)
{
if (modelSelectedCourse.IsSelected)
{
//this one is selected. Save to db
}
}
// to do : Return something
}
Pre-selecting some checkboxes on page load
Sometimes you want to pre select some checkboxes when the page loads (Ex : For your edit screen you want to show already saved courses as checked). To do this, you simply need to set the IsSelected property of the corresponding SelectedCourse object to true in your GET action method.
public IActionResult Edit(int id)
{
// I hard coded the student id and the courses here.
// you may replace it with real data.
var vm = new StudentCourseVM { StudentId = id };
//Assuming we are assigning courses to the student with id 12
vm.SelectedCourses = new List<SelectedCourse>()
{
new SelectedCourse {Id = 1, Name = "CSS"},
new SelectedCourse {Id = 2, Name = "Swift", IsSelected = true },
new SelectedCourse {Id = 3, Name = "IOS", IsSelected = true },
new SelectedCourse {Id = 4, Name = "Java"}
};
return View(vm);
}
The above code will pre select the checkboxes for Swift and IOS.

In ASP.NET MVC5 how do I retrieve the Selected Value chosen by a user in a View from a DropDownListFor and pass it to the Controller Action?

In ASP.NET MVC 5 Please could someone help me with how I determine the value that has been selected from a Select List (implemented as a #Html.DropDownListFor) in a View so I can pass it back to the Controller Method in order to select a modified list of data please? I have spent a few days browsing and trying things to no avail:
Here is what I have. I have a parent Model:
public class ParentEndorsementViewModel
{
// Child Models:
public List<VW_CMA_PRODUCT_ENDORSEMENT> VW_CMA_PRODUCT_ENDORSEMENTS { get; set; }
// This property will hold all available Products for selection:
public IEnumerable<SelectListItem> Product_DropDownList { get; set; }
}
And the relevant “child” model is:
public class Product_DropDownList
{
private Product_DropDownList(int id, string name)
{
Id = id;
Name = name;
}
public int Id { get; set; }
public string Name { get; set; }
}
The View has:
#model App_Endorsement.Models.ParentEndorsementViewModel
….
#using (Html.BeginForm("Manage_Endorsement", "Endorsement", new { ParentEndorsementViewModel = #Model }, FormMethod.Post, null))
{
#*#Html.AntiForgeryToken()*#
#Html.DropDownListFor(m => m.Product_DropDownList, new SelectList(Model.Product_DropDownList, "Value", "Text", Model.Product_DropDownList), "Show All Products")
<input type = "submit" value = "Send" />
}
The Controller method starts:
[HttpPost]
//[ValidateAntiForgeryToken]
public IActionResult Manage_Endorsement(ParentEndorsementViewModel In_ParentEndorsementViewModel)
{
var ParentEndorsementViewModel = In_ParentEndorsementViewModel;
As I say I want to retrieve the Selected Value that the User has chosen from within the Product_DropDownList but when the model (ParentEndorsementViewModel) arrives in the Controller it is empty.
I think you have overcomplicated this somewhat. Your views main model needs both a list to populate the control and a variable to contain the selected value.
For example your model:
public class ParentEndorsementViewModel
{
public int SelectedId { get; set; }
public List<SelectListItem> ProductList { get; set; }
public ParentEndorsementViewModel() {
// Do this just in case you forget to instantiate the list in your first call to the view.
ProductList = New List<SelectListItem>();
}
}
On your view:
#Html.DropDownListFor(x => x.SelectedId, Model.ProductList)
When the user sends this data to back to your controller via a form POST for example, the model binder should marry up to the view model. The value selected by your user is contained in SelectedId variable.
[HttpPost]
public ActionResult MyPostBack (ParentEndorsementViewModel model) {
var myselectedid = model.SelectedId;
//Do whatever
}
You need another property on your ParentEndorsementViewModel, which is what will hold the selected value from the drop down list. Currently your code is attempting to set the selected value to the property that contains the available items.
e.g. in the view model
public class ParentEndorsementViewModel
{
// Child Models:
public List<VW_CMA_PRODUCT_ENDORSEMENT> VW_CMA_PRODUCT_ENDORSEMENTS { get; set; }
// This property will hold all available Products for selection:
public IEnumerable<SelectListItem> Product_DropDownList { get; set; }
// NEW PROPERTY
public int SelectedProductId { get; set; }
}
In the view:
#model App_Endorsement.Models.ParentEndorsementViewModel
#using (Html.BeginForm("Manage_Endorsement", "Endorsement", new { ParentEndorsementViewModel = #Model }, FormMethod.Post, null))
{
#*#Html.AntiForgeryToken()*#
#* CHANGE THE TARGET PROPERTY HERE *#
#Html.DropDownListFor(m => m.SelectedProductId, new SelectList(Model.Product_DropDownList, "Value", "Text", Model.Product_DropDownList), "Show All Products")
<input type = "submit" value = "Send" />
}
In the Controller:
[HttpPost]
//[ValidateAntiForgeryToken]
public IActionResult Manage_Endorsement(ParentEndorsementViewModel In_ParentEndorsementViewModel)
{
var ParentEndorsementViewModel = In_ParentEndorsementViewModel;
var selectedProductId = ParentEndorsementViewModel.SelectedProductId;

How to read the data from a dropdown in ASP.Net MVC 3

Step 1:
I'm using a dropdown to display company locations. The list comes from the Location table.
Step 2:
While the user is registering, the dropdown list will show the locations in question.
When the user selects India, then this value (Location Name) should store in the UserLogin Table.
How can I read the value from the dropdown in ASP.Net MVC 3?
Create a ViewModel for your form
public class CompanyViewModel
{
public int CompanyId { set;get;}
// Other properties of Company
public int SelectedLocationId { set;get;}
public IEnumerable<Location> Locations { set;get;}
}
Assuming you have a Location class like this
public class Location
{
public int Id { set;get;}
public string Name { set;get;}
}
In the Register (HTTPGET) Action method, Return a CompanyViewModel object with Locations filled from database to the View
public ActionReuslt Register()
{
CompanyViewModel model=new CompanyViewModel();
model.Locations =myRepositary.GetAllLocations();
return View(model);
}
Assuming GetAllLocations returns a list of Location objects from your repositary.
And in the Register View which is strongly typed to CompanyViewModel
#model CompanyViewModel
#using(Html.BeginForm())
{
#Html.DropDownListFor(x=>x.SelectedLocationId,
new SelectList(Model.Locations ,"Id",
"Name"),"Select Location")
<input type="submit" value="Save" />
}
Now write an HTTPPost actionmethod to handle the form post(when user submits the form)
[HttpPost]
public ActionResult Register(CompanyViewModel model)
{
if(ModelState.IsValid)
{
// You will have selected Location id available in model.SelectedLocationId property now
//Save and redirect.
}
//Model Validation failed. so Let us reload the locations again
//because HTTP is stateless and ASP.NET MVC is true to HTTP ! :)
model.Locations =myRepositary.GetAllLocations();
return View(model);
}
Here is some sample code that you can modify and use in your scenario. I don't know what your code looks like so I created my own.
In your view:
#model YourProject.ViewModels.YourViewModel
Your locations dropdown:
<td><b>Location:</b></td>
<td>
#Html.DropDownListFor(
x => x.LocationId,
new SelectList(Model.Locations, "Id", "Name", Model.LocationId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.LocationId)
</td>
Your view model:
public class YourViewModel
{
// Partial class
public int LocationId { get; set; }
public IEnumerable<Location> Locations { get; set; }
}
Your create action method:
public ActionResult Create()
{
YourViewModel viewModel = new YourViewModel
{
// Get all the locations from the database
Locations = locationService.FindAll().Where(x => x.IsActive)
}
// Return the view model to the view
// Always use a view model for your data
return View(viewModel);
}
[HttpPost]
public ActionResult Create(YourViewModel viewModel)
{
if (!ModelState.IsValid)
{
viewModel.Locations = locationService.FindAll().Where(x => x.IsActive);
return View(viewModel);
}
// If you browse the values of viewModel you will see that LocationId will have the
// value (unique identifier of location) already set. Now that you have this value
// you can do with it whatever you like.
}
Your location class:
public class Location
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
This is simple as can come. I hope this helps :)
UPDATE:
My service layer is there for any further business logic and then it calls my repository layer to get the data from the database. I use Entity Framework code first. I also use Autofac for my IoC container.
Your service layer:
public class LocationService : ILocationService
{
private readonly ILocationRepository locationRepository;
public LocationService(ILocationRepository locationRepository)
{
this.locationRepository = locationRepository;
}
public IEnumerable<Location> FindAll()
{
return locationRepository.FindAll();
}
}
And your repository:
public class LocationRepository : ILocationRepository
{
YourDbContext db = new YourDbContext();
public IEnumerable<Location> FindAll()
{
return db.Locations.OrderBy(x => x.Name);
}
}
Your database context class:
public class YourDbContext : DbContext
{
public DbSet<Location> Locations { get; set; }
}
It depends how you are getting values of your form if you are passing formcollection then simply you can access its value by this
public ActionResult MyAction (FormCollection form)
{
string value = form["DropDownListName"];
}
Or you can access it through
string value = Request.Form["DropDownListName"];

LIstbox in MVC 2

I am having a Employee Table. From that i want to load the Employee Names in a List Box. I dont know from where i should start. Kindly guide me.
As always start by defining the view model that will represent your data:
public class Employee
{
public string Id { get; set; }
public string Name { get; set; }
}
public class MyViewModel
{
public string SelectedEmployeeId { get; set; }
public IEnumerable<Employee> Employees { get; set; }
}
Then the controller which will manipulate the model:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
// TODO: Instead of hardcoding fetch from your repository
Employees = Enumerable.Range(1, 5).Select(i => new Employee
{
Id = i.ToString(),
Name = "employee " + i
})
};
return View(model);
}
}
And finally generate a dropdown list in the view:
<%: Html.DropDownListFor(
x => x.SelectedEmployeeId,
new SelectList(Model.Employees, "Id", "Name")
) %>
If you want to allow multiple selections a.k.a ListBox a few changes are necessary. First you need an array of employee ids in your model:
public class MyViewModel
{
public string[] SelectedEmployeeIds { get; set; }
public IEnumerable<Employee> Employees { get; set; }
}
And then use the ListBoxFor helper in the view:
<%: Html.ListBoxFor(
x => x.SelectedEmployeeIds,
new SelectList(Model.Employees, "Id", "Name")
) %>
you could also try my AjaxDropdown helper and populate your listbox via jquery Ajax (you don't have to know anything about jquery)
http://awesome.codeplex.com/
there is a live demo that you can try and download

Resources