Value from DropDownListFor is not saving value to Database - asp.net-mvc

Here is my view
<div class="form-group">
#Html.LabelFor(model => model.SubCatagory, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SubCatagory, new SelectList(ViewBag.SubCategories, "Id", "Name", "Category"))
#Html.ValidationMessageFor(model => model.SubCatagory, "", new { #class = "text-danger" })
</div>
</div>
And here is the method where I'm saving data.
dbContext.Products.Add(product);
dbContext.SaveChanges();
It is saving all the values to database except SubCatagoryId..
Can anyone please help me ?

The SubCatagory property contains null value because it's a complex object property bound for SubCatagory class, which DropDownListFor returns single selected value instead of entire class properties. You should do one of these:
Option A: Create selected value property
Create an int property which will hold selected value from DropDownListFor on Product class, and then you can assign SubCatagory property inside controller by querying from database based from passed value in newly created property.
Model
public class Product
{
[Key]
public int Id { get; set; }
[Display(Name = "Sub Catagory")]
public int SelectedSubCatagory { get; set; }
// other properties
}
View
<div class="form-group">
#Html.LabelFor(model => model.SelectedSubCatagory, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedSubCatagory, new SelectList(ViewBag.SubCategories, "Id", "Name", "Category"))
#Html.ValidationMessageFor(model => model.SelectedSubCatagory, "", new { #class = "text-danger" })
</div>
</div>
Option B: Use existing child property of SubCatagory class
Suppose you have ID property declared inside SubCatagory class like this:
public class SubCatagory
{
public int Id { get; set; }
public string Name { get; set; }
// other properties
}
You may use it to bind on DropDownListFor helper as in example below:
View
<div class="form-group">
#Html.LabelFor(model => model.SubCatagory.Id, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SubCatagory.Id, new SelectList(ViewBag.SubCategories, "Id", "Name", "Category"))
#Html.ValidationMessageFor(model => model.SubCatagory.Id, "", new { #class = "text-danger" })
</div>
</div>
Note that if you take this option, make sure that SubCatagory property is already instantiated (with new keyword) in Product class to avoid NullReferenceException when using its child properties.
Reference:
How to simple Html.DropDownListFor MVC.NET (Nested Viewmodels)

Related

DropDown Population Error in ASP.NET MVC 5

I have the following in my controller:
public ActionResult Create()
{
ViewBag.PlayerId = new SelectList(db.Players, "Id", "Name");
return View();
}
This is in the view:
<div class="form-group">
#Html.LabelFor(model => model.PlayerId, "PlayerId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("PlayerId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.PlayerId, "", new { #class = "text-danger" })
</div>
</div>
But when I submit the form, it gives me the below error:
System.InvalidOperationException: 'The ViewData item that has the key 'PlayerId' is of type 'System.Int32' but must be of type 'IEnumerable'.'
I googled a lot but were not able to find the solution. Your help is highly appreciated.
Write your #Html.DropDownList as follows:
#Html.DropDownList("PlayerId", ViewBag.PlayerId as SelectList,"Select Player", htmlAttributes: new { #class = "form-control" })
Now it will work!
You have to pass the SelectList into dropdown but actually the model binder is confused between PlayerId as viewmodel property and PlayerId as ViewBag property, hence causing the error.
Better to create a viewmodel property which will store option list with different name:
public class ViewModel
{
public int PlayerId { get; set; }
// other properties
// option list here
public List<SelectListItem> PlayerList { get; set; }
}
Then add the option lists from database into controller action:
public ActionResult Create()
{
var model = new ViewModel();
model.PlayerList = db.Players.Select(x => new SelectListItem { Text = x.Name, Value = x.Id }).ToList();
return View(model);
}
And use strongly-typed helper to bind it afterwards:
#Html.DropDownListFor(model => model.PlayerId, Model.PlayerList, "Select", new { #class = "form-control" })
Related issue:
The ViewData item that has the key is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'

ASP.NET MVC Foreign Key using Entity Framework Multiple Models in View

Noob here.
I'm struggling wrapping my head around a few things. It used to be pretty straightforward to grab some data from a web form and throw it in a database.
I have a view for patient that gathers information when registering the patient. The information lives across multiple tables.
To facilitate this, I've created the following in my patient model:
public class Patient
{
//properties
public virtual PatientCondition patientcondition { get; set; }
public virtual PatientInsurrance patientinsurance { get; set; }
}
This allows me to add fields to my view for each of those models.
My view contains fields from both patient and patientinsurrance:
<div class="form-group">
#Html.LabelFor(model => model.patientinsurance.InsuranceCompany, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.patientinsurance.InsuranceCompany, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.patientinsurance.InsuranceCompany, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.EmergencyContactPhoneNumber, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.EmergencyContactPhoneNumber, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.EmergencyContactPhoneNumber, "", new { #class = "text-danger" })
</div>
</div>
When I try to save the patient record, I am getting the following error:
Violation of PRIMARY KEY constraint 'PK_dbo.PatientInsurrances'. Cannot insert duplicate key in object 'dbo.PatientInsurrances'. The duplicate key value is (0).\r\nThe statement has been terminated.
Here is my controller:
public ActionResult Create(Patient patient)
{
if (ModelState.IsValid)
{
db.Patients.Add(patient);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(patient);
}
It is attempting to create a patientinsurancerecord, but it can't because we do not yet know the patientId because we are creating the patient record at this time. Furthermore, patientinsurance is not required and it is possible to create a patient without this patientinsurance.
So the question is, how do I add fields to a view that collect data to be stored in multiple tables?
How do I create foreign key relationships that do not require data for the related table?

Access public virtual dropdown value

I have a dropdown list and a datefield. If there is one specific value selected from the dropdown, the datefield should be required.
To solve that, I tried to use the requiredIf sttribute from the FoolProof library.
But I don't know how to access the selected value in the Model.
Model
//This is the datefield
[RequiredIf(tabState == "discarded")]
[DataType(DataType.Date)]
[Display(Name = "date discarded")]
public Nullable<System.DateTime> datDiscarded { get; set; }
//This is the dropdown
public virtual tabState tabState { get; set; }
tabState in Controller
ViewBag.intIdeaStateID = new SelectList(db.tabState, "intStateID", "strState");
dropdown in View
<div class="form-group">
#Html.LabelFor(model => model.intIdeaStateID, "State", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("intIdeaStateID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.intIdeaStateID, "", new { #class = "text-danger" })
</div>
</div>
How can I check if the selected value from the dropdown is "discarded"?
Thanks for your help.

Dropdownlist in MVC with Where cluase in entities

I am new to MVC. I want to fill Dropdownlist only where Account_Type = "D".
Here is my Edit.cshtml
<div class="form-group">
#Html.LabelFor(model => model.Account_Code, "Account_Code", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("Account_Code", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Account_Code, "", new { #class = "text-danger" })
</div>
</div>
And here is my Edit Controller
public ActionResult Edit(int? id)
{
ViewBag.Account_Code = new SelectList(db.Chart_Of_Account, "Account_Code", "Account_Desc", student.Account_Code);
}
Use a .Where() clause to filter your data
public ActionResult Edit(int? id)
{
var accountCodes = db.Chart_Of_Account.Where(a => a.Account_Type == "D");
ViewBag.AccountCodeList = new SelectList(accountCodes , "Account_Code", "Account_Desc");
}
Note I have changed the name of the ViewBag property and removed the 3rd parameter of the SelectList contructor (its ignored when binding to a property)
Your view should be
#Html.DropDownListFor(m => m.Account_Code, (SelectList)ViewBag.AccountCodeList)

ASP.NET MVC 5 Scaffolding not creating elements for enum property

This is probably a newbie question, as I'm quite new to ASP.NET MVC 5. When I tell Visual Studio to add a View based on my ViewModel class, it completely skips properties defined like public EnumName? PropertyName { get; set; } and does not create any #Html.EditorFor calls for it.
However, if I manually add the call #Html.EditorFor(model => model.PropertyName, new { htmlAttributes = new { #class = "form-control" } }) I get exactly what I expect -- a dropdown which is empty by default. Should scaffolding not do this by itself?
My understanding is that this is supposed to be supported in the current version of ASP.NET MVC. Am I wrong about that, or am I missing something? Help or advice is greatly appreciated.
Thanks in advance!
These are the ASP.NET products installed:
ASP.NET and Web Tools 12.4.51016.0
ASP.NET Web Frameworks and Tools 2012.2 4.1.21001.0
ASP.NET Web Frameworks and Tools 2013 5.2.21010.0
Edit for sample code:
Here is a small section of the view model. There are 170 different properties, almost all of them nullable-Enum type.
public partial class MedicalHistoryViewModel
{
public YesNo? Cancer { get; set; }
public MedicalHistoryDiagnosed? CancerDiagnosed { get; set; }
public YesNoUnsure? CancerIndustrialInOrigin { get; set; }
public YesNo? Diabetes { get; set; }
public MedicalHistoryDiagnosed? DiabetesDiagnosed { get; set; }
public YesNoUnsure? DiabetesIndustrialInOrigin { get; set; }
public YesNo? HeartDisease { get; set; }
//...
[Display(Name = #"Do you attribute the sleep disturbance to pain, anxiety and/or depression, or to other factors?")]
[DataType(DataType.MultilineText)]
public string SleepDisturbanceAttributedToComments { get; set; }
[Display(Name = #"Other (please specify)")]
[DataType(DataType.MultilineText)]
public string ParentsGrandparentsMedicalHistoryComments { get; set; }
}
Here is the complete output I get from Scaffolding. As you can see, it has completely ignored all enum properties.
#model QmeSurveyApp.ViewModels.MedicalHistoryViewModel
#{
ViewBag.Title = "EditMedicalHistory"; }
<h2>EditMedicalHistory</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>MedicalHistoryViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.SleepDisturbanceAttributedToComments, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SleepDisturbanceAttributedToComments, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SleepDisturbanceAttributedToComments, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SiblingsCousinsMedicalHistoryComments, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SiblingsCousinsMedicalHistoryComments, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SiblingsCousinsMedicalHistoryComments, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ParentsGrandparentsMedicalHistoryComments, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ParentsGrandparentsMedicalHistoryComments, new { htmlAttributes
= new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ParentsGrandparentsMedicalHistoryComments, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div> }
<div>
#Html.ActionLink("Back to List", "Index") </div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval") }
But, if I add this block manually, I get exactly what I want: a drop-down which is empty by default, with my full pick list as the choices.
<div class="form-group">
#Html.LabelFor(model => model.Cancer, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Cancer, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Cancer, "", new { #class = "text-danger" })
</div>
</div>
You don't mention it, but I'm guessing you're not using Entity Framework.
I had a similar situation in an MVC project I was working in without EF. I had a POCO with a property that was an enum, and it was being completely skipped by the scaffolding engine. I even tried overriding the T4 templates with my own CodeTemplates and that's when I noticed the ModelMetadata.Properties collection didn't even contain my enum property.
I finally got it to work just by adding an empty Code First Entity Data model to the project. Doing that adds the Data context class textbox to the Add View scaffold item, and the resulting scaffolded view now includes my enum properties. This seems like a bug to me.

Resources