DropDownList with foreach loop in C# MVC - c#

ORIGINAL
I have a website where I can manage cars, brands, and car models. Right now I have controllers, models and views, the application is working, everything was auto generated by Visual Studio, and i am using entity framework (database first).
When I try to create a car, the dropdowns with brands and Car models are not cascading like I want.
I have a solution: add a class (or other property/attribute) to each option tag on each select (dropdown). Then, with JS, i'll do the rest. I just want to know how can I do a foreach loop to build my dropdown, even if it's not the best solution, i'm not discussing that. Remember, I need to do a foreach loop to the carmodel Model, inside the Cars View.
EDIT
Car View
#model MyApp.Models.car
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>car</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.bodytypeId, "bodytypeId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("bodytypeId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.bodytypeId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.manufacturerId, "manufacturerId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("manufacturerId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.manufacturerId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.modelId, "modelId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("modelId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.modelId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.versionId, "versionId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("versionId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.versionId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.fuelId, "fuelId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("fuelId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.fuelId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.transmissionId, "transmissionId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("transmissionId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.transmissionId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.colorId, "colorId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("colorId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.colorId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.horsePower, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.horsePower, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.horsePower, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.kw, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.kw, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.kw, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.cc, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.cc, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.cc, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Co2Emissions, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Co2Emissions, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Co2Emissions, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.mileage, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.mileage, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.mileage, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.year, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.year, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.year, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.doors, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.doors, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.doors, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.seats, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.seats, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.seats, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.plate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.plate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.plate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.price, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.price, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.price, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.shortDescription, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.shortDescription, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.shortDescription, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.longDescription, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.longDescription, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.longDescription, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.sold, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.sold)
#Html.ValidationMessageFor(model => model.sold, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.active, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.active)
#Html.ValidationMessageFor(model => model.active, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.dateAdded, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.dateAdded, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.dateAdded, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.dateSold, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.dateSold, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.dateSold, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Car Model
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MyApp.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
public partial class car
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public car()
{
this.carimages = new HashSet<carimage>();
}
public int id { get; set; }
[Display(Name = "#")]
public Nullable<int> bodytypeId { get; set; }
[Display(Name = "Body Type")]
public Nullable<int> manufacturerId { get; set; }
[Display(Name = "Model")]
public Nullable<int> modelId { get; set; }
[Display(Name = "Version")]
public Nullable<int> versionId { get; set; }
[Display(Name = "Fuel")]
public Nullable<int> fuelId { get; set; }
[Display(Name = "Transmission")]
public Nullable<int> transmissionId { get; set; }
[Display(Name = "Color")]
public Nullable<int> colorId { get; set; }
[Display(Name = "HP")]
public Nullable<int> horsePower { get; set; }
[Display(Name = "KW")]
public Nullable<int> kw { get; set; }
[Display(Name = "CC")]
public Nullable<int> cc { get; set; }
[Display(Name = "CO2")]
public Nullable<double> Co2Emissions { get; set; }
[Display(Name = "Mileage")]
public Nullable<int> mileage { get; set; }
[Display(Name = "Year")]
public Nullable<int> year { get; set; }
[Display(Name = "Doors")]
public Nullable<int> doors { get; set; }
[Display(Name = "Seats")]
public Nullable<int> seats { get; set; }
[Display(Name = "Plate")]
public string plate { get; set; }
[Display(Name = "Price")]
public Nullable<int> price { get; set; }
[Display(Name = "Short Description")]
public string shortDescription { get; set; }
[Display(Name = "Long Description")]
public string longDescription { get; set; }
[Display(Name = "Sold")]
public bool sold { get; set; }
[Display(Name = "Active")]
public bool active { get; set; }
[Display(Name = "Date Added")]
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy hh:mm}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> dateAdded { get; set; }
[Display(Name = "Date Sold")]
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy hh:mm}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> dateSold { get; set; }
public virtual bodytype bodytype { get; set; }
public virtual color color { get; set; }
public virtual fuel fuel { get; set; }
public virtual manufacturer manufacturer { get; set; }
public virtual model model { get; set; }
public virtual transmission transmission { get; set; }
public virtual version version { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<carimage> carimages { get; set; }
}
}
Car Controller
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using MyApp.Models;
namespace MyApp.Controllers
{
public class carsController : Controller
{
private MyAppEntities db = new MyAppEntities();
// GET: cars
public ActionResult Index(string id)
{
string searchString = id;
var cars = db.cars.Include(c => c.bodytype).Include(c => c.color).Include(c => c.fuel).Include(c => c.manufacturer).Include(c => c.model).Include(c => c.transmission).Include(c => c.version);
if (!String.IsNullOrEmpty(searchString))
{
cars = cars.Where(s => s.bodytype.name.Contains(searchString) ||
s.cc.ToString().Contains(searchString) ||
s.Co2Emissions.ToString().Contains(searchString) ||
s.color.name.Contains(searchString) ||
s.dateAdded.Value.ToString("dd-mm-yyyy").Contains(searchString) ||
s.dateSold.Value.ToString("dd-mm-yyyy").Contains(searchString) ||
s.doors.ToString().Contains(searchString) ||
s.fuel.name.Contains(searchString) ||
s.horsePower.ToString().Contains(searchString) ||
s.id.ToString().Contains(searchString) ||
s.kw.ToString().Contains(searchString) ||
s.longDescription.Contains(searchString) ||
s.manufacturer.name.Contains(searchString) ||
s.mileage.ToString().Contains(searchString) ||
s.model.name.Contains(searchString) ||
s.plate.Contains(searchString) ||
s.price.ToString().Contains(searchString) ||
s.seats.ToString().Contains(searchString) ||
s.shortDescription.Contains(searchString) ||
s.transmission.name.Contains(searchString) ||
s.version.name.Contains(searchString) ||
s.year.ToString().Contains(searchString)
);
}
return View(cars.ToList());
}
// GET: cars/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
car car = db.cars.Find(id);
if (car == null)
{
return HttpNotFound();
}
return View(car);
}
// GET: cars/Create
public ActionResult Create()
{
ViewBag.bodytypeId = new SelectList(db.bodytypes, "id", "name");
ViewBag.colorId = new SelectList(db.colors, "id", "name");
ViewBag.fuelId = new SelectList(db.fuels, "id", "name");
ViewBag.manufacturerId = new SelectList(db.manufacturers, "id", "name");
ViewBag.modelId = new SelectList(db.models, "id", "name");
ViewBag.transmissionId = new SelectList(db.transmissions, "id", "name");
ViewBag.versionId = new SelectList(db.versions, "id", "name");
return View();
}
// POST: cars/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "id,bodytypeId,manufacturerId,modelId,versionId,fuelId,transmissionId,colorId,horsePower,kw,cc,Co2Emissions,mileage,year,doors,seats,plate,price,shortDescription,longDescription,sold,active,dateAdded,dateSold")] car car)
{
if (ModelState.IsValid)
{
db.cars.Add(car);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.bodytypeId = new SelectList(db.bodytypes, "id", "name", car.bodytypeId);
ViewBag.colorId = new SelectList(db.colors, "id", "name", car.colorId);
ViewBag.fuelId = new SelectList(db.fuels, "id", "name", car.fuelId);
ViewBag.manufacturerId = new SelectList(db.manufacturers, "id", "name", car.manufacturerId);
ViewBag.modelId = new SelectList(db.models, "id", "name", car.modelId);
ViewBag.transmissionId = new SelectList(db.transmissions, "id", "name", car.transmissionId);
ViewBag.versionId = new SelectList(db.versions, "id", "name", car.versionId);
return View(car);
}
// GET: cars/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
car car = db.cars.Find(id);
if (car == null)
{
return HttpNotFound();
}
ViewBag.bodytypeId = new SelectList(db.bodytypes, "id", "name", car.bodytypeId);
ViewBag.colorId = new SelectList(db.colors, "id", "name", car.colorId);
ViewBag.fuelId = new SelectList(db.fuels, "id", "name", car.fuelId);
ViewBag.manufacturerId = new SelectList(db.manufacturers, "id", "name", car.manufacturerId);
ViewBag.modelId = new SelectList(db.models, "id", "name", car.modelId);
ViewBag.transmissionId = new SelectList(db.transmissions, "id", "name", car.transmissionId);
ViewBag.versionId = new SelectList(db.versions, "id", "name", car.versionId);
return View(car);
}
// POST: cars/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "id,bodytypeId,manufacturerId,modelId,versionId,fuelId,transmissionId,colorId,horsePower,kw,cc,Co2Emissions,mileage,year,doors,seats,plate,price,shortDescription,longDescription,sold,active,dateAdded,dateSold")] car car)
{
if (ModelState.IsValid)
{
db.Entry(car).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.bodytypeId = new SelectList(db.bodytypes, "id", "name", car.bodytypeId);
ViewBag.colorId = new SelectList(db.colors, "id", "name", car.colorId);
ViewBag.fuelId = new SelectList(db.fuels, "id", "name", car.fuelId);
ViewBag.manufacturerId = new SelectList(db.manufacturers, "id", "name", car.manufacturerId);
ViewBag.modelId = new SelectList(db.models, "id", "name", car.modelId);
ViewBag.transmissionId = new SelectList(db.transmissions, "id", "name", car.transmissionId);
ViewBag.versionId = new SelectList(db.versions, "id", "name", car.versionId);
return View(car);
}
// GET: cars/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
car car = db.cars.Find(id);
if (car == null)
{
return HttpNotFound();
}
return View(car);
}
// POST: cars/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
car car = db.cars.Find(id);
db.cars.Remove(car);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}

Original
With ASP.NET MVC, you use server-side pre-processing to bind servers-side models to the .cshtml. From within the markup you can use tag helpers to build out common controls and user input components, this is where the razor view engine comes into play. Odeto-Code by Scott Allen has a great article on how you use these technologies together to build out a drop-down-list control specifically.
Here is part of that examples, .cshtml:
#Html.LabelFor(m=>m.SelectedFlavorId)
#Html.DropDownListFor(m => m.SelectedFlavorId, Model.FlavorItems)
#Html.ValidationMessageFor(m=>m.SelectedFlavorId)
<input type="submit" value="Submit" />
And here is the corresponding model, ViewModel.cs:
public class ViewModel
{
private readonly List<IceCreamFlavor> _flavors;
[Display(Name = "Favorite Flavor")]
public int SelectedFlavorId { get; set; }
public IEnumerable<SelectListItem> FlavorItems
{
get { return new SelectList(_flavors, "Id", "Name");}
}
}
As an additional resource there is actually several other stackoverflow Q/A's that cover questions similar to this, here is one that is noteable.
Update 1
I just want to know how can I do a foreach loop to build my dropdown
Again you can use the razor view engine here. It allows for interaction with a server-side C# model and a means to build HTML markup from that. Here is an example:
<select>
#{
foreach (var item in Model.ListOfItems)
{
<option value="item.Value" customAttribute="item.SomethingSpecial">
item.Name
</option>
}
}
</select>
Update 2
You car model does not define a list of models. You need to specify what the options are in order to do a foreach. In other words you cannot build a dropdownlist from a property on a C# model that is not a list. Does that help?

You can do this in C# rather than JS, a quick example here:
public class FindUser
{
// Where the items from the DB will be kept
public Dictionary<int, string> CountryList { get; set; }
// Used to store the users selected option
public int SelectedCountry { get; set; }
// A constructor to be called when the page renders
public FindUser()
{
PopulateCountryDropdown();
}
public void PopulateLeaDropdown()
{
// 1. Grab your items from the database, store it within a databale
// 2. Loop through the datatable and add each row to the list
CountryList = new Dictionary<int, string>();
foreach(DataRow row in dt.Rows)
{
CountryList.Add(Convert.ToInt32(row["ID"]), row["country"].ToString());
}
}
}
Then in your frontend add:
#Html.DropDownListFor(u => u.SelectedCountry, new SelectList(Model.CountryList, "Key", "Value"), "Select your country", new { #class = "form-control countries", id = "country_list" })

Solution found HERE
School database with the following 2 tables.
StateMaster
DistrictMaster
Step 1
Open Visual Studio then select File >> New >> Project then select ASP.Net MVC 4 Web Application.
Step 2
Select Internet Application then click OK.
Step 3
Select the Model folder then create a new Model class.
StudentModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcDemoApplication.Models
{
public class StudentModel
{
public IList<SelectListItem> StateNames { get; set; }
public IList<SelectListItem> DistrictNames { get; set; }
}
}
Step 4
Create a .edmx file and connect with the database.
Step 5
Create a new Controller. In this article I create DropDownListController.cs.
DropDownListController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcDemoApplication.Models;
namespace MvcDemoApplication.Controllers
{
public class DropDownListController : Controller
{
//
// GET: /DropDownList/
SchoolEntities schoolEntity = new SchoolEntities();
public ActionResult Index()
{
List<SelectListItem> stateNames = new List<SelectListItem>();
StudentModel stuModel=new StudentModel();
List<StateMaster> states = schoolEntity.StateMasters.ToList();
states.ForEach(x =>
{
stateNames.Add(new SelectListItem { Text = x.StateName , Value = x.StateId.ToString() });
});
stuModel.StateNames = stateNames;
return View(stuModel);
}
}
}
Index.cshtml
#model MvcDemoApplication.Models.StudentModel
#{
ViewBag.Title = "Index";
}
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<h2>Cascading Dropdownlist</h2>
<table>
<tr>
<td>
<label>State</label>
</td>
<td>
#Html.DropDownListFor(x => x.StateNames, Model.StateNames, "--Select--", new { #id="ddlState"});
</td>
</tr>
</table>
Understand the Code
In Studentmodel we have the following 2 properties:
public IList<SelectListItem> StateNames { get; set; }
public IList<SelectListItem> DistrictNames { get; set; }
Here we are using the SelectListItem class, this class has the following 3 properties:
Selected: This is a bool type to show in a dropdown (as selected) true or false by default.
Text: This is a string type, for the dropdown text.
Value: This is string type for the value of the dropdown
If you notice in the dropdownlist, we also need the same properties. For this reason we are using SelectListItem in a Ilist.
DropdownlistController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcDemoApplication.Models;
namespace MvcDemoApplication.Controllers
{
public class DropDownListController : Controller
{
//
// GET: /DropDownList/
SchoolEntities schoolEntity = new SchoolEntities();
public ActionResult Index()
{
List<SelectListItem> stateNames = new List<SelectListItem>();
StudentModel stuModel=new StudentModel();
List<StateMaster> states = schoolEntity.StateMasters.ToList();
states.ForEach(x =>
{
stateNames.Add(new SelectListItem { Text = x.StateName , Value = x.StateId.ToString() });
});
stuModel.StateNames = stateNames;
return View(stuModel);
}
}
In the preceding code we create the SchoolEntities object, in this object all the related tables exist.
SchoolEntities schoolEntity = new SchoolEntities();
List<StateMaster> states = schoolEntity.StateMasters.ToList();
In the preceding line of code, all the related data of the StateMasters tables comes into the StateMaster list object.
states.ForEach(x =>
{
stateNames.Add(new SelectListItem { Text = x.StateName , Value = x.StateId.ToString() });
});
Now it is time to add entity data into the Text and value properties, the all collection will be stored into the stateNames object.
Index.cshtml
#model MvcDemoApplication.Models.StudentModel
#{
ViewBag.Title = "Index";
}
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<h2>Cascading Dropdownlist</h2>
<table>
<tr>
<td>
<label>State</label>
</td>
<td>
#Html.DropDownListFor(x => x.StateNames, Model.StateNames, "--Select--", new { #id="ddlState"});
</td>
</tr>
</table>
The preceding code shows the model data in View. Now to understand how it works.
#Html.DropDownListFor(x => x.StateNames, Model.StateNames, "--Select--", new { #id="ddlState"});
Look at the preceding code, we used here, #Html helper classes for creating a DropDownList. In the DropDownListFor helper class we used 4 parameters.
x=>x.StateNames: For getting the values of the collection from the entity.
Model.StateNames: Collections of states.
“—Select--”: Default value, when the dropdown list will be populated.
new {#id=”ddlState”}: In this part we can define an id, class and name for the control.
How to do cascading between two dropdownlists.
DropdownlistController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcDemoApplication.Models;
namespace MvcDemoApplication.Controllers
{
public class DropDownListController : Controller
{
//
// GET: /DropDownList/
SchoolEntities1 schoolEntity = new SchoolEntities1();
public ActionResult Index()
{
List<SelectListItem> stateNames = new List<SelectListItem>();
StudentModel stuModel=new StudentModel();
List<StateMaster> states = schoolEntity.StateMasters.ToList();
states.ForEach(x =>
{
stateNames.Add(new SelectListItem { Text = x.StateName , Value = x.StateId.ToString() });
});
stuModel.StateNames = stateNames;
return View(stuModel);
}
[HttpPost]
public ActionResult GetDistrict(string stateId)
{
int statId;
List<SelectListItem> districtNames = new List<SelectListItem>();
if (!string.IsNullOrEmpty(stateId))
{
statId = Convert.ToInt32(stateId);
List<DistrictMaster> districts = schoolEntity.DistrictMasters.Where(x => x.StateId == statId).ToList();
districts.ForEach(x =>
{
districtNames.Add(new SelectListItem { Text = x.DistrictName, Value = x.DistrictId.ToString() });
});
}
return Json(districtNames, JsonRequestBehavior.AllowGet);
}
}
}
Index.cshtml
#model MvcDemoApplication.Models.StudentModel
#{
ViewBag.Title = "Index";
}
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<h2>Cascading Dropdownlist</h2>
<table>
<tr>
<td>
<label>State</label>
</td>
<td>
#Html.DropDownListFor(x => x.StateNames, Model.StateNames, "--Select--", new { #id="ddlState"});
</td>
</tr>
<tr>
<td>
<label>District</label>
</td>
<td id="District">
#Html.DropDownListFor(x => x.DistrictNames, new List<SelectListItem>(), "--Select--", new { #id="ddlDistrict"});
</td>
</tr>
</table>
<script type="text/javascript">
$(document).ready(function () {
$('#ddlState').change(function () {
$.ajax({
type: "post",
url: "/DropDownList/GetDistrict",
data: { stateId: $('#ddlState').val() },
datatype: "json",
traditional: true,
success: function (data) {
var district = "<select id='ddlDistrict'>";
district = district + '<option value="">--Select--</option>';
for (var i = 0; i < data.length; i++)
{
district = district + '<option value=' + data[i].Value + '>' + data[i].Text + '</option>';
}
district = district + '</select>';
$('#District').html(district);
}
});
});
});
</script>
That's it. Press F5 and run your code.

Look at Nuget package Mvc.CascadeDropDown:
https://www.nuget.org/packages/Mvc.CascadeDropDown/
Here is how I am using it:
#Html.CascadingDropDownListFor(m => m.ArticleGroup_Nr, "Department_Nr",
Url.Action("GetArticleGroups"), "DepartmentNr", "-- Select item --", true,
new { #class = "form-control", style = "width: 450px" })
Here Department_Nr specifies the parent dropdown elsewhere in the View - either a regular dropdownlist or another cascaded dropdownlist.
I then created a JSON Action GetArticleGroups on the same Controller that accepts a DepartmentNr parameter, which is passed the current value of the parent dropdown.
The JSON Action will be called everytime the value of the parent dropdown is changed because #Html.Cascading... also attaches an onchange-eventhandler to the parent object.
public virtual JsonResult GetArticleGroups(int DepartmentNr)
{
var items = provider.ArticleGroups.Where(m => m.Parent_Nr == DepartmentNr);
return GetJson(items); // convert items to JSON [ { "Value":"xx", "Text":"yy" } ]
}
private JsonResult GetJson(IQueryable<ICatalogueItem> items)
{
var data = items
.Select(x => new { Value = x.Number, Text = x.Text })
.OrderBy(o => o.Text);
return Json(data, JsonRequestBehavior.AllowGet);
}
... Or see this article on how to build it yourself:
http://www.c-sharpcorner.com/UploadFile/4d9083/creating-simple-cascading-dropdownlist-in-mvc-4-using-razor/

Related

MVC 5 - How to update relational table using EF code first

I am relatively new to MVC 5, and having a problem figuring out how to update a relational table. I am using EF code first. I've spent a lot of time searching for a solution but I just can't find anything that relates to my code which is why I have no other choise than to ask here, so I apologise up front if this has already been answered.
I am including the relational table in my Razor view which works very well. But when I want to update the table it simply doesn't update even though I get no errors with my current code.
I've also tried adding an extra Bind[(Include = "Id,FirstName,LastName")], but this used the Booking FirstName and LastName.
I am unsure if my methods are the "proper" ones. My logic tells me that I need to fetch the data from the view and retrieve them in the controller but I don't know how if I can't use Bind or the db.Entry(item).State = EntityState.Modified?
Booking.cs
namespace Ventures.Innovation.InteractiveModel.Context
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class Bookings
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Bookings()
{
AttendingPeople = new HashSet<AttendingPeople>();
}
public int Id { get; set; }
[Required]
[StringLength(128)]
public string AspNetUserFk { get; set; }
[Required]
public DateTime Date { get; set; }
[Required]
[StringLength(100)]
public string FirstName { get; set; }
[Required]
[StringLength(50)]
public string LastName { get; set; }
public virtual AspNetUsers AspNetUsers { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<AttendingPeople> AttendingPeople { get; set; }
}
}
AttendingPeople.cs
namespace Ventures.Innovation.InteractiveModel.Context
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class AttendingPeople
{
public int Id { get; set; }
public int BookingId { get; set; }
[Required]
[StringLength(100)]
public string FirstName { get; set; }
[Required]
[StringLength(50)]
public string LastName { get; set; }
public virtual Bookings Bookings { get; set; }
}
}
Controller
// GET: AdminHome/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Bookings bookings = db.Bookings.Find(id);
if (bookings == null)
{
return HttpNotFound();
}
ViewBag.AspNetUserFk = new SelectList(db.AspNetUsers, "Id", "Email", bookings.AspNetUserFk);
var attendingPeople = db.AttendingPeople.Where(a => a.BookingId == id).ToList();
bookings.AttendingPeople = attendingPeople;
return View(bookings);
}
// POST: AdminHome/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,AspNetUserFk,Date,FirstName,LastName")] Bookings bookings)
{
if (ModelState.IsValid)
{
db.Entry(bookings).State = EntityState.Modified;
db.SaveChanges();
var editedAttendingPeople = db.AttendingPeople.Where(a => a.BookingId == bookings.Id).ToList();
foreach (var item in editedAttendingPeople)
{
db.Entry(item).State = EntityState.Modified;
}
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.AspNetUserFk = new SelectList(db.AspNetUsers, "Id", "Email", bookings.AspNetUserFk);
return View(bookings);
}
View
#model Ventures.Innovation.InteractiveModel.Context.Bookings
#{
ViewBag.Title = "Edit booking";
}
<h2>Edit booking</h2>
<hr />
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
</div>
<div class="form-group">
#Html.LabelFor(model => model.AspNetUserFk, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("AspNetUserFk", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.AspNetUserFk, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Date, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Date, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Date, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.FirstName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.LastName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.LastName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.LastName, "", new { #class = "text-danger" })
</div>
</div>
#if (Model.AttendingPeople.Count > 0)
{
#Html.Label("Attending people")
foreach (var attendingPeople in Model.AttendingPeople)
{
<div class="form-group">
<div class="col-md-10">
#Html.LabelFor(modelItem => attendingPeople.FirstName, htmlAttributes: new { #class = "control-label col-md-5", #style = "padding-left: 0;" })
#Html.LabelFor(modelItem => attendingPeople.LastName, htmlAttributes: new { #class = "control-label col-md-5", #style = "padding-left: 0;" })
</div>
<div class="col-md-10">
#Html.EditorFor(modelItem => attendingPeople.FirstName, new { htmlAttributes = new { #class = "form-control col-md-5", #style = "display: initial;" } })
#Html.EditorFor(modelItem => attendingPeople.LastName, new { htmlAttributes = new { #class = "form-control col-md-5", #style = "display: initial;" } })
</div>
</div>
}
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save changes" class="btn btn-primary" />
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I want to save the updated data to AttendingPeople table in the database but nothing happens.
Thanks to JARRRRG for helping me out here. :)
To solve this I needed to make sure my naming was exactly the same. Apparently this is how it finds/binds from the view to the controller. Also I needed to make sure I used a for loop so the collection could distinguish between the objects.
So this is my updated view:
#if (Model.AttendingPeople.Count > 0)
{
#Html.Label("Attending people")
var attendingPeople = Model.AttendingPeople.ToArray();
foreach (int i = 0; i < attendingPeople.Length; i++)
{
#Html.HiddenFor(modelItem => attendingPeople[i].Id)
<div class="form-group">
<div class="col-md-10">
#Html.LabelFor(modelItem => attendingPeople[i].FirstName, htmlAttributes: new { #class = "control-label col-md-5", #style = "padding-left: 0;" })
#Html.LabelFor(modelItem => attendingPeople[i].LastName, htmlAttributes: new { #class = "control-label col-md-5", #style = "padding-left: 0;" })
</div>
<div class="col-md-10">
#Html.EditorFor(modelItem => attendingPeople[i].FirstName, new { htmlAttributes = new { #class = "form-control col-md-5", #style = "display: initial;" } })
#Html.EditorFor(modelItem => attendingPeople[i].LastName, new { htmlAttributes = new { #class = "form-control col-md-5", #style = "display: initial;" } })
</div>
</div>
}
}
And this is my new Edit:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,AspNetUserFk,Date,FirstName,LastName")] Bookings bookings, ICollection<AttendingPeople> attendingPeople)
{
if (ModelState.IsValid)
{
db.Entry(bookings).State = EntityState.Modified;
db.SaveChanges();
foreach (var item in attendingPeople)
{
item.BookingId = bookings.Id;
db.Entry(item).State = EntityState.Modified;
}
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.AspNetUserFk = new SelectList(db.AspNetUsers, "Id", "Email", bookings.AspNetUserFk);
bookings = db.Bookings.Include(at => at.AttendingPeople).SingleOrDefault(b => b.Id == bookings.Id)
return View(bookings);
}

ASP.Net MVC Unable to edit user because od the [Compare(Password)] in the class User

I have table named Korisnik (on my language, on english its User) and i added an Edit ActionResult in my Controller , but it wont work because of the [Compare("Lozinka")] that is comparing the password from the database and the added property PotvrdiLozinku, in other words i must enter the Confirm password in order to Submit the changes
namespace ProjekatFinalni.Models
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
public partial class Korisnik
{
public int KorisnikID { get; set; }
[DisplayName("Korisnicko ime:")]
[Required(ErrorMessage ="Molimo vas unesite korisnicko ime.")]
public string Korisnickoime { get; set; }
[DisplayName("Lozinka:")]
[DataType(DataType.Password)]
[Required(ErrorMessage = "Molimo vas unesite lozinku.")]
public string Lozinka { get; set; }
[DisplayName("Admin:")]
public bool DaLiJeAdmin { get; set; }
[DisplayName("Gost:")]
public bool Gost { get; set; }
[DisplayName("Pravo za unos:")]
public bool PravoUnosa { get; set; }
[DisplayName("Potvrdi lozinku:")]
[DataType(DataType.Password)]
[Compare("Lozinka",ErrorMessage ="Lozinke se ne poklapaju.")]
public string PotvrdiLozinku { get; set; }
public string LoginErrorPoruka { get; set; }
}
This is the Edit ActionResult in my controller
public ActionResult Edit(int id)
{
using (BazaProjekatEntities4 dbModel = new BazaProjekatEntities4())
{
return View(dbModel.Korisniks.Where(x => x.KorisnikID == id).FirstOrDefault());
}
}
[HttpPost]
public ActionResult Edit(int id,Korisnik k)
{
try
{
using (BazaProjekatEntities4 dbModel = new BazaProjekatEntities4())
{
dbModel.Entry(k).State = EntityState.Modified;
dbModel.SaveChanges();
}
return RedirectToAction("Izlistaj");
}
catch
{
return View();
}
}
And this is the Edit.cshtml
#model ProjekatFinalni.Models.Korisnik
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Korisnik</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.KorisnikID)
<div class="form-group">
#Html.LabelFor(model => model.Korisnickoime, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Korisnickoime, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Korisnickoime, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Lozinka, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Lozinka, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Lozinka, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PotvrdiLozinku, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PotvrdiLozinku, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PotvrdiLozinku, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.DaLiJeAdmin, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.DaLiJeAdmin)
#Html.ValidationMessageFor(model => model.DaLiJeAdmin, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Gost, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.Gost)
#Html.ValidationMessageFor(model => model.Gost, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PravoUnosa, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.PravoUnosa)
#Html.ValidationMessageFor(model => model.PravoUnosa, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Sacuvaj" class="btn btn-default" />
</div>
</div>
</div>
}
Only want to edit the permissions(Admin, Gost and PravoUnosa
EDIT( Added the registration form that i used)
[HttpPost]
public ActionResult DodajiliIzmeni(Korisnik korisnikmodel)
{
using (BazaProjekatEntities4 Modelkorisnik = new BazaProjekatEntities4())
{
if(Modelkorisnik.Korisniks.Any(x=> x.Korisnickoime == korisnikmodel.Korisnickoime))
{
ViewBag.DuplicateMessage = "Korisnicko ime vec postoji.";
return View("DodajiliIzmeni", korisnikmodel);
}
Modelkorisnik.Korisniks.Add(korisnikmodel);
Modelkorisnik.SaveChanges();
}
ModelState.Clear();
ViewBag.SuccessMessage = "Registracija je uspela";
return RedirectToAction("Index", "Login");
}
You should create a view model specific for the view, which has the properties and validation attributes on them as needed by the view and use that to transfer data between your view and action method.
public class EditUserVm
{
public int Id { get; set; }
[DisplayName("Korisnicko ime:")]
public string UserName { get; set; }
[DisplayName("Admin:")]
public bool Admin { get; set; }
[DisplayName("Gost:")]
public bool Gost { get; set; }
[DisplayName("Pravo za unos:")]
public bool PravoUnosa { get; set; }
}
Now you will use this view model for your GET and POST action methods. In your GET action method, first create an object of this view model, then get your Korisniks object for the Id passed in, Read and map the property values to the view model object and pass it to the view.
public ActionResult Edit(int id)
{
using (var dbModel = new BazaProjekatEntities4())
{
var user = dbModel.Korisniks.FirstOrDefault(x => x.KorisnikID == id);
// to do: If user is NULL, return a "Not found" view to user ?
var vm = new EditUserVm { Id = id };
vm.UserName = user.UserName;
vm.Admin = user.Admin;
vm.Gost = user.Gost;
vm.PravoUnosa = user.PravoUnosa;
return View(vm);
}
}
Now makes sure your view is strongly typed to this view model because we are passing an object of the EditUserVm class to it.
#model YourNamespaceGoesHere.EditUserVm
#using (Html.BeginForm())
{
#Html.HiddenFor(a=>a.Id)
<label>#Model.UserName</label>
#Html.LabelFor(a=>a.Admin)
#Html.CheckBoxFor(a=>a.Admin)
#Html.LabelFor(a=>a.Gost)
#Html.CheckBoxFor(a=>a.Gost)
#Html.LabelFor(a=>a.PravoUnosa)
#Html.CheckBoxFor(a=>a.PravoUnosa)
<button type="submit" >Save</button>
}
Now you will use the same view model as the action method parameter. Inside the method, we will read again the User entity from the database and udpate only the field we want to
[HttpPost]
public ActionResult Edit(EditUserVm model)
{
var db = new BazaProjekatEntities4();
var user = db.Korisniks.FirstOrDefault(x => x.KorisnikID == model.Id);
// to do : Do a null check on user to be safe :)
// Map the property values from view model to entity object
user.Admin = model.Admin;
user.Gost = model.Gost;
user.PravoUnosa = model.PravoUnosa;
db.Entry(k).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
In short, create a view model with properties absolutely needed by the view/ your code and use that to transfer data between your action method and view.
The solution was very simple and it could be from the start, i just need to add the user.PotvrdiLozinku = user.Lozinka; that will tell it that the Confirm password is equal to Password (For the [Compare] that is in the User class. :)
[HttpPost]
public ActionResult Edit(EditUserVm model)
{
var db = new BazaProjekatEntities4();
var user = db.Korisniks.FirstOrDefault(x => x.KorisnikID == model.Id);
// to do : Do a null check on user to be safe :)
// Map the property values from view model to entity object
user.Admin = model.Admin;
user.PotvrdiLozinku = user.Lozinka; // this line was missing
user.Gost = model.Gost;
user.PravoUnosa = model.PravoUnosa;
db.Entry(k).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}

Partial View Count=0, value not being sent to the controller

Only the value of the Partial view form is not being passed to the controller.:/ FounderInvestmentVM is the one whose partial view i have created,this VM is inside of PropertyVM.The other values are passed to the controller but not that of Partial View. It always gives FounderInvestments Count=0 when i put a debugger and see it :/
This is my PROPERTY VM containing FounderInvestorVM:-
namespace propertyMgmt.ViewModel.PropertyViewModel
{
public class PropertyViewModel
{
public int? Id { get; set; }
[Required]
[DisplayName("Property Title")]
public string PropertyTitle { get; set; }
......
public List<FounderInvestmentViewModel> FounderInvestments { get; set; }=new List<>(FounderInvestmentViewModel);
}
}
This is FounderInvestorVM:-
public class FounderInvestmentViewModel
{
public int? Id { get; set; }
public int PropertyId { get; set; }
public int InvestorId { get; set; }
public double Investment { get; set; }
public int InstallmentPeriod { get; set; }
public IEnumerable<SelectListItem> FounderInvestorList { get; set; }
}
This is My COntroller:-
public ActionResult Create(PropertyViewModel _propertyViewModel)
{
if (ModelState.IsValid)
{
Property property = new Property();
property.Id = _propertyViewModel.Id ?? 0;
property.PropertyTitle = _propertyViewModel.PropertyTitle;
........other properties......
}
_propertyQueryProcessor.Create(property);
foreach(var investment in _propertyViewModel.FounderInvestments)
{
FounderInvestment _founderInvestment = new FounderInvestment
{
Id = investment.Id??0,
InstallmentPeriod = investment.InstallmentPeriod,
InvestorId = investment.InvestorId,
PropertyId = investment.PropertyId,
Investment = investment.Investment
};
_founderInvestmentQueryProcessor.Create(_founderInvestment);
}
THIS IS THE PARTIAL VIEW:-
#model propertyMgmt.ViewModel.FounderInvestmentViewModel
#{
ViewData.TemplateInfo.HtmlFieldPrefix = "PropertyViewModel"; //bind to main model
}
<div class="founderInvestmentDetails">
#using (Html.BeginCollectionItem("founderInvestmentDetails"))
{
#Html.HiddenFor(m => m.Id, new { #class = "id" })
#Html.HiddenFor(m=>m.PropertyId, new { #name = "PropertyId" })
<div class="form-group">
#Html.LabelFor(m => m.FounderInvestorList, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(m=>m.FounderInvestorList,Model.FounderInvestorList , "Select Investor", htmlAttributes: new {#class = "form-control"})
#Html.ValidationMessageFor(m => m.FounderInvestorList, "", new { #class = "text-danger" })
#Html.HiddenFor(m => m.InvestorId, new { #name = "InvestorId" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Investment, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(m=>m.Investment, new { htmlAttributes = new { #class = "form-control",#type="number" } })
#Html.ValidationMessageFor(m => m.Investment, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.InstallmentPeriod, htmlAttributes: new { #class = "control-label col-md-2", #type = "number" })
<div class="col-md-10">
#Html.EditorFor(m => m.InstallmentPeriod, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(m => m.InstallmentPeriod, "", new { #class = "text-danger" })
</div>
</div>
}
</div>
And finally this is the main VIEW:-
#model propertyMgmt.ViewModel.PropertyViewModel.PropertyViewModel
#using (Html.BeginForm("Create", "Property", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
#Html.LabelFor(model => model.PropertyTitle, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PropertyTitle, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PropertyTitle, "", new { #class = "text-danger" })
</div>
</div>
.....(other form groups)
<div id="founderInvestmentDetails" class="form-group">
#foreach(var founderInvestmentDetails in Model.FounderInvestments)
{
#Html.Partial("_FounderInvestmentDetails", founderInvestmentDetails)
}
</div>
Sorry,there was a silly mistake here.As #Stephen Muecke pointed out
#using (Html.BeginCollectionItem("founderInvestmentDetails"))
Should be
#using (Html.BeginCollectionItem("FounderInvestments"))
Because BeginCollectionItem uses name of the Collection it is working on.

Dropdownlist selected value not saved into database

I am new to this . I am using Northwind database .
The REGION DESCRIPTIONS appears in the dropdownlist but when i try to create a new customer , no new record is saved into database , because dropdownlist selected value is not working. These two tables are not linked with foreign key in the model .
Any help ?! Thank you so.
this is the view :
#model Northwind.Customer
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Customer</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.CustomerID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CustomerID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CustomerID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CompanyName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CompanyName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CompanyName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ContactName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ContactName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ContactName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ContactTitle, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ContactTitle, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ContactTitle, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Address, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Address, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Address, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.City, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.City, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.City, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Region, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("Region", String.Empty)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PostalCode, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PostalCode, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PostalCode, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Country, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Country, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Country, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Phone, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Phone, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Phone, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Fax, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Fax, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Fax, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
this is the controller :
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using Northwind.Models;
using System.Data.Entity;
using System.Data.Entity.Validation;
namespace Northwind.Controllers
{
public class CustomerController : Controller
{
dbNorthwindEntities db = new dbNorthwindEntities();
// GET: Customer
// public ActionResult Index()
// {
// return View(db.Customers.ToList().Take(10));
// return View(db.Customers.ToList());
// }
public ActionResult Index()
{
return View(db.Customers.ToList());
// var customers = db.Customers.Include(a => a.Region);
// return View(customers.ToList());
// var customers = db.Customers.Include(a => a.Region);
// return View(customers.ToList());
// var customers = db.Customers.Include("Region");
//return View(customers.ToList());
// return View(db.Customers.ToList());
}
//me marr formen per create
[HttpGet]
public ActionResult Create()
{
ViewBag.Region = new SelectList(db.Regions, "RegionDescription", "RegionDescription");
return View();
}
//me bo post ne databaze
[HttpPost]
public ActionResult Create(Customer customer)
{
if (ModelState.IsValid)
{
db.Customers.Add(customer);
try
{
db.SaveChanges();
}
catch (DbEntityValidationException ex)
{
foreach (var entityValidationErrors in ex.EntityValidationErrors)
{
foreach (var validationError in entityValidationErrors.ValidationErrors)
{
Response.Write("Property: " + validationError.PropertyName + " Error: " + validationError.ErrorMessage);
}
}
}
//return RedirectToAction("Index");
}
ViewBag.Region = new SelectList(db.Regions, "RegionDescription", "RegionDescription", customer.Region);
return View(customer);
}
//me marr formen me get
[HttpGet]
public ActionResult Edit(string id)
{
dbNorthwindEntities db = new dbNorthwindEntities();
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Customer customer = db.Customers.Find(id);
if (customer == null) { return HttpNotFound(); }
ViewBag.Region = new SelectList(db.Regions, "RegionDescription", "RegionDescription", customer.Region);
return View(customer);
}
//me postu
[HttpPost]
public ActionResult Edit([Bind(Include = "CustomerID,CompanyName,ContactName,Address,City,Region ,PostalCode, Country , Phone , Fax ")]Customer customer)
{
if (ModelState.IsValid)
{
db.Entry(customer).State = EntityState.Modified;
db.SaveChanges();
// return RedirectToAction("Index", new {id = selectedc})
return RedirectToAction("Index");
}
ViewBag.Region = new SelectList(db.Regions, "RegionDescription", "RegionDescription", customer.Region);
return View(customer);
}
// GET: /Employee/Delete/5
public ActionResult Delete(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Customer customer = db.Customers.Find(id);
if (customer == null)
{
return HttpNotFound();
}
return View(customer);
}
/// POST: /Employee/Delete/5
[HttpPost]
public ActionResult Deletee(string id)
{
Customer customer = db.Customers.Find(id);
db.Customers.Remove(customer);
db.SaveChanges();
return RedirectToAction("Index");
}
[HttpGet]
public ActionResult Details(string id)
{
dbNorthwindEntities db = new dbNorthwindEntities();
Customer customer = db.Customers.Single(x => x.CustomerID == id);
return View(customer);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
this is the customer and region classes :
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Northwind
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public partial class Customer
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Customer()
{
this.Orders = new HashSet<Order>();
this.CustomerDemographics = new HashSet<CustomerDemographic>();
}
public string CustomerID { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
public string ContactTitle { get; set; }
public string Address { get; set; }
public string City { get; set; }
// [StringLength(15, MinimumLength = 3, ErrorMessage = "Invalid")]
// [MaxLength(15), MinLength(5)]
public virtual Region Regions { get; set; }
public string Region { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Order> Orders { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<CustomerDemographic> CustomerDemographics { get; set; }
// public string Region { get; set; }
// [NotMapped]
// public List<Region> RegionList { get; set; }
//public Region Regionn { get; set; } // Navigation Property
//[NotMapped]
// public string RegionID { get; set; }
// [NotMapped]
// public List<Region> RegionList { get; set; }
// public int RegionID { get; set; }
}
}
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Northwind
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
public partial class Region
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Region()
{
this.Territories = new HashSet<Territory>();
}
public int RegionID { get; set; }
public string RegionDescription { get; set; }
public Nullable<int> SelectId { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Territory> Territories { get; set; }
// public List<Customer> Customers { get; set; } // Navigation property
}
}
You should probably be using a model for your view.
You can add your Customer, Region list, and SelectedRegionId. Then use something like this:
Html.DropDownListFor(model => model.SelectedRegionId, Model.Regions.Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() })) The problem seems to be that you don't have a variable to store the selected region (SelectedRegionId in my example).

"DRY up" MVC models when using SelectListItem

I have just started MVC and i am able to find examples of most DRY principles online. Although I don't employ all as i find some make code a lot harder to read.
I have found one I cannot find an example of though and I feel like there must be a way to do it.
Basically at the moment I populate model selectlist type objects in the controller, this means I have to reuse the code. I know I could just put this in a method but I was wondering if there anyway to put it in the model so that anytime the model/viewmodel is used this action is called to populate the the selectlist contents.
I have put an example of my code below.
Model
using System;
using System.Data.Entity;
namespace MyWebsite.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
namespace CustomerWebsites.Models
{
public class CustomerWebsites
{
public int Id { get; set; }
public Guid UserGuid { get; set; }
public string WebsiteAddress { get; set; }
public string WebsiteType { get; set; }
public DateTime ReleaseDate { get; set; }
public string Description { get; set; }
public decimal Budget { get; set; }
public DateTime CreationDate { get; set; }
public string DevelopmentStatus { get; set; }
public int CompletedPercentage { get; set; }
public bool Completed { get; set; }
public decimal TotalCost { get; set; }
public decimal TotalPaid { get; set; }
}
public class CustomerWebsitesDBContext : DbContext
{
public CustomerWebsitesDBContext()
: base("DefaultConnection")
{
}
public static CustomerWebsitesDBContext Create()
{
return new CustomerWebsitesDBContext();
}
public DbSet<CustomerWebsites> CustomerWebsites { get; set; }
}
}
}
ViewModel
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace MyWebsite.ViewModels
{
public class CreateCustomerWebsites
{
public int Id { get; set; }
public Guid UserGuid { get; set; }
[Required]
public string WebsiteAddress { get; set; }
public string WebsiteType { get; set; }
public DateTime ReleaseDate { get; set; }
public string Description { get; set; }
public decimal Budget { get; set; }
public DateTime CreationDate { get; set; }
public string DevelopmentStatus { get; set; }
public int CompletedPercentage { get; set; }
public bool Completed { get; set; }
public decimal TotalCost { get; set; }
public decimal TotalPaid { get; set; }
public IEnumerable<SelectListItem> AllUsers { get; set; }
}
}
Controler
// GET: CustomerWebsites/Create
public ActionResult Create()
{
var db = new ApplicationDbContext();
var users = db.Users.ToArray();
var allUsers = users.Select(x => new SelectListItem
{
Value = x.Id,
Text = x.Email
});
var model = new CreateCustomerWebsites
{
AllUsers = allUsers
};
return View(model);
}
// POST: CustomerWebsites/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateCustomerWebsites model)
{
if (ModelState.IsValid)
{
var userGuid = new Guid(User.Identity.GetUserId());
var developmentStatus = "Pending MyWebsite Review";
if (User.IsInRole("Administrator"))
{
userGuid = model.UserGuid;
developmentStatus = model.DevelopmentStatus;
}
db.CustomerWebsites.Add(new CustomerWebsites
{
UserGuid = userGuid,
WebsiteAddress = model.WebsiteAddress,
CreationDate = DateTime.Now,
ReleaseDate = model.ReleaseDate,
Budget = model.Budget ,
Description = model.Description,
DevelopmentStatus = developmentStatus,
CompletedPercentage = model.CompletedPercentage,
Completed = model.Completed,
TotalCost = model.TotalCost,
TotalPaid = model.TotalPaid
});
db.SaveChanges();
return RedirectToAction("Index");
}
var dbUsers = new ApplicationDbContext();
var users = dbUsers.Users.ToArray();
var allUsers = users.Select(x => new SelectListItem
{
Value = x.Id,
Text = x.Email
});
model = new CreateCustomerWebsites
{
AllUsers = allUsers
};
return View(model);
}
View
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>CustomerWebsites</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#if (User.IsInRole("Administrator"))
{
<div class="form-group">
#Html.LabelFor(model => model.UserGuid, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.UserGuid, Model.AllUsers, "-- Select a user --")
#Html.ValidationMessageFor(model => model.UserGuid, "", new { #class = "text-danger" })
</div>
</div>
}
<div class="form-group">
#Html.LabelFor(model => model.WebsiteAddress, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.WebsiteAddress, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.WebsiteAddress, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.WebsiteType, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.WebsiteType, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.WebsiteType, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ReleaseDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ReleaseDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ReleaseDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(model => model.Description, new { rows = "10", #class = "form-control" })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
</div>
#if (User.IsInRole("Administrator"))
{
<div class="form-group">
#Html.LabelFor(model => model.DevelopmentStatus, htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.EditorFor(model => model.DevelopmentStatus, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.DevelopmentStatus, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CompletedPercentage, htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.EditorFor(model => model.CompletedPercentage, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.CompletedPercentage, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Completed, htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.Completed)
#Html.ValidationMessageFor(model => model.Completed, "", new {#class = "text-danger"})
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TotalCost, htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.EditorFor(model => model.TotalCost, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.TotalCost, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TotalPaid, htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.EditorFor(model => model.TotalPaid, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.TotalPaid, "", new {#class = "text-danger"})
</div>
</div>
}
<div class="form-group">
#Html.LabelFor(model => model.Budget, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Budget, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Budget, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
Basically at the moment I populate model selectlist type objects in
the controller, this means I have to reuse the code. I know I could
just put this in a method but I was wondering if there anyway to put
it in the model so that anytime the model/viewmodel is used this
action is called to populate the the selectlist contents.
It is generally not a good idea to put any methods in your viewmodels, especially for data access & population. Viewmodels should be plain data containers, void of knowledge or behavior. You are doing the right thing by populating the SelectList from the controller action.
As far as DRY, it looks pretty DRY to me already. You are only repeating one or two lines of code. You could DRY it up a little more by using something like AutoMapper to do the projection for you:
var users = dbUsers.Users.ToArray();
model = new CreateCustomerWebsites
{
AllUsers = Mapper.Map<IEnumerable<SelectListItem>>(users)
};
...but do do this, you would have to add even more code to define the mapping. You could also like you mentioned in your question move the projection to a private method on the controller, but this would also mean adding more code, and would move some relevant code away from the controller action body. And you're effectively only removing 2 lines of code (one from each action that needs to hydrate the dropdown). Personally, I don't really see a problem with the way you are doing it now.
Another option could be to write an ActionFilterAttribute to populate the SelectList during ResultExecuted. But the point is, don't do it from the ViewModel: do it during the action execution.
This might be OTT for your needs, but I looked at this a while ago and was also trying to address the fact that a db lookup was performed every time the selectlist was populated.
I have a service class that sits between the Controllers and dbcontext, so in your example I would have a class called UserService.cs. The service class handles business logic & keeps the controller methods reasonably 'thin'. In the UserService class you have a method called GetAsSelectList():
public SelectList GetAsSelectList()
{
var b = CacheHelper.GetCacheItem("UserSelectList", UsersDelegate, CacheHelper.SlidingParam, CacheHelper.AbsoluteParam);
return new SelectList((IEnumerable)b, "Id", "Name");
}
This uses a CacheHelper class to check if the selectlist exists in memory. If it does then it returns it, thus saving a database lookup. If not in the cache, it runs the method below to generate the selectlist & store it in the cache with the name 'UserSelectList'.
private object UsersDelegate()
{
return (from c in _context.Set<Users>()
select new
{
c.Id, c.Name
}).ToList();
}
The actual CacheHelper class can be found here
Using this approach has saved me loads of database lookups as I'm populating forms with multiple selectlists containing data that rarely - if ever - changes.

Categories