Html.DropDownListFor selected value not being selected - asp.net-mvc

EDIT: I've found a solution and what I think is the reason why, see answer below.
I've got a drop down list where the selected calue is not being rendered correctly.
The code to create is as follows:
In the controller
var dlvm = new DonorIndexViewModel();
return View(dlvm);
The ViewModel is created by
public DonorIndexViewModel() {
var list = CreateSearchList();
SearchList = new SelectList(list, "Value", "Text", list.First().Value);
}
CreateSearchList is:
private IEnumerable<SelectListItem> CreateSearchList() {
var list = new List<SelectListItem> {
CreateSelectListItem(Constants.SurnameName, Constants.SurnameValue),
CreateSelectListItem(Constants.CodeName, Constants.CodeValue),
CreateSelectListItem(Constants.PostcodeName, Constants.PostcodeValue),
CreateSelectListItem(Constants.Address1Name, Constants.Address1Value)
};
return list;
}
View code is:
<div class="form-group">
#Html.LabelFor(model => model.SearchList, htmlAttributes: new {#class = "control-label col-md-1"})
<div class="col-md-11">
#Html.DropDownListFor(model => model.SearchListId, Model.SearchList, "Select Search Type", htmlAttributes: new { #class = "control-label input-width-xlarge"})
</div>
</div>
In the view, the model shows the first item is selected:
But the item is not being selected in the browser. Rendered code is as follows:
<select class="control-label input-width-xlarge" data-val="true" data-val- number="The field SearchListId must be a number." data-val-required="The SearchListId field is required." id="SearchListId" name="SearchListId">
<option value="">Select Search Type</option>
<option value="1">Surname</option>
<option value="2">Code</option>
<option value="3">PostCode</option>
<option value="4">Address (Line 1)</option>
</select>
Everything else works fine, e.g. selected value on postback is correct.
Thanks!

The API takes in an object of the selected item, try:
SearchList = new SelectList(list, "Value", "Text", list.First());
No need to add Value.

Got it to work by setting the Id in the controller:
var dlvm = new DonorIndexViewModel();
dlvm.SearchListId = 1;
return View(dlvm);
The value of this seems to determine what is selected, so if it's not set - i.e. has a value 0 - then nothing is selected. Seems a bit counter-intuitive, maybe I'll put in a feature request for this!

Related

Compare dropdown with value not key

I am fetching user data in the model and using SelectList, fetching the country detail with name and ID.
ID Name
1 USA
2 UK
3 CANADA
On my page, I have TEXTBOX, in which I am displaying the country NAME USA which is fetched from the model. Now SAME COUNTRY NAME I WANT TO KEEP SELECTED in my dropdown also.
var GetNewCountry = new SelectList(_manualGridService.GetCountry().OrderBy(l => l.Name)
.ToDictionary(us => us.ID, us => us.Name), "Key", "Value");
ViewBag.GetNewCountry = GetNewCountry ;
here is my view dropdown code
<div class="form-group">
<select asp-for="ConId" asp-items="#ViewBag.GetNewCountry" class="form-control">
<option value=""> Select </option>
</select>
<span asp-validation-for="ConId" class="text-danger"></span>
</div>
Parameter details
public int ConId { get; set; }
Here is my textbox code with parameter
public string UserConName{ get; set; }
<div class="form-group">
<input asp-for="UserConName" class="form-control" readonly="readonly" autocomplete="off" placeholder="Country Name" style="width:107%" />
</div>
The UserConName, textbox contains value USA, I want to keep seleted USA in my DROPDOWN LIST also.
MY SOLUTION
string strId = "";
foreach (var item in GetNewCountry )
{
if (item.Text == res.ConName)
{
strId = item.Value;
}
}
if (!string.IsNullOrEmpty(strId))
{
res.ConId= int.Parse(strId);
}
Shorten Answer
var GetNewCountry = new List<SelectListItem>();
foreach (var item in _manualGridService.GetCountry().OrderBy(l => l.Name).ToDictionary(us => us.ID, us => us.Name))
{
GetNewCountry.Add(new SelectListItem() {
Value = item.Key.ToString(),
Text = item.Value,
Selected = item.Value == "USA" ? true : false
});
}
ViewBag.GetNewCountry = GetNewCountry ;
Detailed explanation
Firstly you need know, by using new SelectList(_manualGridService.GetCountry().OrderBy(l => l.Name) .ToDictionary(us => us.ID, us => us.Name), "Key", "Value"), the Key equals to Id's value, the Value equals to Name's value.
Then compare with this constructor definition: public SelectList(IEnumerable items, string dataValueField, string dataTextField), we can know that ID represents the <option>'s value, 'Name' represents the <option>'s text.
<option value="IDValue">NameValue</option>
Finally the SelectList contains another constructor which can set the dropdownlist selected value:
public SelectList(IEnumerable items, string dataValueField, string dataTextField, object selectedValue)
Above all, in your scenario the selected value does not match the ID, it matched Name value, so you need change the SelectList like below:
var GetNewCountry = new SelectList(_manualGridService.GetCountry().OrderBy(l => l.Name)
.ToDictionary(us => us.ID, us => us.Name), "Value", "Value","USA");
Generated html:
<select class="form-control" data-val="true" data-val-required="The ConId field is required." id="ConId" name="ConId">
<option value=""> Select </option>
<option selected="selected" value="NameValue1">NameValue1</option>
<option value="NameValue2">NameValue2</option>
//...
</select>
Note:
In this way you can get the value="USA" option selected, but another question, your select <select asp-for="ConId"> here binds value to ConId, but the option value now represents Name, so it cannot bind successfully if you do form submit.
So if you do not want to change the <select asp-for="ConId"> to <select asp-for="UserConName">, you need modify your backend code like below:
var GetNewCountry = new List<SelectListItem>();
foreach (var item in _manualGridService.GetCountry().OrderBy(l => l.Name).ToDictionary(us => us.ID, us => us.Name))
{
GetNewCountry.Add(new SelectListItem() { Value = item.Key.ToString(), Text = item.Value, Selected = item.Value == "USA" ? true : false });
}
ViewBag.GetNewCountry = GetNewCountry ;

Selected Option is not Working in MVC Razor View

I'm unable to get selected value in dropdown using simple below code -
<select class="form-control" id="team-name" name="gameTypes">
#{long selectedOption = #ViewBag.HomeTeamId;}
#foreach (var item in Model.teams)
{
<option value="#item.TeamId" data-logo="#item.LogoURL" selected="#(selectedOption == #item.TeamId ? "selected" : "")">#item.FullName</option>
}
</select>
I would do it like this:
Write your method to get the needed Teams in a List<SelectListItem> and then in your controller put the values in a ViewBag (ViewBag.Teams = GetTeams();)
For exmaple:
[NonAction]
private List<SelectListItem> GetTeams()
{
IEnumerable<Team> teams = new List<Team>();
//fill the teams here from the DB
return teams.Select(team => new SelectListItem
{
Text = team.TeamName, //here you can select the property that you want to show as text in the dropdown
Value = team.ID.ToString()
}).ToList();
}
And in your view, retrieve
#{
List<SelectListItem> teams = ViewBag.Teams as List<SelectListItem>;
}
And here define your dropdown and pass teams as the datasource:
<div class="col-md-6 form-group">
#Html.LabelFor(model => model.TeamId, htmlAttributes: new { #class = "control-label" })
#Html.DropDownListFor(model => model.TeamId, teams, "Select a team", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.TeamId, "", new { #class = "text-danger" })
</div>

ASP MVC EF6 Access foreign key table as list

I have 2 tables, codes and countries, with a foreign key constraint on codes.countryid on countries.id - I am using the basic crud given by the controller mvc setup from within visual studio 15 but would like to replace the text input with a select for countryid so that the user can select a country from a dropdown as appose to entering the id as an int.
How do I access a list of the countries through the provided Model? Sample razor code below. Do I need to get the countries list from another model?
<div class="form-group">
<label for="CountryId" class="control-label col-md-2">Country</label>
<select name="CountryId" class="form-control" required>
<option value="">Please select ...</option>
/* Model.Countries is not available even after a foreignkey constraint? */
#foreach(var i in Model.Countries)
{
<option value="#i.id">#i.Name</option>
}
</select>
#Html.ValidationMessageFor(model => model.CountryId, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.CountryId, htmlAttributes: new { #class = "control-label col-md-2" })
</div>
You should set a ViewBag variable in the controller action with the list of countries.
Assuming you have a DB Context inside your controller, you should put the following code in your action
ViewBag.CountriesList = new SelectList(_context.countries.ToList(), "Id", "Name");
And use it as below inside your view
#Html.DropDownListFor(a => a.countryId, (SelectList)ViewBag.CountriesList , htmlAttributes: new { #class = "form-control" })

Why are the initial multiple selections of an Html.ListBox not visible?

I am testing a new plugin that converts a multiple-select ListBox to a set of multiple mutually-exclusive single-select drop-down lists. This should have been very straight-forward, as I just wanted to start with some items selected, but the answer eludes me so far.
I have reduced the problem to the following simple controller code (the plugin was turned off so is not a factor):
List<SelectListItem> selectList2 = db.LookupType.Select(x => new SelectListItem() { Selected = x.LookupTypeId < 4, Value = x.LookupTypeId.ToString(), Text = x.Name }).ToList();
ViewBag.LookupTypeId2 = selectList2;
This will mark Selected = true on the first three items as the IDs start at 1 (confirmed in debugger that the first 3 items have Selected = true).
And the view looks like this:
#Html.ListBox("LookupTypeId2", (IEnumerable<SelectListItem>)ViewBag.LookupTypeId2, htmlAttributes: new { #class = "form-control"})
The resulting output however has no selected items:
<select name="LookupTypeId2" class="form-control" id="LookupTypeId2" multiple="multiple">
<option value="1">Degree</option>
<option value="2">WorkdayLanguage</option>
<option value="3">Language_Ability_Type_ID</option>
<option value="4">National_ID</option>
<option value="5">Phone_Device_Type_ID</option>
<option value="6">Background_Check_Status_ID</option>
<option value="7">Educational_Institution_Type_ID</option>
<option value="8">Gender_Code</option>
<option value="9">Military_Status_ID</option>
<option value="10">Ethnicity_ID</option>
</select>
I have no problem selecting multiples with CTRL-Click etc, but the initial selections are not visible. What am I missing here?
Update: based on answer below I changed it to a ListBoxFor
#Html.ListBoxFor(x=>x.LookupTypeId2, (IEnumerable<SelectListItem>)ViewBag.LookupTypeId2, htmlAttributes: new { #class = "form-control"})
have added the following value initialization:
List<SelectListItem> selectList2 = db.LookupType.Select(x => new SelectListItem() { Selected = x.LookupTypeId < 4, Value = x.LookupTypeId.ToString(), Text = x.Name }).ToList();
lookup.LookupTypeId2 = new string[]{"1","2","3","4"};
ViewBag.LookupTypeId2 = selectList2;
Also tried with int array as suggested:
List<SelectListItem> selectList2 = db.LookupType.Select(x => new SelectListItem() { Selected = x.LookupTypeId < 4, Value = x.LookupTypeId.ToString(), Text = x.Name }).ToList();
lookup.LookupTypeId2 = new int[]{1,2,3,4};
ViewBag.LookupTypeId2 = selectList2;
But still nothing is selected.
Firstly you need a property to bind to. A multiple select will only post back a collection of value types, but your trying to bind to List<SelectListItem>. Add a property (say) public int[] SelectedItems { get; set; } to your model and then use
#Html.ListBoxFor(m => m.SelectedItems, (IEnumerable<SelectListItem>)ViewBag.LookupTypeId2, htmlAttributes: new { #class = "form-control"})
Then if the values of SelectedItems matches any of the options, those options will be selected, for example if model.SelectedItems = new int[] { 2, 10 }; then the 2nd and last options will be selected when you display the page. You do not (and should not) set the Selected property of SelectListItem when your binding to a property.

Using a html select box with razor

I have a html selector, and I want to use the selected value for my "model => model.type" in my form. Is there a way to set the value in my #Html.EditorFor(model => model.type) to the value of the selector?
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Bet</legend>
<div class="editor-label">
#Html.LabelFor(model => model.type)
</div>
<div class="editor-field">
<select id ="type">
<option value="Football">Football</option>
<option value="Rugby">Rugby</option>
<option value="Horse Racing">Horse Racing</option>
</select>
#Html.EditorFor(model => model.type)
#Html.ValidationMessageFor(model => model.type)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
You can try with this options:
Model:
public string Type { get; set; }
public IEnumerable<SelectListItem> TypeList
{
get
{
return new List<SelectListItem>
{
new SelectListItem { Text = "Football", Value = "Football"},
new SelectListItem { Text = "Rugby", Value = "Rugby"},
new SelectListItem { Text = "Horse Racing", Value = "Horse Racing"}
};
}
}
HTML (Razor):
#Html.DropDownListFor(model => model.Type, Model.TypeList)
OR
HTML (Razor):
#Html.DropDownListFor(model => model.Type, new SelectList(new string[] {"Football", "Rugby", "Horse Racing"}, Model.Type))
#andresdescalzo's solution (last one) works with a minor change:
#Html.DropDownListFor(model => model.Type, new SelectList(new string[] {"Football", "Rugby", "Horse Racing"}, "Rugby"), htmlAttributes: new { #class = "form-control" })
First: Add a selected item for dropdown list (e.g. "Rugby")
Second: remove last Model.Type and add htmlAttributes
PS: SelectedList open parentheses closed after selected item of list (here is "Rugby")
The solution provided by #andresdescalzo works only when we pass the model from Controller to the view.
public class SomeController : Controller
{
public ActionResult SomeAction()
{
return View(new SomeModelWithIEnumerationsSelectListItem())
}
}
An addition to the existing answers: If you get the exception "object reference not set to an instance of an object" when implementing #andresdescalzo's solution, you either need to:
Return the model that you are working with as #diwas mentioned
Instantiate a model on the razor page so you can call the method. This is helpful if you are using a ViewModel instead of a simple EF model.
The second can be done like this:
#{ var tempModel = new YourNameSpace.Models.YourModel(); }
#Html.DropDownListFor(model => model.Type, tempModel.TypeList, Model.Type))
This is the Razor View
<div class="editor-field col-md-3">
#Html.DropDownListFor(model => model.Servers,
Model.AvailableServers,new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.SqlServerName)
</div>
Dynamic DropDown from controller
List<SelectListItem> ServersAvailable = new List<SelectListItem>();
bool IdSelected = false;
ServersAvailable.Add(new SelectListItem { Text = "......Select your server name......", Value = "" });
for (int i = 0; i < dt.Rows.Count; i++)
{
ServersAvailable.Add(new SelectListItem
{
Text = dt.Rows[i].ItemArray[0].ToString(),
Value = dt.Rows[i].ItemArray[0].ToString(),
Selected = IdSelected
});
}

Resources