I have seen lots of examples on this, but cannot get any working. I have built this example to prove/disprove passing back of the view model SomeDataViewModel.
I am trying to post back the dropdownlist data. Everything works ok, but the OtherData property on TestViewModel never returns the collect that was passed in.
Have tried adding:
#Html.HiddenFor(m => Model.OtherData)
but again this just produces the following error;
The parameter conversion from type 'System.String' to type 'SomeDataViewModel' failed because no type converter can convert between these types
The Code:
ViewModels
TestViewmodel
public class TestViewModel
{
public TestViewModel()
{
OtherData = new List<SomeDataViewModel>();
}
public int Id { get; set; }
public String Name { get; set; }
public DateTime DoB { get; set; }
public int SelectedOtherData { get; set; }
public List<SomeDataViewModel> OtherData { get; set; }
public IEnumerable<SelectListItem> TolistData()
{
IEnumerable<SelectListItem> ret = OtherData.Select(i => new SelectListItem() { Text = i.Text, Value=i.Value });
return ret;
}
}
SomeDataViewmodel
public class SomeDataViewModel
{
public string Value { get; set; }
public string Text { get; set; }
}
View
#model TestViewModel
#{
ViewBag.Title = "Home Page";
}
#using (Html.BeginForm("Index","Home"))
{
<div class="row">
<div class="col-md-12">
<br />
#Html.EditorFor(m => Model.Id)
<br />
#Html.EditorFor(m => Model.Name)
<br />
#Html.EditorFor(m => Model.DoB)
<br/>
#Html.DropDownListFor(m => Model.SelectedOtherData, Model.TolistData(), new { id = "OtherData" })
<p><a class="btn btn-default" href="http://go.microsoft.com/fwlink/?LinkId=301865">Learn more ยป</a></p>
</div>
</div>
<button id="dosomething" formmethod="post">Post</button>
}
Controller
public ActionResult Index()
{
var model = new TestViewModel() {
Id = 99,
Name = "Billy",
DoB = DateTime.Now
};
model.OtherData.Add(
new SomeDataViewModel { Text = "Bob", Value = "1" });
model.OtherData.Add(
new SomeDataViewModel { Text = "Sally", Value = "2" });
return View(model);
}
[HttpPost]
public ActionResult Index(TestViewModel retModel)
{
if (ModelState.IsValid)
{
if (retModel.OtherData.Count() == 0)
{
var dud = true;
}
}
return View(retModel);
}
You can't render hidden inputs for complex data with #Html.HiddenFor helper.
You should use it only with simple types. Becouse you got array you should write something like this:
#for(int i = 0; i < Model.OtherData.Count(); i++)
{
#Html.HiddenFor(m => Model.OtherData[i].Text)
#Html.HiddenFor(m => Model.OtherData[i].Value)
//... other fields.
#Html.HiddenFor(m => Model.OtherData[i].OtherProperty)
}
Use for loop instead of foreach becouse you should same your mappings for right binding on form POST.
Certainly there is a type conversion error. your SelectedOtherData is type of int while selectlistitem value is type of string
Related
I am trying to pass a complex data structure from Controller to View and Back to Controller which contains Lists. I can see the list items in View. I want to edit those and send it back to the controller. I am able to edit some properties but for lists, I am getting null value in the controller.
Here is an example (simulation) of what I am trying to achieve:
Consider Model -
using System.Collections.Generic;
namespace WebApplication1.Models
{
public class StudentViewModel
{
public string StudentId { get; set; }
public string FeedBack { get; set; }
public List<ScoreCard> ScoreCards;
}
public class ScoreCard
{
public string Subject { get; set; }
public string Marks { get; set; }
}
}
Controller -
public class StudentController : Controller
{
public ActionResult Index()
{
var model = new StudentViewModel();
model.StudentId = "Some Student";
model.ScoreCards = new List<ScoreCard>
{
new ScoreCard()
{
Marks = "0",
Subject = "English"
},
new ScoreCard()
{
Marks = "0",
Subject = "Maths"
}
};
return View("View", model);
}
public ActionResult SubmitScore(StudentViewModel model)
{
/* Some Code */
}
}
View -
#model WebApplication1.Models.StudentViewModel
#{
ViewBag.Title = "Title";
}
#using (Html.BeginForm("SubmitScore", "Student", FormMethod.Post))
{
#Html.DisplayName(#Model.StudentId)<br />
<label>Comment:</label><br/>
#Html.EditorFor(m => m.FeedBack, new { htmlAttributes = new { #type = "text", id = #Model.FeedBack} })<br />
for (var i = 0; i < #Model.ScoreCards.Count; i++)
{
#Html.DisplayName(#Model.ScoreCards[i].Subject) <br/>
#Html.EditorFor(m => m.ScoreCards[i].Marks, new { htmlAttributes = new { #type = "number", #min = 0, id = #Model.ScoreCards[i].Marks} })<br />
}
<input class="btn btn-primary" type="submit" value="Submit" />
}
When I run the application -
When I click submit, I am able to see model.FeedBack but the list is set to null.
Something similar is achieved in this question & it's answer; I am not sure what exactly I am missing here.
you send no input for the Subject . You'll need a hidden input for that along with any other value you want returned to the controller when the form is posted. Also a simple text box should work for the marks.
#using (Html.BeginForm("SubmitScore", "Student", FormMethod.Post))
{
#Html.DisplayName(#Model.StudentId)<br />
#Html.HiddenFor(m => m.StudentId)
<label>Comment:</label><br/>
#Html.EditorFor(m => m.FeedBack, new { htmlAttributes = new { #type = "text", id = #Model.FeedBack} })<br />
for (var i = 0; i < #Model.ScoreCards.Count; i++) {
#Html.HiddenFor(m => m.ScoreCards[i].Subject)
#Html.DisplayName(#Model.ScoreCards[i].Subject) <br/>
#Html.TextBoxFor(m => m.ScoreCards[i].Marks, new { htmlAttributes = new { #type = "number", #min = 0} })<br />
}
<input class="btn btn-primary" type="submit" value="Submit" />
}
Finally you need to use properties in order for the model binding to work. You currently have ScoreCards as a field so update it to a property.
public class StudentViewModel {
public string StudentId { get; set; }
public string FeedBack { get; set; }
public List<ScoreCard> ScoreCards { get; set; }
}
I have been following a article on Visual Studio Magazine and have found that for some reason I am getting duplicates for Rules in the drop down on my page. Could someone please explain what I am missing here? Also I would like to know how I could fix this issue.
Upon closer inspection I believe the issue lies with the Validators line as it appears to be reading in 4 objects rather than 2 (a Phone validator and an Email validator). The Email validator code is essentially the same as the Phone but using a different regex.
Controller code:
[ImportMany]
public IEnumerable<Lazy<BusinessRules.IValidate<string>, BusinessRules.IValidateMetaData>> Validators { get; private set; }
[HttpGet]
public ActionResult Index()
{
var vm = new ValidationFormModel();
vm.Rules = new List<SelectListItem>(from v in Validators
select new SelectListItem()
{ Text = v.Metadata.Name,
Value = v.Metadata.Name });
return View(vm);
}
View Model code:
public class ValidationFormModel
{
public string Input { get; set; }
public List<SelectListItem> Rules { get; set; }
public string Rule { get; set; }
public string StatusLabel { get; set; }
}
Business Rules Code
[Export(typeof(IValidate<string>))]
[ExportMetadata("Name", "Phone")]
public class ValidatePhone : IValidate<string>
{
const string PHONE_PATTERN = #"^((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}$";
public ValidationResult Validate(string input)
{
var result = new ValidationResult();
if (input == null || !Regex.IsMatch(input, PHONE_PATTERN))
{
result.ErrorMessage = string.Format("{0} is not a valid phone number");
}
else
{
result.IsValid = true;
}
return result;
}
}
The View:
#model ValidationExample.ViewModels.ValidationFormModel
#{
ViewBag.Title = "MEF Demo";
}
#using (Html.BeginForm())
{
<strong>#Html.DisplayFor(m => m.StatusLabel)</strong>
#Html.ValidationSummary(false)
<fieldset>
<legend>Validation Demo</legend>
#Html.LabelFor(m => m.Input)
#Html.TextBoxFor(m => m.Input)
#Html.LabelFor(m => m.Rule)
#Html.DropDownListFor(m => m.Rule, Model.Rules)
</fieldset>
<input type="submit" />
}
From the view, try using IEnumerable
#model IEnumerable<ValidationExample.ViewModels.ValidationFormModel>
and try changing your dropdown list to a normal <select>
<fieldset>
<legend>Validation Demo</legend>
#Html.LabelFor(m => m.Input)
#Html.TextBoxFor(m => m.Input)
#Html.LabelFor(m => m.Rule)
foreach(var item in Model)
{
<select>#item.Rule </select>
}
</fieldset>
I'm trying to make very simple forum, but I have problem with DropDownList. I have two models:
ForumThread.cs
public partial class ForumThread
{
public ForumThread()
{
this.ForumCategory = new HashSet<ForumCategory>();
}
public int TH_ID { get; set; }
public System.DateTime DATE { get; set; }
public string TOPIC { get; set; }
public string USER { get; set; }
public virtual ICollection<ForumCategory> ForumCategory { get; set; }
}
ForumCategory.cs
public partial class ForumCategory
{
public ForumCategory()
{
this.ForumThread = new HashSet<ForumThread>();
}
public int CA_ID { get; set; }
public string CATEGORY { get; set; }
public bool isSelected { get; set; }
public virtual ICollection<ForumThread> ForumThread { get; set; }
}
I tried to make "Create" function with view:
Create
#model AnimeWeb.Models.ForumThread
#{
ViewBag.Title = "Create";
}
<h2>New Thread</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<div class="editor-field">
#Html.HiddenFor(model => model.TH_ID)
</div>
<div class="editor-label">
TOPIC
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TOPIC)
#Html.ValidationMessageFor(model => model.TOPIC)
</div>
<div class="editor-label">
CATEGORY
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ForumCategory)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
And PartialView for ForumCategory:
ForumCategory
#model AnimeWeb.Models.FORUMCATEGORY
#Html.HiddenFor(model => model.CA_ID)
#Html.HiddenFor(model => model.CATEGORY)
<div>
#Html.DropDownListFor(item => Model.CA_ID, ViewBag.CA_ID as SelectList, "-- Select --")
</div>
ForumController
public ActionResult Create()
{
var db = new MainDatabaseEntities();
var viewModel = new ForumThread
{
ForumCategory = db.ForumCategory.Select(c => new { CA_ID = c.CA_ID, CATEGORY = c.CATEGORY, isSelected = false }).ToList().Select(g => new ForumCategory
{
CA_ID = g.CA_ID,
CATEGORY = g.CATEGORY,
isSelected = false
}).ToList(),
};
return View(viewModel);
}
//
// POST: /Forum/Create
[HttpPost]
public ActionResult Create(ForumThread forumthread, String user, int id)
{
var db = new MainDatabaseEntities();
var newthread = new ForumThread
{
TH_ID = forumthread.TH_ID,
DATE = DateTime.Now,
TOPIC = forumthread.TOPIC,
USER = forumthread.USER,
ForumCategory = new List<ForumCategory>()
};
foreach (var selectedCategory in forumthread.FORUMCATEGORY.Where(c => c.isSelected))
{
var category = new ForumCategory { CA_ID = selectedCategory.CA_ID };
db.ForumCategory.Attach(category);
newthread.ForumCategory.Add(category);
}
db.ForumThread.Add(newthread);
db.SaveChanges();
return RedirectToAction("Index");
}
And it obviously doesn't work. I tried to use other threads on this forum but nothing helped. Could someone explain me how to make this work?
The error is in partial view of ForumCategory:
The ViewData item that has the key 'CA_ID' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'.
In your PartialView for ForumCategory, your cast is not correct:
#Html.DropDownListFor(item => Model.CA_ID, ViewBag.CA_ID as SelectList, "-- Select --")
You have to use a SelectList (List of SelectListItem) that you can implement for example in a method in your model:
public List<SelectListItem> GetCategories()
{
var db = new MainDatabaseEntities();
List<SelectListItem> list = new List<SelectListItem>();
// Add empty item if needed
SelectListItem commonItem = new SelectListItem();
commonItem.Text = "--- Select ---";
commonItem.Value = "-1";
commonItem.Selected = true;
list.Add(commonItem);
// Add items from Database
foreach (ForumCategory fc in db.ForumCategory)
{
SelectListItem i = new SelectListItem();
i.Text = fc.CATEGORY;
i.Value = fc.CA_ID.ToString();
list.Add(i);
}
return list;
}
And then you can have you dropdown like that:
#Html.DropDownList("DropName", Model.GetCategories())
There may be other errors in some parts of your code, I just answered to the one you quoted
In your editortemplate, you have:
ViewBag.CA_ID as SelectList
But you don't show where you fill the ViewBag. Instead you might want to do something like this:
#Html.DropDownListFor(m => m.CA_ID,
new SelectList(Model.ForumCategory,
"CA_ID", "CATEGORY", Model.CA_ID))
As also explained in MVC3 DropDownListFor - a simple example?.
When clicking save to submit my form, my HTTPPost Edit Action receives a null value for IEnumerable<MedicalProduct> productList. I am not sure what parameter to use for my edit Action to prevent nulls. I would try and determine the cause with some breakpoints but cannot find the spot before the parameter is assigned null.
Side Note:
I am adapting my code to use this new Model/ViewModel hierarchy. My Controller hasn't been completely tested with these new models, but I started testing the Edit Action, and received the null reference exception when trying to use the parameter IEnumerable<MedicalProduct> productList in my Edit post action.
Another Side Note:
I am using a sub-ViewModel class MedicalProductViewModelLineItem (haven't figured out a better name yet) inside my ViewModel MedicalProductViewModel because I need a way to retrieve all the Brand names from the database with one database call, and then assign them one by one to the MedicalProductViewModelLineItem.
EDIT: CODE UPDATE 10/22/13 5:14pm CST. The values produced in FormCollection.Keys parameter in the HttpPost Edit action method are now fixed. Now, values like "Products[0].Name" or "Products[0].ID" are produced in FormCollection.Keys parameter instead of "p.Name" or "Name". However, the productList parameter is still null.
Model Classes
MedicalProductViewModel
public class MedicalProductViewModel
{
public List<MedicalProductViewModelLineItem> Products { get; private set; }
//public SelectListItem BrandSelectListItem { get; private set; }
public void BuildViewModel(IEnumerable<MedicalProductViewModelLineItem> productsList, IEnumerable<Brand> brandList)
{
BuildProducts(productsList, brandList);
}
public void BuildViewModel(IEnumerable<MedicalProduct> productsList, IEnumerable<Brand> brandList)
{
BuildProducts(productsList, brandList);
}
private IEnumerable<SelectListItem> BuildSelectListItems(IEnumerable<Brand> brandList)
{
return brandList.Select(b => new SelectListItem()
{
Text = b.Name,
Value = b.ID.ToString()
});
}
private void BuildProducts(IEnumerable<MedicalProductViewModelLineItem> productList, IEnumerable<Brand> brandList)
{
var medicalProducts = productList.Select(p => new MedicalProduct()
{
BrandID = p.BrandID,
ID = p.ID,
Name = p.Name,
Price = p.Price
});
BuildProducts(medicalProducts, brandList);
}
private void BuildProducts(IEnumerable<MedicalProduct> productsList, IEnumerable<Brand> brandList)
{
Products = productsList.Select(p => new MedicalProductViewModelLineItem()
{
BrandID = p.BrandID,
BrandName = brandList.Single(b => b.ID == p.BrandID).Name,
BrandSelectListItem = BuildSelectListItems(brandList),
ID = p.ID,
Name = p.Name,
Price = p.Price
}).ToList();
}
}
MedicalProductViewModelLineItem
// Sub-ViewModel of MedicalProductViewModel
// It gets displayed as one row on a view.
public class MedicalProductViewModelLineItem
{
[Key]
public int ID { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[DataType(DataType.Currency)]
public double Price { get; set; }
// is a foreign key
public int BrandID { get; set; }
public string BrandName { get; set; }
}
MedicalProduct
// DOMAIN MODEL
public class MedicalProduct
{
[Key]
public int ID { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[DataType(DataType.Currency)]
public double Price { get; set; }
// is a foreign key
public int BrandID { get; set; }
}
Controller
MedicalProductController
public class MedicalProductController : Controller
{
private MvcMedicalStoreDb _db = new MvcMedicalStoreDb()
//
// GET: /MedicalSupply/Edit/5
public ActionResult Edit(int id = 0)
{
MedicalProduct product = _db.Products.Find(id);
if (product == null)
{
return HttpNotFound();
}
var productList = new List<MedicalProduct> { product };
var viewModel = GetMedicalProductViewModel(productList);
return View(viewModel);
}
// ==========================================
// NULL REFERENCE EXCEPTION OCCURS IN THIS ACTION
// ==========================================
// POST: /MedicalSupply/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(IEnumerable<MedicalProductViewModelLineItem> productList, FormCollection values)
{
if (ModelState.IsValid)
{
foreach (var product in productList)
_db.Entry(product).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
var productViewModelList = GetMedicalProductViewModel(productList);
return View(productViewModelList);
}
protected override void Dispose(bool disposing)
{
_db.Dispose();
base.Dispose(disposing);
}
}
Views
Edit.cshtml
#model MvcMedicalStore.Models.MedicalProductViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>MedicalProduct</legend>
#for (int i = 0; i < Model.Products.Count(); i++)
{
#Html.EditorFor(m => m.Products[i])
}
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
EditorTemplates\MedicalProductViewModelLineItem.cshtml
#model MvcMedicalStore.Models.MedicalProductViewModelLineItem
#Html.HiddenFor(item => Model.ID)
<div class="editor-label">
#Html.LabelFor(item => Model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(item => Model.Name)
#Html.ValidationMessageFor(item => Model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(item => Model.Price)
</div>
<div class="editor-field">
#Html.EditorFor(item => Model.Price)
#Html.ValidationMessageFor(item => Model.Price)
</div>
<div class="editor-label">
#Html.LabelFor(item => Model.BrandID)
</div>
<div class="editor-field">
#Html.DropDownListFor(item => Model.BrandID, Model.BrandSelectListItem)
#Html.ValidationMessageFor(item => Model.BrandID)
</div>
EDIT: (Pictures obsolete)
two images of the foreach approach, and for approach used in MedicalProductViewModel.cshtml, and the resulting key values of FormsCollection parameter values
Use a BindAttribute with Prefix in your Controller Action like below:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Prefix = "Products")] IEnumerable<MedicalProductViewModelLineItem> productList)
{
if (ModelState.IsValid)
{
foreach (var product in productList)
_db.Entry(product).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
var productViewModelList = GetMedicalProductViewModel(productList);
return View(productViewModelList);
}
Change your view from foreach loop to for loop
#foreach (MvcMedicalStore.Models.MedicalProductViewModelLineItem p in Model.Products)
{
#Html.HiddenFor(item => p.ID)
//rest of the code.
}
to
#for ( i = 0; i < Model.count(); i++)
{
#Html.LabelFor(m => m[i].Name)
#Html.HiddenFor(m => m[i].Name)
#Html.LabelFor(m => m[i].Price)
#Html.EditorFor(m => m[i].Price)
//rest of the code.
}
[HttpPost]
public MedicalProductViewModel GetMedicalProductViewModel(ICollection<MedicalProduct> productList)
{
var brandList = _db.Brands.ToArray();
var mapper = new MedicalProductMapper();
return mapper.MapMedicalProductViewModel(productList, brandList);
}
Make it more explicit, specify
FormMethod.Post
#using (Html.BeginForm()) { } to
#using (Html.BeginForm("Action", "Controller", FormMethod.Post, new { id = "forId" }))
{}
I am trying to put a list of medical product brand names in a dropdown list on my edit.cshtml file using Html.DropDownListFor(). I am trying to use the Html helper properly but my efforts have been unsuccessful. Model.BrandSelectListItem is an IEnumerable that is supposed to go into the DropDownList.
Also, I don't understand why I need to reference the model as 'model' in the lambda expression, but as 'Model' in the second argument of the following code segment:
#Html.DropDownListFor(model => model.BrandName, Model.BrandSelectListItem)
when executing the code, I receive the following run-time error:
The ViewData item that has the key 'BrandName' is of type
'System.String' but must be of type 'IEnumerable'.
Here are some classes that may be relevant to this error:
MedicalProduct
public class MedicalProduct
{
[Key]
public int ID { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[DataType(DataType.Currency)]
public double Price { get; set; }
// is a foreign key
public Nullable<int> BrandID { get; set; }
}
MedicalProductViewModel
public class MedicalProductViewModel
{
[Key]
public int ID { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[DataType(DataType.Currency)]
public double Price { get; set; }
public Nullable<int> BrandID { get; set; }
[DisplayFormat(NullDisplayText="[Generic]")]
public string BrandName { get; set; }
public IEnumerable<SelectListItem> BrandSelectListItem { get; set; }
}
MedicalProductController
public class MedicalProductController : Controller
{
private MvcMedicalStoreDb _db = new MvcMedicalStoreDb();
//
// GET: /MedicalSupply/Edit/5
public ActionResult Edit(int id = 0)
{
MedicalProduct medicalProduct = _db.Products.Find(id);
if (medicalProduct == null)
{
return HttpNotFound();
}
var viewModel = GetMedicalProductViewModel(medicalProduct);
return View(viewModel);
}
public MedicalProductViewModel GetMedicalProductViewModel(MedicalProduct product)
{
var mapper = new MedicalProductMapper(_db);
return mapper.GetMedicalProductViewModel(product);
}
}
MedicalProductMapper
public class MedicalProductMapper
{
private MvcMedicalStoreDb _db;
public MedicalProductMapper(MvcMedicalStoreDb db)
{
_db = db;
}
public MedicalProductViewModel GetMedicalProductViewModel(MedicalProduct source)
{
MedicalProductViewModel viewModel = new MedicalProductViewModel();
var dbBrands = _db.Brands.ToArray();
viewModel.ID = source.ID;
viewModel.Name = source.Name;
viewModel.Price = source.Price;
viewModel.BrandID = source.BrandID;
if (viewModel.BrandID != null)
viewModel.BrandName = dbBrands.SingleOrDefault(b => b.ID == source.BrandID).Name;
var queryBrands = from b in dbBrands
select b;
// BrandSelectListItem is 'null' before this assignment statement executes.
// and Stays null after the statement executes, why?
viewModel.BrandSelectListItem = queryBrands as IEnumerable<SelectListItem>;
return viewModel;
}
}
Edit.cshtml
#model MvcMedicalStore.Models.MedicalProductViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>MedicalProduct</legend>
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Price)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Price)
#Html.ValidationMessageFor(model => model.Price)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.BrandName)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.BrandName, Model.BrandSelectListItem)
#Html.ValidationMessageFor(model => model.BrandName)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Also, I don't understand why I need to reference the model as 'model'
in the lambda expression, but as 'Model' in the second argument of the
following code segment:
You don't need to reference it as model in the lambda expression. The first part of the lambda (before the => symbol) you are just specifying your parameters and you can name them whatever you want
anything => anything.BrandName
would work the same as using model in place of anything
The lambda expression in this case you can think of it as a method that looks like this
TProperty GetPropertyYouWantToCreateADropdownFor(MedicalPropertyViewModel model)
{
return model.BrandName
}
As for the dropdown, here is a good post explaining how to create a dropdown
How to write a simple Html.DropDownListFor()?
Edit
I plugged in your all your code except your mapper, and just made a little fake implementation of your ViewModel. Your code worked fine.
Here's what I used for my fake controller
var viewModel = new MedicalProductViewModel
{
BrandID = 12,
BrandName = "Some Brand",
ID = 6,
Name = "Some Name",
Price = 12.27,
BrandSelectListItem = new List<SelectListItem>()
{
new SelectListItem() {Text = "Item 1", Value = "1"},
new SelectListItem() {Text = "Item 2", Value = "2"}
}
};
return View(viewModel);
So seeing that this worked, the only thing I can guess is that your problem lies in your Mapper, can you give an example of what viewModel.BrandSelectListItem equals after you get data from the database? Does throwing in fake data work for you?
Edit 2:
queryBrands has to be compatible with SelectListItem if your going to cast it into an IEnumerable<SelectListItem>
You can modify your existing
var queryBrands = from b in dbBrands
select b;
to something like
var queryBrands = dbBrands.Select(b => new SelectListItem()
{
Text = b.PropertyWithWhatYouWantToDisplay,
Value = b.PropertyYouWantAsTheValue,
Selected = //true if you want this item selected, false otherwise
});