I have populated a selectlist in my viewmodel in the form:
DeliveryCentres = new SelectList(deliveryCentres, "Id", "CentreName");
in my View I have:
#Html.DropDownListFor(m => m.DeliveryCentreId, Model.DeliveryCentres, "-- Not Required --");
The problem is that on display the dropdown defaults to the first item in the list as opposed to the -- Not Required -- value.
How do I make this the default?
#Stephen Muecke has answered the question. I just needed to leave the ID as null in the ViewModel before rendering.
From comments:
The selected value will be whatever the value of DeliveryCentreId is. If its value is null or does not match one of the option values, then the "Not Required" option will be selected
Related
I have read many articles about using MultiSelectList and have yet to understand what is going wrong with my DropDownListFor. I have a ListBoxFor with the same View, ViewModel and data that works fine. I want to use the DropDownListFor because of its optionLabel parameter that ListBoxFor doesn't have.
When the View is first loaded, both the DropDownListFor and the ListBoxFor show the multiple selected items.
When the Submit button is clicked, the selected items collection is posted back to the Controller action okay and the view is refreshed with the ListBoxFor still showing both selected items but the DropDownListFor is only showing one selected item.
The controller action is constructing the MultiSelectList like this:
vm.TasksFilterGroup.Assignees = new MultiSelectList(employees, "Id", "FullName", new string[] { "51b6f06a-e04d-4f98-88ef-cd0cfa8a2757", "51b6f06a-e04d-4f98-88ef-cd0cfa8a2769" });
The View code looks like this:
<div class="form-group">
<label>ListBoxFor</label>
#Html.ListBoxFor(m => m.TasksFilterGroup.SelectedAssignees, Model.TasksFilterGroup.Assignees, new { #class = "form-control", multiple = "multiple" })
</div>
<div class="form-group">
<label>DropDownListFor</label>
#Html.DropDownListFor(m => m.TasksFilterGroup.SelectedAssignees, Model.TasksFilterGroup.Assignees, new { #class = "form-control", multiple = "multiple" })
</div>
Why does the DropDownListFor lose the multiple selection after Submit but the ListBoxFor doesn't?
As the names of the methods imply, DropDownListFor() is for creating a <select> (to select 1 option) and ListBoxFor() is for creating a <select multiple> (to select multiple options). While both methods share a lot of common code, they do produce different results.
Adding the multiple="multiple" attribute changes the display, but it does not change the functionality of the code executed by these methods.
If you inspect the source code, you will note that all the overloads of DropDownListFor() ultimately call the private static MvcHtmlString DropDownListHelper() method, and similarly ListBoxFor() ultimately calls the private static MvcHtmlString ListBoxHelper() method.
Both these methods call the private static MvcHtmlString SelectInternal() method, but the difference is that DropDownListHelper() passes allowMultiple = false while the ListBoxHelper() passes allowMultiple = true.
Within the SelectInternal() method, the key line of code is
object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string));
The value of defaultValue is then used when building html for the <option> elements and is used to set the selected attribute(s).
In the case of ListBoxFor(), the value of defaultValue will be the array defined by your SelectedAssignees property. In the case of DropDownListFor() it returns null because the value of your property cannot be cast to string (its an array).
Because defaultValue is null, none of the <option> elements have the selected attribute set and you lose model binding.
As a side note, if you were to set the values of SelectedAssignees in the GET method before you pass the model to the view, you will see that none of them are selected when using DropDownListFor() for the same reasons described above.
Note also that the code for generating the SelectList should just be
vm.TasksFilterGroup.Assignees = new SelectList(employees, "Id", "FullName" });
There is no point setting the 3rd parameter when using either the DropDownListFor() or ListBoxFor() methods because its the value of the property your binding to (SelectedAssignees) that determines which options are selected (the 3rd parameter is ignored by the methods). If you want the options matching those Guid values to be selected, then in the GET method, use
vm.TasksFilterGroup.SelectedAssignees= new string[]{ "51b6f06a-e04d-4f98-88ef-cd0cfa8a2757", "51b6f06a-e04d-4f98-88ef-cd0cfa8a2769" };
I was wondering if anyone has ever experienced a problem like I'm currently having.
Controller:
_OpsAdminViewModel.userRoleID = _OpsAdminViewModel.retrieveHighestUserRoleGuidFromUserID(id.Value);
_OpsAdminViewModel.ActiveRoleList = _OpsAdminViewModel.GetActiveRoles();
_OpsAdminViewModel.UserRoleSelectList = new SelectList(_OpsAdminViewModel.ActiveRoleList, "RoleID", "RoleName", _OpsAdminViewModel.userRoleID);
View:
#Html.DropDownListFor(model=>model.selectedRoleID, Model.UserRoleSelectList)
Now, here is where it gets very odd. When I place a break on the Controller's Return line or the View's DropDownListFor line, I literally see that the value I want to have selected should be selected. Expanding the UserRoleSelectList object, reveals the correct "SelectedValue" ID and in the "Results View", the correct value has a "True" for selected. However, when the page is rendered, the pull-down menu is displaying the 0-position element of the pull-down menu.
Model binding works by binding to the value of your property. When your use DropDownListFor() the method internally builds a new IEnumerable<SelectListItem> and sets the Selected property based on the value of your property. In your case, the value of selectedRoleID does not match the value of one of the options so the first option is selected (because something has to be).
Set the value of selectedRoleID in the GET method before you pass the model to the view
model.selectedRoleID = _OpsAdminViewModel.userRoleID;
return View(model);
and delete the last parameter in your SelectList constructor since its pointless.
In my model class for view, I have an enum type property SubjectType:
[Required(ErrorMessage = "This field is required.")]
public SubjectType SubjectType { get; set; }
I would like to create drop-down list for this property. But by default I would like it to be set to null so that user has to choose something, and the validation message will be shown if he would try to submit form without choosing any option.
What is the best approach to achieve this?
I was trying to change SubjectType property to nullable, and setting the default value to null, but the validation still passed on this field (somehow) and the form was submitted to the server. By default the value of this field was set to the first value from enum definition. No JavaScript allowed, I'd like to keep everything in code-behind. I will be grateful for any advice.
so far i render it this way:
#Html.DropDownList("SubjectType", EnumHelper.GetSelectList(typeof(SubjectType)))
#Html.LabelFor(model => model.SubjectType)
#Html.ValidationMessageFor(model => model.SubjectType)
You are able to solve problem doing this:
Change submit button to button with onclick action, then validate it in javascript and if form and this enum field is valid submit the form using jQuery.
Edit: I think the problem was three fold. first your attribute is named SubjectType but your dropdown is named Type so it cannot be bound to SubjectType.
second, Apparently you have to use #HTML.dropdownlistfor(). I did a viewsource with my two different versions dropdown and dropdownlistfor and dropdownlistfor is the only one that adds the validation classes (see below)
third, we needed to add the option label parameter "Select a Type" as a default value. I'm sure it'll work for you now.
In Model:
[Required(ErrorMessage = "Error!")]
public string SubjectType{ get; set; }
In Html:
#Html.DropDownListFor(m => m.SubjectType, new SelectList(Enum.GetNames(typeof(SubjectType))), "Select a Type", new { #class = "pretty" } )
now I see you have a helper that furnishes an enumerable I think that will be just fine if you replace my second param with that.
Dropdownlist vs DropdownlistFor Rendering of Select Element:
DropdownList:
<select name="SubjectType" class="pretty" id="SubjectType">...</select>
DropdownListFor:
<select name="SubjectType" class="pretty" id="SubjectType" data-val-required="Error!" data-val="true">...</select>
As you can see data-val-required and data-val classes are missing when doing a simple dropdown thus not turning on validation FOR that attribute. Sorry for all the pain of getting here. Don't forget to mark me right if it works.
I'm trying to generate a dropdownlist in my view, like the one below except I want my option label ("Please select...") to have a value of -1 as blank is already occupied by another option. Is there anyway to do this without adding it to the select list in my controller or view model, or creating a new html helper?
<%: Html.DropDownListFor(model => model.stuff.Id, new SelectList(Model.stuff, "Id", "Name"), "Please select...")%>
Thanks
I want my option label ("Please select...") to have a value of -1
You cannot do this out of the box with the DropDownListFor helper. It will always use blank for this value. You have two possibilities:
Write a custom helper
Add it manually to the collection
Actually you have a third possibility which IMHO is the best and what I would recommend you:
Don't use blank as values. This should be reserved for the Please Select default value. It doesn't seem logical to use blank as the value of something that the user can actually select. You might also have problems with the validation.
Just use the Concat method to add a new item to the SelectList after you get your values from the database. Then set the value to 0 and text to "Please Select".
var selectList = new SelectList(types.Concat( new[]{new MediaType() {MediaTypeId = 0, Type = "Please select"}})
, "mediatypeid", "type");
I am trying set up a simple dropdown list but I dont seem to be able to get it to bind to the Model.
I am using Asp.Net MVC and nhibernate.
My dropdown list is declared like so:
<%= Html.DropDownListFor(model => model.Project, (IEnumerable<SelectListItem>)ViewData["Projects"], " -- Select -- ", new { name = "Project" })%>
I set up the select list like so:
ViewData["Projects"] = new SelectList(projectRepository.GetAll(), "EntityGUID", "Name", editEntity.Project);
This seems to bind the select list to the Dropdown fine, but the SelectedValue is not set.
it shows up as the default --- Select ---
Also when I save this data, the dropdown does not bind to the model, I have to manually set the object like so to save it:
entity.Project = projectRepository.GetById(new Guid(Request["Project"].ToString()));
I believe I have take the correct messures to have this item bind directly to my model.
Is there something I am missing here?
Many thanks for your time,
Rod
OMG I found the problem........
It has taken me 3 days to turn:
<%= Html.DropDownListFor(model => model.Aspect, (IEnumerable<SelectListItem>)ViewData["AspectTypes"])%>
into:
<%= Html.DropDownListFor(model => model.Aspect.EntityGUID, (IEnumerable<SelectListItem>)ViewData["AspectTypes"])%>
model.Aspect**.EntityGUID**
I had to bind the drop down to the objects guid, not the object itself.
Doh....Im feeling the pain, much work to catch up on.
Thanks for your time.
This is just a hunch since your code looks good to me but I don't think you need to include the forth parameter when defining your SelectList. Setting that field might be distrupting the normal flow of things (overriding your model binding) and I have never bound a DropDownList and had the SelectList's SelectedValue set.
Try removing that and see how it goes.
SelectList(projectRepository.GetAll(), "EntityGUID", "Name");
Also I asked a question a while back regarding how to implement DropDownList in MVC2 that you might find useful.