DropDownList always displays the first element - c#

I have the DropDownList which has two items. When I select the second one, it flashes it then goes back the first one immediately.
#Html.DropDownListFor(m => m.SelectedProduct, new SelectList(Model.Products, "ProductCode", "ProductName",Model.SelectedProduct),new { #class = "form-control" })
My controller code.
public ActionResult Index(int id, string productName)
{
var model = new ProductModel
{
Product = ProductService.GetProducts()
};
var view = "Something";
model.SelectedProduct = productName;
if(productName =="another")
view = "another";
return View(view, model);
}
The type of Model.Products is IList<Product>.
public class Product
{
public string ProductName {get;set;}
public string ProductCode {get;set;}
}
I saw this link, but I don't have ViewData in my controller. So help me please.
My client side code:
$(document).ready(function () {
$("#SelectedProduct").change(function () {
var selectedValue = $(this).find('option:selected').text();
window.location.href = "#(Url.RouteUrl("MyRoute", new { id = Model.id }))/" + encodeURI(selectedValue);
});

The problem is with the selected item (4th parameter) that is passed to
new SelectList(Model.Products, "ProductCode", "ProductName", Model.SelectedProduct).
This expects that Model.SelectedProduct holds the Value of an item in the SelectList.
But your JS code passes var selectedValue = $(this).find('option:selected').text(); which is the Name.
Change this to
var selectedValue = $(this).find('option:selected').val(); to pass along the ProductCode.

Related

Unable to Populate Dropdown from Database with MVC

Bear with me, I am new to MVC. I am trying to populate a dropdown list from a list function that retrieves integer values from the database. The dropdown currently shows the model name instead of values.
In my model, I have two functions for the AgentId I am trying to receive and have tried using both. I am uncertain on how this should actually be called.
Edit: I made a few changes and the list is now populating but I am unable to update the selected value. When I try to submit, I am getting this error in my view: "System.InvalidOperationException: 'There is no ViewData item of type 'IEnumerable' that has the key 'AgentId'.'"
Below is my updated code:
// customer model
[DisplayName("Agent")]
public int AgentId { get; set; }
// list function
public static List<int> GetAgentIdDropdown()
{
List<int> agentIdList = new List<int>();
string getAgentIdQuery = #"SELECT AgentId FROM Agents";
using (SqlConnection con = TravelExpertsConn.GetConnection())
{
using (SqlCommand cmd = new SqlCommand(getAgentIdQuery, con))
{
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
Customer Agents = new Customer();
while (reader.Read())
{
Agents.AgentId = Convert.ToInt32(reader["AgentId"]);
agentIdList.Add(Agents.AgentId);
}
con.Close();
}
}
return agentIdList;
}
// view
#Html.DropDownListFor(model => model.AgentId, (IEnumerable<SelectListItem>)ViewBag.AgentId, "Select Agent ID", new { #class = "form-control" })
// controller
public ActionResult Edit()
{
int id = Convert.ToInt32(Session["CustomerId"]);
Customer currentCust = CustomerDB.CustomerDetails(id);
ViewBag.AgentId = new SelectList(CustomerDB.GetAgentIdDropdown(), currentCust.AgentId);
return View(currentCust);
}
// POST: Customer/Edit/5
[HttpPost]
public ActionResult Edit(Customer customer)
{
if (ModelState.IsValid)
{
try
{
int id = Convert.ToInt32(Session["CustomerId"]);
CustomerDB.EditCustomer(id, customer);
return RedirectToAction("Details");
}
catch
{
return View();
}
}
else
{
return View();
}
}
The DropDownListFor() method parameters should consist of first, the attribute of the model representing the selection by the user, which I'm guessing is your model.AgentId. The second parameter should be the IEnumerable property of the Model containing the options, or model.Agents
So one issue then is this line:
#Html.DropDownListFor(model => model.AgentId, ViewBag.Agents as SelectList, new { #class = "form-control" })
should look more like this:
#Html.DropDownListFor(model => model.AgentId, model.Agents, new { #class = "form-control" })
But more so, the model.Agents property is not going to actually return anything without a backing property. Here's a good example I've found online:
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");}
}
}
Notice how FlavorItems get method is returning a SelectList of the _flavors. Currently the code you've provided doesn't show any assignment of your GetAgentIdDropDown() to any property of the model, so I would try to match your Model's code with the convention I provided above, assign the results of GetAgentIdDropDown() to the backing property, and change the parameters of the #Html.DropDownListFor() as well.
I found the example from this link if you want to check it out. It's a bit older but there's only a minor difference in syntax.

return model to view on error with selectlistitem default value

i have some issues with default value of my dropdownlist when returning my model to view in case of one or many errors. I have a dropdownlist in the view which is filled from the controller and others empty dropdownlists in the same view which are filled with JSON on selection of the first dropdownlist.
public ActionResult Countriesdata()
{
CountrydetailsViewModel vm= new CountrydetailsViewModel();
vm.countries= dal.countries().Select(x => new SelectListItem { Text = x.Name, Value = x.CountryID.ToString() })
.ToList();
return View(vm);
}
here, dal is my data access layer and allows me to fill the list of countries from the database. The code use to fill the countries list in the view is like this
#Html.DropDownListFor(m => m.selectedcountry, new SelectList(Model.countries, "Value", "Text", Model.selectedcountry), "-Select a Country-", new { #class = "ddlist" })
one of the empty dropdowlists is as the one below
#Html.DropDownListFor(m => m.selectedtown, new SelectList(Enumerable.Empty<SelectListItem>(), "Value", "Text", Model.selectedtown), "-Select a Town/City-", new { #class = "ddlist" })
This code work very well i reach the page for the first time because i have set a default value for country dropdownlist which is select a country. i use the following code to post my form.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Countriesdata(CountrydetailsViewModel returnmodel)
{
if (! ModelState.IsValid)
{
returnmodel.countries= dal.countries().Select(x => new SelectListItem { Text = x.Name, Value = x.CountryID.ToString() })
.ToList();
return View(returnmodel);
}
return RedirectToAction("mainpage");
}
If the form contains errors, my model is returned back to my view with the posted value of country selected dropdownlist as default, which is not my goal because the others dropdowlists which are filled using JSON on the country dropdownlist selection change are empty.Thus, I ought to select this same country once to fill the others dropdowlists, which is cumbersome. To be logic, i would like to send back my model to my view with default value of the dropdowlist of country when an error occurs. I am using MVC4 and VS 2010
You need to populate both SelectList's in the controller methods so they get passed to the view. In the GET method, the 2nd one will be an empty SelectList (assuming its a 'Create' metod), but in the POST method it will be populated based on the country that has been selected.
You model should include
public class CountrydetailsViewModel
{
[Required(Error Message = "..")]
public int? SelectedCountry { get; set; }
[Required(Error Message = "..")]
public int? SelectedTown { get; set; }
....
public IEnumerable<SelectListItem> CountryList{ get; set; }
public IEnumerable<SelectListItem> TownList { get; set; }
}
And your controller methods
public ActionResult Countriesdata()
{
CountrydetailsViewModel vm = new CountrydetailsViewModel();
ConfigureViewModel(vm);
return View(vm);
}
[HttpPost]
public ActionResult Countriesdata(CountrydetailsViewModel returnmodel)
{
if(!ModelState.IsValid)
{
ConfigureViewModel(returnmodel);
return View(returnmodel);
}
.... // save and redirect
}
private ConfigureViewModel(CountrydetailsViewModel model)
{
var countries = dal.countries();
model.CountryList= countries.Select(x => new SelectListItem
{
Text = x.Name,
Value = x.CountryID.ToString()
});
if (model.SelectedCountry.HasValue)
{
// adjust query to suit your property names
var towns = db.towns.Where(e => e.CountryId == model.SelectedCountry);
model.TownList = towns.Select(x => new SelectListItem
{
Text = x.Name,
Value = x.TownID.ToString()
});
}
else
{
model.TownList = new SelectList(Enumerable.Empty<SelectListItem>());
}
}
This also allows you to generate the correct options and default selections when editing an existing CountrydetailsViewModel.
Then in the view, use
#Html.DropDownListFor(m => m.SelectedCountry, Model.CountryList, "-Select a Country-", new { #class = "ddlist" })
#Html.ValidationMessageFor(m => m.SelectedCountry)
#Html.DropDownListFor(m => m.SelectedTown, Model.TownList, "-Select a Country-", new { #class = "ddlist" })
#Html.ValidationMessageFor(m => m.SelectedTown)
Note that there is no point creating an identical SelectList from the original one you passed to the view by using new SelectList(..) - its just unnecessary extra overhead. Note also that the last parameter in the SelectList constructor is ignored when your binding to a model property (internally the method builds its own SelectList based on the value of the property) - you could put whatever value you wanted as the last parameter and you will see that the option is still correct selected based on the value of the property.

How can I capture the #Html.DropDownListFor selected value?

I am using MVC5, Razor, Entity Framework, C#. I am trying to pass a value of a dorpdown list using a link.
my model is
public class TestVM
{
public string TheID { get; set; }
}
I am loading an enum into a IEnumerable<SelectListItem>.
My enum is
public enum DiscountENUM
{
SaleCustomer,
SaleCustomerCategory,
SaleProduct,
SaleProductCategory,
SaleCustomerAndProduct,
SaleCustomerAndProductCategory,
SaleCustomerCategoryAndProductCategory,
PurchaseVendor,
PurchaseVendorAndProduct,
PurchaseVendorAndProductCategory,
PurchaseProduct,
PurchaseProductCategory,
Unknown
}
I am using the index method of the home controller
public ActionResult Index()
{
ViewBag.ListOfDiscounts = SelectListDiscountENUM();
TestVM d = new TestVM();
return View(d);
}
Where I load the ListOfDiscounts using:
private IEnumerable<SelectListItem> SelectListDiscountENUM()
{
List<SelectListItem> selectList = new List<SelectListItem>();
var listOfEnumValues = Enum.GetValues(typeof(DiscountENUM));
if (listOfEnumValues != null)
if (listOfEnumValues.Length > 0)
{
foreach (var item in listOfEnumValues)
{
SelectListItem sVM = new SelectListItem();
sVM.Value = item.ToString();
sVM.Text = Enum.GetName(typeof(DiscountENUM), item).ToString();
selectList.Add(sVM);
}
}
return selectList.OrderBy(x => x.Text).AsEnumerable();
}
My create method which is called from the view is
public ActionResult Create(TestVM d, string TheID)
{
return View();
}
My Index view is
#model ModelsClassLibrary.Models.DiscountNS.TestVM
<div>#Html.ActionLink("Create New", "Create", new { TheID = Model.TheID})</div>
<div>
#Html.DropDownListFor(x => x.TheID, #ViewBag.ListOfDiscounts as IEnumerable<SelectListItem>, "--- Select Discount Type ---", new { #class = "form-control" })
</div>
The problem is in the following line in the View
<div>#Html.ActionLink("Create New", "Create", new { TheID = Model.TheID })</div>
I have tried adding a model with the name of the field as "TheID"... no luck. Also, added a string field in the parameter, no luck. I looked at the FormControl object, and there was nothing in it either! I suspect something has to be added at the Route level in the helper, but I don't know what.
Model.TheID is always null. Even when I select an item in the DropDownListFor.
Does anyone have an idea how I can capture the select value of the DropDownListFor and send it into the Html.ActionLink TheID?

Set selected index of dropdown to zero after form submit in ASP.NET MVC

I am bit to new asp.net mvc and using aps.net mvc 5. I have create the below dropdown using html helpers in aps.net mvc. When i submit(post back) the form i want to set the selected index to zero. Here i am using a optionLabel "--select--". I want to set the selected value to that one ("--select--") after post back. How to achieve this. Please help. Thank you.
#Html.DropDownListFor(model => model.TestCategory, new SelectList(#ViewBag.TestCategories, "value", "text"), "-- Select --", new { #class = "form-control input-sm"})
Controller Code
[HttpGet]
public ActionResult Index()
{
var model = new LaboratoryViewModel {
medicaltestlist = new List<MedicalTest>()
};
PopTestCategory();
PopEmptyDropdown();
return View(model);
}
[HttpPost]
public ActionResult Index(LaboratoryViewModel labvm)
{
var test = PopMedicalTests().Where(x => x.TestSerial == Convert.ToInt32(labvm.TestCode)).FirstOrDefault();
if (labvm.medicaltestlist == null)
labvm.medicaltestlist = new List<MedicalTest>();
if(!labvm.medicaltestlist.Any(x=> x.TestSerial == test.TestSerial))
labvm.medicaltestlist.Add(test);
labvm.TestCategory = "";
PopTestCategory();
return View(labvm);
}
public void PopTestCategory()
{
var categorylist = new List<DropDownItem>
{
new DropDownItem{value="Medical",text="Medical"},
new DropDownItem{value="Animal",text="Animal"},
new DropDownItem{value="Food",text="Food"},
new DropDownItem{value="Water",text="Water"}
};
ViewBag.TestCategories = categorylist;
}
public class DropDownItem
{
public int id { get; set; }
public string value { get; set; }
public string text { get; set; }
}
You return the view in you post method so if you selected (say) Animal then that value will be selected when you return the view because the html helpers use the values from ModelState, not the model property. Setting labvm.TestCategory = ""; has no effect. The correct approach is to follow the PRG pattern and redirect to the GET method, however you can make this work by calling ModelState.Clear(); before setting resetting the value of TestCategory although this will clear all ModelState properties and errors and may have other side effects.
Side note: You DropDownItem class seems unnecessary. MVC already has a SelectListItem class designed to work with dropdownlists, and in any case you can replace all the code in your PopEmptyDropdown() method with
ViewBag.TestCategories = new SelectList(new List<string>() { "Medical", "Animal", "Food", "Water" });
and in the view
#Html.DropDownListFor(m => m.TestCategory, (SelectList)#ViewBag.TestCategories, "-- Select --", new { #class = "form-control input-sm"})
If you set the "value" attribute of the top item in the drop down list to something and then pass back a model containing that for the bound property it should work?

How Do I Model Bind A List Of 'List<SelectItem>' Using MVC.Net

I am trying to create a form that will consist of a series of dropdown lists, all of which are loaded from a database. I will not know how many dropdown lists will be needed, or how many options each dropdown list will have at compile-time.
How can these fields be set-up to allow them to model-bind when posted?
There is a lot of other complexity in each of the below code elements, but I cannot get the model binding to work even when reduced down to a basic level.
The Models:
public class MyPageViewModel
{
public List<MyDropDownListModel> ListOfDropDownLists { get; set; }
}
public class MyDropDownListModel
{
public string Key { get; set; }
public string Value { get; set; }
public List<SelectListItem> Options { get; set; }
}
The Controller Get Action:
[AcceptVerbs(HttpVerbs.Get)]
[ActionName("MyAction")]
public ActionResult MyGetAction()
{
var values_1 = new List<string> {"Val1", "Val2", "Val3"};
var options_1 =
values_1
.ConvertAll(x => new SelectListItem{Text=x,Value=x});
var myDropDownListModel_1 =
new MyDropDownListModel { Key = "Key_1", Options = options_1 };
var values_2 = new List<string> {"Val4", "Val5", "Val6"};
var options_2 =
values_2
.ConvertAll(x => new SelectListItem{Text=x,Value=x})};
var myDropDownListModel_2 =
new MyDropDownListModel { Key = "Key_2", Options = options_2 };
var model =
new MyPageViewModel
{
ListOfDropDownLists =
new List<MyDropDownListModel>
{
myDropDownListModel_1,
myDropDownListModel_2,
}
};
return View(model);
}
The Controller Post Action:
[AcceptVerbs(HttpVerbs.Post)]
[ActionName("MyAction")]
public ActionResult MyPostAction(MyPageViewModel model)
{
//Do something with posted model...
//Except 'model.ListOfDropDownLists' is always null
return View(model);
}
The View:
#model MyPageViewModel
#using (Html.BeginForm("MyPostAction"))
{
foreach (var ddl in Model.ListOfDropDownLists)
{
#Html.DropDownListFor(x => ddl.Value, ddl.Options)
}
<button type="submit">Submit</button>
}
Edit: Corrected typos and copy-paste mistakes.
Solution:
The problem turned out to be the foreach-loop within the view. Changing it into a for-loop instead caused the post to populate as expected. The updated view is below:
#using (Html.BeginForm("MyPostAction"))
{
for (int i = 0; i < Model.ListOfDropDownLists.Count; i++)
{
#Html.HiddenFor(x => x.ListOfDropDownLists[i].Key)
#Html.DropDownListFor(m => m.ListOfDropDownLists[i].Value, Model.ListOfDropDownLists[i].Options);
}
<button type="submit">Submit</button>
}
Your view is only creating multiple select elements named dll.Value (and duplicate ID's) which has no relationship to your model. What you need is to create elements named ListOfDropDownLists[0].Value, ListOfDropDownLists[1].Value etc.
Change you loop in the view to this
for (int i = 0; i < Model.ListOfDropDownLists.Count; i++)
{
#Html.DropDownListFor(m => m.ListOfDropDownLists[i].Value, Model.ListOfDropDownLists[i].Options);
}
You posted code has multiple errors (e.g. your pass a model of type MyPageViewModel but the post action method expects type of MyModel). I assume these are just typo's.
I can give you my solution,It is working:
Method in base controller
//To bind Dropdown list
protected Dictionary<int, string> GenerateDictionaryForDropDown(DataTable dtSource, string keyColumnName, string valueColumnName)
{
return dtSource.AsEnumerable()
.ToDictionary<DataRow, int, string>(row => row.Field<int>(keyColumnName),
row => row.Field<string>(valueColumnName));
}
Code in controller:
DataTable dtList = new DataTable();
dtList = location.GetDistrict();
Dictionary<int, string> DistrictDictionary = GenerateDictionaryForDropDown(dtList, "Id", "DistrictName");
model.DistrictList = DistrictDictionary;
Binding Data in view:
#Html.DropDownListFor(model => model.DiscrictId, new SelectList(Model.DistrictList, "Key", "Value"), new { id = "ddlDist", #class = "form-control" })
Binding Other Dropdown from this(cascading):
Other Dropdown:
#Html.DropDownListFor(model => model.TalukaId, new SelectList(Model.TalukaList, "Key", "Value"), new { id = "ddlTaluka", #class = "form-control" })
JQuery Code:
$("#ddlDist").change(function () {
var TalukaList = "Select"
$('#ddlTaluka').html(TalukaList);
$.ajax({
type: "Post",
dataType: 'json',
url: 'GetTaluka',
data: { "DistId": $('#ddlDist').val() },
async: false,
success: function (data) {
$.each(data, function (index, optionData) {
TalukaList = TalukaList + "<option value='" + optionData.Key + "'>" + optionData.Value + "</option>";
});
},
error: function (xhr, status, error) {
//alert(error);
}
});
$('#ddlTaluka').html(TalukaList);
});
Controller Method Return JSON
public JsonResult GetTaluka(int DistId)
{
LocationDH location = new LocationDH();
DataTable dtTaluka = location.GetTaluka(DistId);
Dictionary<int, string> DictionaryTaluka = GenerateDictionaryForDropDown(dtTaluka, "ID", "TalukaName");
return Json(DictionaryTaluka.ToList(), JsonRequestBehavior.AllowGet);
}

Categories

Resources