dropdownlistfor selected value with viewdata - asp.net-mvc

I am not able to bind the selected value in MVC. Can someone tell me what is wrong with the following code:
#Html.DropDownListFor(x => Model.Members[i].OccupationCd,
(IEnumerable<SelectListItem>)ViewData["ddl_occupation"],
new { #style = "width:100px", #class = "Occupation required" })
public List<SelectListItem> GetOccupation(string selectedValue)
{
List<SelectListItem> selLstOccupation = new List<SelectListItem>();
selLstOccupation.Add(new SelectListItem { Value = "", Text = "---" + ("Select Occupation") + "---" });
selLstOccupation.AddRange(GetData.AllOccupation());
selLstOccupation = GetData.GetSelectedList(selLstOccupation, selectedValue);
return selLstOccupation;
}
public class Member()
{
//code
//code
public int educationCd { get; set; }
}
I found the Solution:
#Html.DropDownListFor(x => Model.Members[i].OccupationCd,new SelectList((IEnumerable<SelectListItem>)ViewData["ddl_occupation"],"Value","Text",Model.Members[i].OccupationCd))

You have to do two things to fix your problem. The first one is to change the GetOccupation method with the following implementation
public List<Occupation> GetOccupation()
{
return GetData.AllOccupation();
}
Then you have to change the dropdown initialization to the following
#Html.DropDownListFor(x => x.Members[i].OccupationCd,
new SelectList(
(IEnumerable<Occupation>)ViewData["ddl_occupation"],
"OccupationCd",
"##HERE YOU ADD THE PROPERTY YOU WANT TO VISUALIZE##",
Model.Members[i].OccupationCd),
"---Select Occupation--",
new { #style = "width:100px", #class = "Occupation required" })
This should fix your problem.

Related

MVC Razor Is there a way to populate a DropdownListFor by generating SelectListItems from a List<string> ViewModel

I am trying to populate a DropDownListFor in my view with SelectListItems generated by a foreach loop iterating through a List of strings in my ViewModel.
Here are attributes I am using in my ViewModel:
public string Selected {get; set;}
public List<string> Strings {get; set;}
Here is my view syntax:
#Html.DropdownListFor(
model => model.Selected,
new List<SelectListItem>
{
foreach(var answer in Model.Strings)
{
new SelectListItem
{
Value = answer, Text = answer
};
}
},
new { htmlAttributes = new { #class = "form-control" } })
Visual studio throws an error under "foreach" that reads:
} expected
) expected
; expected
and another error under the very last ) that reads:
new{
; expected
} expected
I am not sure what I am doing wrong or how to remove these errors. Any advice will be greatly appreciated. Thank you.
List<SelectListItem> item = Model.Strings.ConvertAll(answer =>
{
return new SelectListItem()
{
Text = answer.ToString(),
Value = answer.ToString()
};
});
#Html.DropDownListFor(model => model.Selected, item, new { htmlAttributes = new { #class = "form-control" } })

There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'DiseaseType'

I want to bind data to dropdownlist, select one and save it into database.
I've successfully binded data to dropdownlist but it is giving an error
There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'DiseaseType'.
on click of save button.
Edit.cshtml code:
<div class="form-group">
#Html.LabelFor(model => model.DiseaseType, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.DiseaseType, ViewData["Diseases"] as SelectList, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.DiseaseType, "", new { #class = "text-danger" })
</div>
</div>
PatientController.cs code:
public ActionResult Edit(int id)
{
List<string> disease = new List<string>();
disease.Add("Select");
disease.Add("Cancer");
disease.Add("Heart");
SelectList Diseases = new SelectList(disease);
ViewBag.Diseases = Diseases;
PatientDBHandle pdb = new PatientDBHandle();
return View(pdb.GetPatient().Find(p => p.ID == id));
}
Patient.cs class:
[Required(ErrorMessage="Please select Disease Type.")]
public string DiseaseType { get; set; }
PatientDBHandle.cs code:
public bool UpdatePatient(Patient patient)
{
connection();
SqlCommand cmd = new SqlCommand("UpdatePatientDetails", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#ID", patient.ID);
cmd.Parameters.AddWithValue("#DiseaseType", patient.DiseaseType);
con.Open();
int i = cmd.ExecuteNonQuery();
con.Close();
if(i >= 1)
{
return true;
}
else
{
return false;
}
}
I've created one table Patient
CREATE TABLE [dbo].[Patient] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[DiseaseType] VARCHAR (20) NULL,
PRIMARY KEY CLUSTERED ([ID] ASC)
);
I'm new to mvc, please help.
Instead of using a List<string> and SelectList in your controller, use a List<SelectListItem> instead and load that into your ViewBag:
List<SelectListItem> disease = new List<SelectListItem>();
disease.Add(new SelectListItem { Value = "Select", Text = "Select" });
disease.Add(new SelectListItem { Value = "Cancer", Text = "Cancer" });
disease.Add(new SelectListItem { Value = "Heart", Text = "Heart" });
ViewBag.Diseases = disease;
In your View (Edit.cshtml) use your ViewBag for the dropdown like so:
#Html.DropDownList("DiseaseType", (IEnumerable<SelectListItem>)ViewBag.Diseases, new { htmlAttributes = new { #class = "form-control" } })
Here I have put "DiseaseType" in instead of your model, but only to demonstrate that when you then post your choice, in order to get that value passed back into your controller, take a string called DiseaseType (use your model instead):
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult TestStack(string DiseaseType)
{
string result = DiseaseType;
return RedirectToAction("Index");
}

MVC 5: Table edits appear to be an all-or-nothing proposition -- why?

I am using boilerplate CRUD methods, which include BIND operations on the methods that catch the form submissions. I have discovered that if I have my fields as nullable both in the model as well as in the DB, and I do not include those fields in a CRUD operation (also no presence in BIND), these fields end up null when before they were filled. If I flag these fields as not nullable in the DB, I cannot complete the CRUD operation without including these fields in hidden form fields because they are not nullable.
How do I make a CRUD operation ignore these fields without adding them as hidden fields in the forms?? As in, do not null them, do not change their data.
For example, if I have my POST method as such:
public async Task<ActionResult> Edit([Bind(Include = "CompanyId,CompanyName,CompanyAddress,CompanyCity")] Company company) {
And there is a field both in the model as well as in the DB such as CompanyCity, if it is nullable in model and db it gets nulled with the update. If it is not nullable in the model and db, the update fails because the field is not nullable but the update wants to null it because it didn't exist in the bind.
I am also using only the base models, such as Company, for this example. However when I try to make another base model, such as EditCompanyViewModel, I am unable to pull data out of the database to put into that view model. The entire await command gets flagged as being not of the correct model/type.
Essentially, I need to know how to edit only part of a table, without messing/mucking/deleting the rest of the table entries and without creating a metric arseload of hidden form fields that exist purely to hold the data I don't want to edit.
I have a conceptual gap here, and I am metaphorically chasing my tail. I can't seem to bridge the gap to a solution.
EDIT:
My modified view model:
public class EditMarketingViewModel {
[Key]
public Guid CompanyId { get; set; }
[DisplayName("How did you hear of us")]
public Guid? HowHeardId { get; set; }
[DisplayName("eNewsletter")]
public bool eNewsletter { get; set; }
[DisplayName("Event Code")]
public Guid? EventCodeId { get; set; }
[DisplayName("Notes")]
public string MarketingNotes { get; set; }
#region Essentials
[HiddenInput, Timestamp, ConcurrencyCheck]
public byte[] RowVersion { get; set; }
[HiddenInput]
public DateTime Modified { get; set; }
[HiddenInput]
public string TouchedBy { get; set; }
#endregion
}
My view:
#model CCS.Models.EditMarketingViewModel
#{
ViewBag.Title = "Edit Marketing Info.";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>#ViewBag.Title</h2>
#using(Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<fieldset>
#Html.HiddenFor(model => model.CompanyId)
#Html.HiddenFor(model => model.RowVersion)
#Html.LabelFor(model => model.HowHeardId, htmlAttributes: new { #class = "control-label" })#Html.DropDownList("HowHeardId", null, " « ‹ Select a How Heard Type › » ", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.HowHeardId, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.eNewsletter, htmlAttributes: new { #class = "control-label" })#Html.EditorFor(model => model.eNewsletter, new { htmlAttributes = new { #data_on_text = "Yes", #data_off_text = "No" } })
#Html.ValidationMessageFor(model => model.eNewsletter, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.EventCodeId, htmlAttributes: new { #class = "control-label" })#Html.DropDownList("EventCodeId", null, " « ‹ Select an Event Code › » ", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.EventCodeId, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.MarketingNotes, htmlAttributes: new { #class = "control-label" })#Html.EditorFor(model => model.MarketingNotes, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.MarketingNotes, "", new { #class = "text-danger" })
<input type="submit" value="Save" class="btn btn-default" />
</fieldset>
}
<p>[ #Html.ActionLink("Back to List", "Index", "Company") ]</p>
Now how do I modify my controller to work with it:
// GET: Company/EditMarketing
public async Task<ActionResult> EditMarketing() {
var id = new Guid(User.GetClaimValue("CWD-Company"));
Company company = await db.Company.FindAsync(id);
if(company == null) {
return HttpNotFound();
}
ViewBag.HowHeardId = new SelectList(db.HowHeard.Where(x => x.Active == true).OrderBy(x => x.SortOrder), "HowHeardId", "HowHeardType", company.HowHeardId);
ViewBag.EventCodeId = new SelectList(db.EventCode.Where(x => x.Active == true).OrderBy(x => x.EventCodeDate), "EventCodeId", "EventCodeName", company.EventCodeId);
return View(company);
}
EDIT 2:
My POST:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EditMarketing([Bind(Include = "CompanyId,HowHeardId,eNewsletter,EventCodeId,MarketingNotes,RowVersion")] Company company) {
try {
if(ModelState.IsValid) {
TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
company.Modified = DateTime.UtcNow;
company.TouchedBy = User.Identity.GetFullNameLF();
db.Entry(company).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index", "Company");
}
} catch(DbUpdateConcurrencyException ex) {
var entry = ex.Entries.Single();
var companyValues = (Company)entry.Entity;
var databaseValues = (Company)entry.GetDatabaseValues().ToObject();
if(databaseValues.MarketingNotes != companyValues.MarketingNotes) { ModelState.AddModelError("MarketingNotes", "Current Value: " + databaseValues.MarketingNotes); }
if(databaseValues.eNewsletter != companyValues.eNewsletter) { ModelState.AddModelError("eNewsletter", "Current Value: " + databaseValues.eNewsletter); }
if(databaseValues.HowHeardId != companyValues.HowHeardId) { ModelState.AddModelError("HowHeardId", "Current Value: " + db.HowHeard.Find(databaseValues.HowHeardId).HowHeardType); }
if(databaseValues.EventCodeId != companyValues.EventCodeId) { ModelState.AddModelError("EventCodeId", "Current Value: " + db.EventCode.Find(databaseValues.EventCodeId).EventCodeName); }
ModelState.AddModelError(string.Empty, "The record you attempted to edit "
+ "was modified by another user after you got the original value. The "
+ "edit operation was canceled and the current values in the database "
+ "have been displayed. If you still want to edit this record, click "
+ "the Save button again. Otherwise click the Back to List hyperlink.");
company.RowVersion = databaseValues.RowVersion;
} catch(DataException dex) {
ModelState.AddModelError(string.Empty, "Unable to save changes. Try again, and if the problem persists please inform your Manager, who will inform the developers." + dex);
}
ViewBag.HowHeardId = new SelectList(db.HowHeard.Where(x => x.Active == true).OrderBy(x => x.SortOrder), "HowHeardId", "HowHeardType", company.HowHeardId);
ViewBag.EventCodeId = new SelectList(db.EventCode.Where(x => x.Active == true).OrderBy(x => x.EventCodeDate), "EventCodeId", "EventCodeName", company.EventCodeId);
return View(company);
}
Please note that I am making use of concurrency to avoid data collisions. Hence the RowVersion column.
As I understand your code EditMarketingViewModel is used to update a company record. Pass your view model as parameter to your post action result. You would want to load the company record first before updating it like so. This approach makes your record retain property values which are not needed to be updated.
[HttpPost]
public async Task<ActionResult> Edit(EditMarketingViewModel viewModel)
{
if (!ModelState.IsValid)
{
ViewBag.HowHeardId = new SelectList(db.HowHeard.Where(x => x.Active == true).OrderBy(x => x.SortOrder), "HowHeardId", "HowHeardType", company.HowHeardId);
ViewBag.EventCodeId = new SelectList(db.EventCode.Where(x => x.Active == true).OrderBy(x => x.EventCodeDate), "EventCodeId", "EventCodeName", company.EventCodeId);
return View(viewModel);
}
Company company = await db.Company.FindAsync(viewModel.CompanyId);
if(company == null) {
return HttpNotFound();
}
company.HowHeardId = viewModel.HowHeardId;
company.eNewsletter = viewModel.eNewsletter;
// etc.
// don't need to assign a new value to properties that should be retained
db.Entry(company).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
Update:
You are returning an object of type Company from your GET controller but your view is expecting an EditMarketingViewModel. So do it like this:
// GET: Company/EditMarketing
public async Task<ActionResult> EditMarketing() {
var id = new Guid(User.GetClaimValue("CWD-Company"));
Company company = await db.Company.FindAsync(id);
if(company == null) {
return HttpNotFound();
}
ViewBag.HowHeardId = new SelectList(db.HowHeard.Where(x => x.Active == true).OrderBy(x => x.SortOrder), "HowHeardId", "HowHeardType", company.HowHeardId);
ViewBag.EventCodeId = new SelectList(db.EventCode.Where(x => x.Active == true).OrderBy(x => x.EventCodeDate), "EventCodeId", "EventCodeName", company.EventCodeId);
EditMarketingViewModel viewModel = new EditMarketingViewModel()
{
CompanyId = company.Id,
// Other view model properties go here
}
return View(viewModel);
}
Make sure the object type you are returning from the controller to the view matches.

MVC5 DropDownListFor not selecting correct value

I realize there are tons of questions on SO about this particular issue, however none of the answers that I've already found are doing quite what I am doing.
View Model
public FreightDiscountViewModel()
{
Sign = new List<SelectListItem>();
States = new List<SelectListItem>();
FreightDiscounts = new List<FreightDiscountModel>();
PopSign();
PopStates();
}
public List<FreightDiscountModel> FreightDiscounts { get; set; }
public List<SelectListItem> States { get; set; }
public List<SelectListItem> Sign { get; set; }
private void PopSign ()
{
Sign.Add(new SelectListItem { Text = "-", Value = "-" });
Sign.Add(new SelectListItem { Text = "+", Value = "+" });
}
private void PopStates ()
{
States.Add(new SelectListItem { Value = "AL", Text = "Alabama" });
States.Add(new SelectListItem { Value = "AK", Text = "Alaska" });
States.Add(new SelectListItem { Value = "AZ", Text = "Arizona" });
States.Add(new SelectListItem { Value = "AR", Text = "Arkansas" });
States.Add(new SelectListItem { Value = "CA", Text = "California" });
States.Add(new SelectListItem { Value = "CO", Text = "Colorado" });
}
}
View
#for (var i = 0; i < Model.FreightDiscounts.Count; i++ )
{
<tr>
<td>#Html.DropDownListFor(x => x.FreightDiscounts[i].State, Model.States, new { #class = "form-control" })</td>
</tr>
}
I am populating my FreightDiscounts list in my view model without issue, and right now for testing, I only have 1 state being returned, Alaska. So the 1 record that being populated in that list has the following info
AK,
US,
50,
0,
+
My question is that when the view loads, the state dropdown for the 1 record is set to Alabama (AL), and not Alaska like I would expect. Does anyone see anything obvious I am missing?\
Edit
JamieD77's answer fixed my problem. I changed my View to the following.
<td>
#Html.DropDownListFor(x => x.FreightDiscounts[i].State,
new SelectList(Model.DStates, "key", "value", Model.FreightDiscounts[i].State), new { #class = "form-control" })
</td>
And I changed my View Model to the following
public Dictionary<String, String> DStates { get; set; }
DStates.Add("AL","Alabama" );
DStates.Add("AK","Alaska" );
try using a SelectList and setting the selected item when you build the dropdownlistfor
#Html.DropDownListFor(x => x.FreightDiscounts[i].State,
new SelectList(Model.States, "Value", "Text", x.FreightDiscounts[i].State),
new { #class = "form-control" })
Possibly because your Text and Value fields are reversed?
Edit: OP has updated his code, they originally were reversed.

How to retain the ASP.NET dropdownlist selected item

I'm trying to retain the selected value of a dropdownlist once the user change the dropdownlist item but its not working as expected what I wanted is to retain the selected item in the dropdownlist but its it defaulted to the Select Company everytime i select the item from dropdownlist, once the user change it postback the page (i know there is no postback in the MVC)
What I'm doing wrong here?
<div class="form-group">
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { #id = "form_dropdown" }))
{
#Html.DropDownListFor(m => m.ListOfCompanies,
new SelectList((System.Collections.IEnumerable)Model.ListOfCompanies, "Value", "Text"),
"Select Company", new { #class = "form-control", Name = "sel" })
}
[HttpPost]
public ActionResult Index(string sel)
{
var vModel = new EmployeeViewModel();
vModel = _db.GetEmployee.ToList();
//load list of companies:
var company = _db.LoadComapny.ToList();
IEnumerable<SelectListItem> result = model.Select(b => new SelectListItem
{
Value = b.Value,
Text = b.Text,
Selected = b.Text == sel
}).ToList();
vModel.ListOfCompanies = company;
vModel.SELECTED_COMPANY = sel;
return View(vModel);
}
Model:
public class EmployeeViewModel
{
public IEnumerable<SelectListItem> ListOfCompanies { get; set; }
public string SELECTED_COMPANY { get; set; }
//other props
}
DropdownListFor has 2 important argumnets:
the first one the variable with the index of the selected item (mostly lambda expressions (=>) were used)
the secound one is the SelectList of items availble
#Html.DropDownListFor(m => m.SELECTED_COMPANY,
new SelectList(Model.ListOfCompanies, "Value", "Text"),
"Select Company", new { #class = "form-control", Name = "sel" })
Update it to
#Html.DropDownListFor(m => m.SELECTED_COMPANY,
new SelectList((System.Collections.IEnumerable)Model.ListOfCompanies, "Value", "Text"),
"Select Company", new { #class = "form-control", Name = "sel" })

Resources