why is my dropdown selection not being submitted? - asp.net-mvc

I have a dropdown list when the form is submitted it is submitted null...
html:
#Html.DropDownListFor(c => Model.HowOftenCar, Model.HowOftenCar, new { id = "CompDrop" })
Model:
public IEnumerable<SelectListItem> HowOftenCar { get; set; }
Controller:
IList<string> HowOftenCar = new List<string>();
HowOftenCar.Insert(0, "More than once a week");
HowOftenCar.Insert(1, "Once a month");
HowOftenCar.Insert(2, "Once a year");
model.HowOftenCar = HowOftenCar.Select(c => new SelectListItem()
{
Text = c,
Value = c
});
Post:
[HttpPost]
public ActionResult Index(Competition model)
{
if (ModelState.IsValid)
{}
}
I have also tried...
#Html.DropDownListFor(c => Model.HowOftenCar, new SelectList(Model.HowOftenCar, "Value","Text"), new { id = "CompDrop" })

You're not using DropDownListFor correctly.
The first parameter is the property on the model you want to populate. If you want to populate the HowOftenCar property on the model, it should be of the type of the value - in this case, it looks like a string.
public string HowOftenCar { get; set; }
The second parameter is the list of choices. You've got that right, but it needs to be something else than the property you're trying to set.
IList<string> HowOftenCarChoices = new List<string>
{
"More than once a week",
"Once a month",
"Once a year"
};
model.HowOftenCarChoices = HowOftenCar.Select(c => new SelectListItem()
{
Text = c,
Value = c
});
So then you'll end up with
#Html.DropDownListFor(m => m.HowOftenCar, Model.HowOftenCarChoices)
Note that you don't need the id property, because DropDownListFor will automatically give it the id of HowOftenCar, based on the lambda.

Related

Placeholder on a #Html.Dropdownlist that is not selectable

How do i put a placeholder on my #Html.Dropdownlist that is not selectable.
I implemented chosen-jquery on my dropdown.
My code is as per below:
#Html.DropDownList("Id", new SelectList(new Ahib.Membership.UserFacade().GetAllUsers(), "Id", "Username"), "-select a system owner-", new { #class="chosen1-select" })
Currently my dropdownlist has a placeholder but the "-select a system owner-" becomes a selectable value which i dont want. How do solve this issue?
You can convert your list to the selectitem list and apply your disabled attribute from the controller itself.
like this
assuming your model is like this
class user
{
public int Id { get; set; }
public string Username { get; set; }
}
Convert your list to List<SelectListItem> like this, note here I am disabling the select a system owner entry.
public ActionResult Index()
{
List<user> users = new List<user>();
users.Add(new user { Id = 1, Username = "test1" });
users.Add(new user { Id = 2, Username = "test2" });
List<SelectListItem> list = new List<SelectListItem>();
list.Add(new SelectListItem { Text = "-select a system owner-", Value = "0", Disabled = true });
foreach (var item in users)
{
list.Add(new SelectListItem
{
Text = item.Username,
Value = item.Id.ToString()
});
}
ViewBag.listItems = list;
return View();
}
and in view use it like this
#Html.DropDownList("test", ViewBag.listItems as IEnumerable<SelectListItem>);
Result:

Dropdownlistfor selected text and value ASP.NET MVC

I have three dropdownlistfor in edit mode, i am able to populate the correct text in DDLFor but the id of it is coming up as 0 on submit, but if i select a different team it is coming up with correct id. Following is my code
ViewModel
public List<SelectListItem> TeamOneList { get; set; }
public string SelectedTeamOne { get; set; }
.... //remaining properties for DDL's..........
Controller
List<SelectListItem> TeamOneList = new List<SelectListItem>();
foreach (var item in db.Teams)
{
TeamOneList.Add(new SelectListItem { Text = item.TeamName, Value = item.TeamId.ToString() });
}
string SelectedTeamOne = db.Teams.Where(o => o.TeamId == fixture.TeamOneId).Select(s => s.TeamName).Single();
View
#Html.DropDownListFor(model => model.TeamOneId, Model.TeamOneList, Model.SelectedTeamOne, new { #class = "form-control" })
Your generating the option value attribute based on the TeamId property of Team, but your setting the SelectedTeamOne value based on the TeamName name property, so the value of SelectedTeamOne does not match any of the options, therefore the first option (the null label option) is selected (because something has to be).
But you generating the null label option with the same text as SelectedTeamOne so it appears your are selecting it when in fact your only selecting the option with a null value (there is actually a second option with the same name in your dropdownlist).
Your need to change the code in the view to
#Html.DropDownListFor(model => model.SelectedTeamOne, Model.TeamOneList, "-Please select-", new { #class = "form-control" })
and then change the controller code to
SelectedTeamOne = db.Teams.Where(o => o.TeamId == fixture.TeamOneId).Select(s => s.TeamId).Single();
Note that it appears TeamId is typeof int, therefore your SelectedTeamOne property should also be int, not string
public int SelectedTeamOne { get; set; }
In addition, you can simply use
var model = new yourModelName
{
TeamOneList = db.Teams.Select(x => new SelectListItem>
{
Value = x.TeamId.ToString(),
Text = x.TeamName
}),
SelectedTeamOne = fixture.TeamOneId // no need to make a database call
};
return View(model);
or, even simpler
var model = new yourModelName
{
TeamOneList = new Selectist(db.Teams, "TeamId", "TeamName"),
SelectedTeamOne = fixture.TeamOneId // no need to make a database call
};
return View(model);

How to set the default value for Html.DropDownListFor in MVC

i have following code :
controller method:
public ActionResult Register(int? registrationTypeId)
{
IEnumerable<AccountType> accountTypes = new List<AccountType>
{
new AccountType
{
AccountTypeId = 1,
AccountTypeName = "Red"
},
new AccountType
{
AccountTypeId = 2,
AccountTypeName = "Blue"
}
};
// I want to select account type on registrationTypeId
ViewBag.AccountTypes = accountTypes;
return View();
}
View
<div class="col-md-10">
#Html.DropDownListFor(n => n.AccountType,
new SelectList(ViewBag.AccountTypes, "AccountTypeId", "AccountTypeName"), new { #class = "form-control" })
</div>
Model
public class RegisterViewModel
{
[Required]
[Display(Name = "Account Type")]
public int AccountType { get; set;
}
As you can see registrationTypeId in controller , i want to set the type on its bases if it is not null ,otherwise set to red. I have tried a alot but nothing worked for me. Any help will be appreciated !
I would highly recommend that you don't pass your list through the view bag. have seen too many questions where that has caused major issues. add this to your model
public List<SelectListItem> AccountTypes { get; set; }
in your controller in the get method set your default and set your list
Model.AccountType = 1; // change the one to your default value
Model.AccountTypes = accountTypes; //instead of ViewBag.AccountTypes = accountTypes;
then on your view
#Html.DropDownListFor(x => x.AccountType, Model.AccountTypes)
setting AccountType before passing the model to the view will set the default and the selected value on the view will be passed back in that same value.
The Wrong Way To Do This
var accountTypes = new SelectList(accountTypes, "AccountTypeId", "AccountTypeName");
foreach(var item in accountList)
if (item.AccountTypeId == registrationTypeId)
item.Selected = true;
ViewBag.AccountTypes = accountTypes;
In view,
#Html.DropDownListFor(n => n.AccountType, (SelectList)ViewBag.AccountTypes)

Problem with DropDownListFor SelectedItem

This has totally puzzled me.
Here's my View:
#Html.DropDownListFor(model => model.ScoreDescription,
Model.RatingOptions,
"--",
new { #id = clientId })
And the model:
public decimal? Score { get; set; }
public SelectList RatingOptions
{
get
{
var options = new List<SelectListItem>();
for (var i = 1; i <= 5; i++)
{
options.Add(new SelectListItem
{
Selected = Score.HasValue && Score.Value == Convert.ToDecimal(i),
Text = ((decimal)i).ToRatingDescription(ScoreFactorType),
Value = i.ToString()
});
}
var selectList = new SelectList(options, "Value", "Text");
// At this point, "options" has an item with "Selected" to true.
// Also, the underlying "MultiSelectList" also has it.
// Yet selectList.SelectedValue is null. WTF?
return selectList;
}
}
As the comments suggest, i can't get the selected value to happen.
Is it something to do with the fact i'm using a nullable decimal ? After that loop, options is correct in that it has exactly 1 item with select to true, so it seems i'm doing the right thing.
Now, if i use a different SelectList overload:
var selectedValue = Score.HasValue ? Score.Value.ToString("0") : string.Empty;
var selectList = new SelectList(options, "Value", "Text", selectedValue);
It works. Why? At first i thought it might be a LINQ-trick (e.g deferred execution), but i tried forcing a .ToList() and there is no difference.
It's like setting the Selected property as you create the SelectListItem has no effect, and you have you set it at the end using the SelectList ctor parameter.
Can anyone shed some light on this?
If you look at the implementation of the SelectList class it never actually uses the fact that you are passing a SelectListItem. It works with an IEnumerable. So the Selected property of a SelectListItem is not used. Personally I prefer setting the selected value of a dropdown by setting the value of the corresponding property that you are binding the ddl to.
Example:
public int? Score { get; set; }
public SelectList RatingOptions
{
get
{
var options = Enumerable.Range(1, 5).Select(i => new SelectListItem
{
Text = ((decimal)i).ToRatingDescription(ScoreFactorType),
Value = ((decimal)i).ToString()
});
return new SelectList(options, "Value", "Text");
}
}
and then in the controller action simply set the Score property to the necessary value and in the view use this Score property to bind to:
#Html.DropDownListFor(
model => model.Score,
Model.RatingOptions,
"--",
new { #id = clientId }
)

Creating a SelectListItem with the disabled="disabled" attribute

I'm not seeing a way to create, via the HtmlHelper, a SelectListItem that will spit out the following HTML:
<option disabled="disabled">don't click this</option>
The only properties SelectListItem has are:
new SelectListItem{
Name = "don't click this",
Value = string.Empty,
Selected = false
}
The only option I see is to
Subclass the SelectListItem to add an Enabled property to get the value to the view
Not use the HTML helper for DropDownList
Create a new HtmlHelper extension that accepts my new EnablableSelectList and adds my disabled attribute.
The Disabled property is supported since ASP.NET MVC 5.2:
new SelectListItem {
// ...
Disabled = true
}
See the API reference.
This is something I might try before recreating the helper completely. The basic idea is that the Html you get from the helper should be well formed, so it should be safe to parse. So you can build on that idea by making your own extension that uses the existing extension but adds the functionality to disable the items.
Something like this might do (totally untested)
public class CustomSelectItem : SelectListItem
{
public bool Enabled { get; set; }
}
public static class CustomHtmlHelpers
{
public static MvcHtmlString MyDropDownList(this HtmlHelper html, IEnumerable<CustomSelectItem> selectList)
{
var selectDoc = XDocument.Parse(html.DropDownList("", (IEnumerable<SelectListItem>)selectList).ToString());
var options = from XElement el in selectDoc.Element("select").Descendants()
select el;
foreach (var item in options)
{
var itemValue = item.Attribute("value");
if (!selectList.Where(x => x.Value == itemValue.Value).Single().Enabled)
item.SetAttributeValue("disabled", "disabled");
}
// rebuild the control, resetting the options with the ones you modified
selectDoc.Root.ReplaceNodes(options.ToArray());
return MvcHtmlString.Create(selectDoc.ToString());
}
}
Clientside option: if you for example give your dropdownlist a class 'custom' and the items that should be unselectable the value -1 (for example), then you can do something like:
$('select.custom option[value=-1]').each(function () {
$(this).attr("disabled", "disabled");
});
If all you are trying to do is prevent a user from selecting a certain value from the list, it seems like the simpler and more time-efficient way to do it is to use input validation. Which you may quite possibly be doing anyways, if you want to verify they've made a selection to begin with.
-----Option 1
Controller:
var ExpectedShipmentsRange = new List();
ExpectedShipmentsRange.Add(new SelectListItem() { Text = "Selected number of shipments", Value="0", Disabled = true, Selected = true });
ExpectedShipmentsRange.Add(new SelectListItem() { Text = "0 to 20 shipments", Value = "0-20" });
ExpectedShipmentsRange.Add(new SelectListItem() { Text = "20 to 40 shipments", Value = "20-40" });
ViewBag.ExpectedShipmentsRange = ExpectedShipmentsRange;
View:
#Html.DropDownListFor(m => m.ExpectedShipments, (IEnumerable<SelectListItem>)#ViewBag.ExpectedShipmentsRange, new { #class = "form-control" })
-----Option 2
Controller:
ViewBag.citiesSa = _dbContext.Countries.ToList();
View:
#Html.DropDownListFor(m => m.City, new SelectList(#ViewBag.citiesSa, "Id", "Name"), "Select your city", new { #class = "form-control" })
-----Option 3 does not support disabled option:
List<SelectListItem> ExpectedShipmentsRange = new List<SelectListItem>();
ExpectedShipmentsRange.Add(new SelectListItem() { Text = "0 to 20 shipments", Value = "0-20" });
ExpectedShipmentsRange.Add(new SelectListItem() { Text = "20 to 40 shipments", Value = "20-40" });
ViewBag.ExpectedShipmentsRange = new SelectList(ExpectedShipmentsRange, "Value", "Text");
View:
#Html.DropDownListFor(m => m.ExpectedShipments, (SelectList)#ViewBag.ExpectedShipmentsRange, new { #class = "form-control" })
I've noticed that while using SelectList to populate the DropDownListFor() method the Disabled & Selected parameters are not respected. They are only honored when populating using List<SelectListItem>. However I've run into other odd bugs when populating the DropDownListFor() using List<SelectListItem> and found that using SelectList is the correct option for populating a DropDownListFor() list. Here's an example of how to create a SelectList list:
public static SelectList States = new SelectList(new[]
{
new SelectListItem { Text = "AL", Value = "AL" },
new SelectListItem { Text = "AK", Value = "AK" },
...
}, "Value", "Text", 1);
In my case I needed to disable the first item of the select list, the only way I was able to do so using the SelectList was by creating an extension method for the DropDownListFor() method. Here is the class I used:
public static class HtmlHelperExtensions
{
private static MvcHtmlString DisableFirstItemDropDownListFor(MvcHtmlString source, string sourceItemName, string sourceItemValue = "", string targetItemValue = "")
{
string htmlString = source.ToHtmlString();
if (string.IsNullOrEmpty(sourceItemValue))
{
htmlString = htmlString.Replace("value=\"\"", "value=\"\" disabled=\"disabled\" selected=\"selected\"");
}
return new MvcHtmlString(htmlString);
}
public static MvcHtmlString DisableFirstItemDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, object htmlAttributes)
{
return DisableFirstItemDropDownListFor(htmlHelper.DropDownListFor(expression, selectList, htmlAttributes), string.Empty);
}
}
You can then use this method in your .cshtml file like so:
#Html.DisableFirstItemDropDownListFor(x => x.YourFieldType, Model.YourModel, new { #class = "YourClass" })

Resources