Populate a DropDownList with Users - c#

I want to make my model to associate with a User from the Identity system in ASP.NET MVC 5, instead of an Employee. My problem is that I can't seem to figure out the magic behind #Html.DropDownList... I'm pulling my hair out. Here is my ViewModel:
public class TicketViewModel
{
[Display(Name="ID#")]
public int TicketId { get; set; }
public int EmployeeId { get; set; }
public int ShopId { get; set; }
public int UserId { get; set; }
public int ApplicationUserId { get; set; }
public string Description { get; set; }
public string Status { get; set; }
public EmployeeViewModel Employee { get; set; }
public ShopViewModel Shop { get; set; }
public TotsUser User { get; set; }
}
and the TicketController method:
// GET: /Ticket/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Ticket ticket = db.Tickets.Find(id);
if (ticket == null)
{
return HttpNotFound();
}
TicketViewModel ticketVM = Mapper.Map(ticket, new TicketViewModel());
ViewBag.EmployeeId = new SelectList(db.Employees, "EmployeeId", "Name", ticketVM.EmployeeId);
ViewBag.ShopId = new SelectList(db.Shops, "ShopId", "Name", ticketVM.ShopId);
ViewBag.UserListing = new SelectList(db.Users, "Id", "UserName", ticketVM.UserId);
return View(ticketVM);
}
The view (the part in question)
<div class="form-group">
#Html.LabelFor(model => model.EmployeeId, "EmployeeId", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("EmployeeId", String.Empty)
#Html.ValidationMessageFor(model => model.EmployeeId)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserId, "UserId", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#* #Html.DropDownList("UserId", String.Empty) *#
#Html.DropDownList("UserId", #ViewBag.UserListing, null);
#Html.ValidationMessageFor(model => model.UserId)
</div>
</div>
I can't even explain how it even works with EmployeeId. This is the way that the scaffold generated it for my original model. It populates EmployeeId just fine. Can someone please explain the dark magic going on with the #Html.DropDownList helper and explain why I can't get the DropDownList to populate with anything?

you can try to change
ViewBag.UserListing = new SelectList(db.Users, "Id", "UserName", ticketVM.UserId);
to
ViewBag.UserId = new SelectList(db.Users, "Id", "UserName", ticketVM.UserId);
or change
#Html.DropDownList("UserId", #ViewBag.UserListing, null);
to
#Html.DropDownList("UserId", (SelectList)#ViewBag.UserListing);
This is incorrect no matter which method you use
#Html.DropDownList("UserId", #ViewBag.UserListing, null);
You have to tell the helper what type of object #ViewBag.UserListing is. In your case it would be (SelectList)#ViewBag.UserListing

Related

C# ASP.NET Core : I am able to update data for only one table but the others are not updating

Am I doing something wrong?
I am not able to update data in my LsstoreDetails table but the Lsstores table is the only table that is updating the data in the database.
Whenever I debug, I can see that model.StoreDetail.StoreDetailsEn is not null and has registered my input but it doesn't save it.
I am not sure what to do as I tried so many different methods and the same issue kept persisting.
I am not getting any errors.
It would be much appreciated if I could receive some help/guidance to resolve this issue.
Thank you!
Model class:
public class Manage
{
public Lsstore Store { get; set; }
public List<Lscity> Cities { get; set; }
public List<Lscountry> Countries { get; set; }
public List<LsstoreStatus> Status { get; set; }
public List<LsstoreType> Types { get; set; }
public List<Lsprovince> Provinces { get; set; }
public List<LsstoreMall> Malls { get; set; }
public List<Lsregion> Regions { get; set; }
public List<LssubBrand> SubBrands { get; set; }
public List <LsstoreBusinessHour> StoreBusinessHours { get; set; }
public List<Lslanguage> Languages { get; set; }
public List<Lsbanner> Banners { get; set; }
public VwLsstoreMgmtInfo LsstoreMgmt { get; set; }
public VwStoreKiboInfo StoreKiboInfo { get; set; }
public LsstoreDetail StoreDetail { get; set; }
}
A part of the view (it is in a form):
<div class="mb-1">
#Html.LabelFor(model => model.Store.StoreDescription, "Store Name",
htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Store.StoreDescription, new { htmlAttributes
= new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Store.StoreDescription, "", new {
#class = "text-danger" })
</div>
<div class="form-group input-group-lg mb-1">
#Html.LabelFor(model => model.StoreDetail.StoreDetailsEn, "Store Description", htmlAttributes: new { #class = "control-label" })
<ul class="nav nav-tabs" id="myTab">
<li class="nav-item">
EN
</li>
<li class="nav-item">
FR
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade show active" id="english">
#Html.TextAreaFor(model => model.StoreDetail.StoreDetailsEn, new { htmlAttributes = new { #class = "form-control" }, rows = 10, cols = 60 })
#Html.ValidationMessageFor(model => model.StoreDetail.StoreDetailsEn, "", new { #class = "text-danger" })
</div>
<div class="tab-pane fade" id="french">
#Html.TextAreaFor(model => model.StoreDetail.StoreDetailsFr, new { htmlAttributes = new { #class = "form-control" }, rows = 10, cols = 60 })
#Html.ValidationMessageFor(model => model.StoreDetail.StoreDetailsFr, "", new { #class = "text-danger" })
</div>
</div>
</div>
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int? id, Manage model)
{
if (id == null)
{
return NotFound();
}
// This part doesn't work
var storeDetail = db.LsstoreDetails.Where(x => x.StoreId.Equals(id)).FirstOrDefault();
if (storeDetail != null)
{
storeDetail.StoreDetailsEn = model.StoreDetail.StoreDetailsEn;
db.SaveChanges();
}
//-------------------------
// This part works
var data = db.Lsstores.Find(id);
if (data != null)
{
data.StoreDescription = model.Store.StoreDescription;
data.Address = model.Store.Address;
data.Local = model.Store.Local;
data.Zip = model.Store.Zip;
data.Sqft = model.Store.Sqft;
data.Fax2 = model.Store.Fax2;
data.Phone1 = model.Store.Phone1;
data.Fax1 = model.Store.Fax1;
data.RegisterCount = model.Store.RegisterCount;
data.PosVersion = model.Store.PosVersion;
data.Latitude = model.Store.Latitude;
data.Longitude = model.Store.Longitude;
data.OpenDate = model.Store.OpenDate;
data.CloseDate = model.Store.CloseDate;
data.ModifiedDate = model.Store.ModifiedDate;
data.ModifiedBy = model.Store.ModifiedBy;
db.SaveChanges();
}
//------------------------------------------
return RedirectToAction("index", "Home");
}
}
I think this is what you wanted to accomplish, but got confused along the way, i would suggest you read about auto mapper it would help clean up your code.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int? id, Manage model)
{
if (id == null)
{
return NotFound();
}
// This part doesn't work
var storeDetail = db.LsstoreDetails.Where(x => x.StoreId.Equals(id)).FirstOrDefault();
if (storeDetail != null)
{
storeDetail.StoreDetailsEn = model.StoreDetail.StoreDetailsEn;
db.LsstoreDetails.update(storeDetail);
}
//-------------------------
// This part works
var data = db.Lsstores.Find(id);
if (data != null)
{
data.StoreDescription = model.Store.StoreDescription;
data.Address = model.Store.Address;
data.Local = model.Store.Local;
data.Zip = model.Store.Zip;
data.Sqft = model.Store.Sqft;
data.Fax2 = model.Store.Fax2;
data.Phone1 = model.Store.Phone1;
data.Fax1 = model.Store.Fax1;
data.RegisterCount = model.Store.RegisterCount;
data.PosVersion = model.Store.PosVersion;
data.Latitude = model.Store.Latitude;
data.Longitude = model.Store.Longitude;
data.OpenDate = model.Store.OpenDate;
data.CloseDate = model.Store.CloseDate;
data.ModifiedDate = model.Store.ModifiedDate;
data.ModifiedBy = model.Store.ModifiedBy;
db.Lsstores.update(data);
}
db.SaveChanges();
//------------------------------------------
return RedirectToAction("index", "Home");
}}

Create Dropdown field form from List with ASP.NET MVC

During the next time, I could create some posts because I'm learning C# and ASP.NET MVC. I'm coming from Pythonic world, so some things are not clear for me.
I would like to generate a List of strings, then I would like to display this list in my form as a DropDownList.
This is my model:
public class Joueur
{
public int ID { get; set; }
[Required, Display(Name = "Nom"), StringLength(30)]
public string Lastname { get; set; }
[Required, Display(Name = "Prénom"), StringLength(30)]
public string Firstname { get; set; }
[Required, StringLength(15)]
public string Poste { get; set; }
public string Image { get; set; }
}
This is my controller according to Create Method:
// GET: Joueurs/Create
public ActionResult Create()
{
List<Strings> posteList = new List<SelectListItem>{ "Gardien", "Défenseur", "Milieu", "Attaquant" };
ViewBag.PosteList = posteList;
return View();
}
And this is my view:
<div class="col-md-10">
#*ViewBag.PosteList is holding all the postes values*#
#Html.DropDownListFor(model => model.Poste, ViewBag.PosteList as SelectList, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Poste, "", new { #class = "text-danger" })
</div>
But I get this issue:
#Html.DropDownListFor(model => model.Poste, ViewBag.PosteList as SelectList, new { #class = "form-control" })
There is no ViewData element of type « IEnumerable » with the key « Poste ».
How I could do that ?
With Django, it's pretty easy, in my model I create a dictionary and I pass this dict in the property, but with C# ASP.NET? I don't find a way to do that.
I assume your view will display a form to represent the Joueur object that you want the user to fill out, and your ViewBag.PosteList will have the values that the user can select from for the Joueur.Poste property. In order to accomplish this, you should create a new/empty Joueur object in your Create controller method and pass it to the view like so:
public ActionResult Create()
{
var model = new Joueur();
List<Strings> posteList = new List<SelectListItem>{ "Gardien", "Défenseur", "Milieu", "Attaquant" };
ViewBag.PosteList = posteList;
return View(model);
}
Then the rest of your original code should work.
I found a solution, hopefully it's a good way:
In my model I created an Enum:
public class Joueur
{
public int ID { get; set; }
[Required, Display(Name = "Nom"), StringLength(30)]
public string Lastname { get; set; }
[Required, Display(Name = "Prénom"), StringLength(30)]
public string Firstname { get; set; }
[Required, StringLength(15)]
public Position Poste { get; set; }
public string Image { get; set; }
}
public enum Position
{
Gardien,
Défenseur,
Milieu,
Attaquant
}
And in my view I added:
<div class="form-group">
#Html.LabelFor(model => model.Poste, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.Poste, new SelectList(Enum.GetValues(typeof(FCSL.Models.Joueur.Position))), "Sélectionner le poste", new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Poste, "", new { #class = "text-danger" })
</div>
</div>
And I applied migration commands. It seems to work now.
#Html.DropDownList("Poste", new SelectList( ViewBag.PosteList, "id", "Poste"))
and in controller
public ActionResult Create()
{
List<Strings> posteList = new List<SelectListItem>{ "Gardien", "Défenseur", "Milieu", "Attaquant" };
ViewBag.PosteList = posteList;
return View(ViewBag.PosteList); // return viewbag
}

Problems with Code First Migration and SQL Server Management Studio

Having a problem with my database for an application I'm developing. I have two classes - House and Donation. A Donation needs to have a House associated with it.
public class House
{
[Key]
public int HouseId { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
}
public class Donation
{
[Key]
public int DonationId { get; set; }
public string TypeOfDonation { get; set; }
public decimal Amount { get; set; }
[ForeignKey("Church")]
public int ChurchId { get; set; }
[ForeignKey("House")]
public int HouseId { get; set; }
public virtual House House { get; set; }
public virtual Church Church { get; set; }
}
I've used Code First Migrations multiple times and its worked but I'm getting two errors. The first one I've noticed is on SQL Server Studio with Donation. It comes up with Invalid Column Name for all of them
Then, when I run the application and attempt to associate a Donation with a House, I get this error The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Donation_dbo.House_HouseId". The conflict occurred in database "ChurchDatabase", table "dbo.House", column 'HouseId'".
Here's the Create in my DonationController where I get that error:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "DonationId,HouseId,TypeOfDonation,Amount,ChurchId")] Donation donation)
{
if (ModelState.IsValid)
{
db.Donations.Add(donation);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ChurchId = new SelectList(db.Churches, "ChurchId", "Name", donation.ChurchId);
return View(donation);
}
Anyone have any idea what is going on? Its been wrecking my head
Found my problem, it was in my View:
<div class="form-group">
#Html.LabelFor(model => model.House.HouseId, "Address", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.House.HouseId, new { id = "HouseId" })
#Html.ValidationMessageFor(model => model.House.HouseId, "", new { #class = "text-danger" })
</div>
</div>
It needed to be:
<div class="form-group">
#Html.LabelFor(model => model.HouseId, "Address", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.HouseId, new { id = "HouseId" })
#Html.ValidationMessageFor(model => model.HouseId, "", new { #class = "text-danger" })
</div>
</div>
I was stupidly putting down House.HouseId when it didn't need the House bit

Editing only part of object in view but pass whole obj to ActionListener

I have a form with a submit button that should pass through the item to the actionlistener. I thought it might be similar to the question in #Html.HiddenFor does not work on Lists in ASP.NET MVC but none of the answers seem to work. You can even see my for-loop taken from one of the answers in there.
[
EDIT: I have gotten rid of the mass of hidden loops and replaced with #Html.EditorFor so that you can see, even if not hidden, the flags list does not get to the actionlistener. This is a problem because when someone edits the flags, there is no way to update the db as I cannot get the ID of the flag updated.
]
The ModelState in the controller is never valid, regardless whether I keep the "[Bind(Include =" there or not. That's just there because of the tutorial for
ASP.NET MVC Tutorial: Web application development with Azure Cosmos DB.
ItemController.cs:
[HttpPost]
[ActionName("ProductEdit")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EditProductAsync( [Bind(Include = "Id, Name, Flags")] Item model)
{
Item product = await DocDBRepo<Item>.GetItem(model.Id);
model.Organisations = product.Organisations;
if (ModelState.IsValid) //Checks item validation via "required" set on properties
{
await DocDBRepo<Item>.UpdateItemAsync(model.Id, model);
return RedirectToAction("Index");
}
return View(model);
}
[HttpGet]
[ActionName("ProductEdit")]
public async Task<ActionResult> EditProductAsync(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Item item = await DocDBRepo<Item>.GetItem(id);
if (item == null)
{
return HttpNotFound();
}
return View(item);
}
ProductEdit.cs:
#model RRPortal.Models.Item
#{
ViewBag.Title = "ProductEdit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>ProductEdit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Flags, htmlAttributes: new { #class = "control-label col-md-2 " })
</div>
#*Flags list*#
#for (int i = 0; i < Model.Flags.Count; i++) //foreach (var flag in Model.Flags)
{
<div class="form-group">
//#Html.HiddenFor(modelItem => Model.Flags[i].Id)
#Html.Label(Model.Flags[i].Name, htmlAttributes: new { #class = "control-label col-md-3" })
#Html.LabelFor(modelItem => Model.Flags[i].Enabled, htmlAttributes: new { #class = "control-label col-md-1" })
<div class="col-md-8">
#Html.EditorFor(modelItem => Model.Flags[i].Enabled, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(modelItem => Model.Flags[i].Enabled, "", new { #class = "text-danger" })
</div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Item.cs:
public class Item
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[Required]
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "flags")]
public List<Flag> Flags { get; set; }
[JsonProperty(PropertyName = "organisations")]
public List<Organisation> Organisations { get; set; }
}
public class Flag
{
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
[Required]
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[Required]
[JsonProperty(PropertyName = "enabled")]
public bool Enabled { get; set; }
}
public class Organisation
{
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "users")]
[Display(Name ="Users")]
public List<User> UserStore { get; set; }
}
public class User
{
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
[Required]
[JsonProperty(PropertyName = "fname")]
public string FName { get; set; }
[Required]
[JsonProperty(PropertyName = "lname")]
public string LName { get; set; }
[Required]
[Display(Name = "Admin?")]
[JsonProperty(PropertyName = "isadmin")]
public bool IsAdmin { get; set; }
}
The Item's Id and Name comes through and is not null when I debug the controller, but the Flags List is always empty. The ModelState shows the following exception: {"The parameter conversion from type 'System.String' to type 'RRPortal.Models.Flag' failed because no type converter can convert between these types."}
I have also been asked where the ModelState is showing the exception so below is a screenshot:
I will gladly update the question if anyone has any questions. I have been tweaking the view for 2 days now and still can't get the item to contain anything. The rendered HTML appears to contain the organisation and inner objects perfectly fine.
Any help is appreciated!
My guess is that in your HttpGet view you have something along the lines of:
[HttpGet]
public ActionResult EditProductAsync()
{
var model = new ProductViewModel()
{
Flags = _uow.Products.GetFlags(),
Organisations = _uow.Products.GetOrganisations()
};
return View(model);
}
Because these objects are not also returned as part of your form, they are returning to the server as empty which is throwing an error for you, thus invalidating the model. Before you check if the model is valid, you should first do something like this:
[HttpPost]
[ActionName("ProductEdit")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EditProductAsync( [Bind(Include = "Id, Name, Flags, Organisations")] Item model)
{
model.Organisations = _uow.Products.GetOrganisations();
model.Flags = _uow.Products.GetFlags();
if (ModelState.IsValid)
{
await DocDBRepo<Item>.UpdateItemAsync(model.Id, model);
return RedirectToAction("Index");
}
return View(model);
}
By populating those fields, any model errors you have are strictly your client's errors on submitting the form.

FluentValidation Improperly Validating Model from DropDown

I have the following two models (stripped to relevant parts):
Models\Department.cs:
public class DepartmentValidator : AbstractValidator<Department> {
public DepartmentValidator() {
RuleFor(d => d.Name)
.NotEmpty().WithMessage("You must specify a name.")
.Length(0, 256).WithMessage("The name cannot exceed 256 characters in length.");
}
}
[Validator(typeof(DepartmentValidator))]
public class Department {
public int Id { get; set; }
[Column(TypeName = "nvarchar")]
[MaxLength(256)]
public string Name { get; set; }
}
Models\FacultyMember.cs:
public class FacultyValidator : AbstractValidator<FacultyMember> {
public FacultyValidator() {
RuleFor(f => f.Name)
.NotEmpty().WithMessage("You must specify a name.")
.Length(0, 64).WithMessage("The name cannot exceed 64 characters in length.");
}
}
[Validator(typeof(FacultyValidator))]
public class FacultyMember {
public int Id { get; set; }
[Column(TypeName = "nvarchar")]
[MaxLength(64)]
public string Name { get; set; }
public virtual ICollection<Department> Departments { get; set; }
public FacultyMember() {
Departments = new HashSet<Department>();
}
}
I have the following controller code:
Controllers\FacultyController.cs:
// GET: Faculty/Create
public ActionResult Create() {
// Get Departments.
var departmentList = db.Departments.ToList().Select(department => new SelectListItem {
Value = department.Id.ToString(),
Text = department.Name
}).ToList();
ViewBag.DepartmentList = departmentList;
var facultyMember = new FacultyMember();
facultyMember.Departments.Add(new Department()); // Create a single dropdown for a department to start out.
return View(facultyMember);
}
// POST: Faculty/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,Departments")] FacultyMember facultyMember) {
// Get Departments.
var departmentList = db.Departments.ToList().Select(department => new SelectListItem {
Value = department.Id.ToString(),
Text = department.Name
}).ToList();
ViewBag.DepartmentList = departmentList;
if (!ModelState.IsValid) { // Problem here...
return View(facultyMember);
}
db.Faculty.Add(facultyMember);
db.SaveChanges();
return RedirectToAction("Index");
}
Views\Faculty\Create.cshtml:
...
<div class="form-group">
#Html.LabelFor(model => model.Departments, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Departments, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Departments, "", new { #class = "text-danger" })
</div>
</div>
...
Views\Shared\EditorTemplates\Department.cshtml:
#model MyProject.Models.Department
#Html.DropDownListFor(model => model.Id, ViewBag.DepartmentList as IEnumerable<SelectListItem>, "Select...", new { #class = "form-control" })
So, when I navigate to the create faculty page, everything displays properly; the 'Departments' field has a dropdown list with the departments in my database. However, upon submitting the form, my model state is invalid (see comment in code above). Upon further inspection, it seems that FluentValidation is spitting out an error because my "Name" field is null. That's exactly what it should do when I'm creating/editing departments, but for this dropdown in faculty members, it shouldn't be validating the entire department, should it? The only thing the dropdown is sending back is the Id, as I've specified.
The only thing that this dropdown sends is the Id of the department, which is properly received. So, what do I need to do to make this work? My goal is to have a dynamic set of dropdown lists, each populated with existing departments in the database. Similar to this example.
Please let me know if anything else needs explaining.
The solution, as explained by Stephen Muecke, was to create a view model to represent all data I wanted to pass to the form and back.
ViewModel\FacultyMemberViewModel.cs:
public class FacultyMemberViewModelValidator : AbstractValidator<FacultyMemberViewModel> {
public FacultyMemberViewModelValidator() {
RuleFor(f => f.Name)
.NotEmpty().WithMessage("You must specify a name.")
.Length(0, 64).WithMessage("The name cannot exceed 64 characters in length.");
RuleFor(s => s.SelectedDepartments)
.NotEmpty().WithMessage("You must specify at least one department.")
}
}
[Validator(typeof(FacultyMemberViewModelValidator))]
public class FacultyMemberViewModel {
public int Id { get; set; }
public string Name { get; set; }
public int[] SelectedDepartments { get; set; }
[DisplayName("Departments")]
public IEnumerable<SelectListItem> DepartmentList { get; set; }
}
Views\Faculty\Create.cshtml:
...
<div class="form-group">
#Html.LabelFor(model => model.DepartmentList, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.ListBoxFor(model => model.SelectedDepartments, Model.DepartmentList, new { #class = "form-control" }) #Html.ValidationMessageFor(model => model.SelectedDepartments, "", new { #class = "text-danger" })
</div>
</div>
...
Controllers\FacultyController.cs:
// GET: Faculty/Create
public ActionResult Create() {
var facultyMemberViewModel = new FacultyMemberViewModel {
DepartmentList = GetDepartmentList()
};
return View(facultyMemberViewModel);
}
// POST: Faculty/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,SelectedDepartments,DepartmentList")] FacultyMemberViewModel facultyMemberViewModel) {
if (!ModelState.IsValid) {
// Re-set the Department list.
if (facultyMemberViewModel.DepartmentList == null) {
facultyMemberViewModel.DepartmentList = GetDepartmentList();
}
return View(facultyMemberViewModel);
}
var facultyMember = new FacultyMember {
Id = facultyMemberViewModel.Id,
Name = facultyMemberViewModel.Name,
};
foreach (var departmentId in facultyMemberViewModel.SelectedDepartments) {
// I'm assuming this is safe to do (aka the records exist in the database)...
facultyMember.Departments.Add(db.Departments.Find(departmentId));
}
db.Faculty.Add(facultyMember);
db.SaveChanges();
return RedirectToAction("Index");
}

Categories