Introduction
In this article I describe a way to create an HTML helper method using ASP.NET MVC3 to make a select
element that
can be dynamically enabled or disabled without using the "disabled
" attribute.
Background
What is the purpose of writing this article? For your understanding I will describe why it isn't feasible to use the
"disabled
" attribute in ASP.NET MVC. Disabling the HTML element by the "disabled
" attribute makes the HTTP POST request to ignore that
value altogether and not send it back to the server which would be required in certain cases. Other possibilities to make the element unselectable would be to
intercept certain mouse events but I couldn't make that work.
A possible solution to the problem is to hide the element by another element that is invisible to the user by making the
original select
element uncontrollable by the user. For this I used a
span
element that I positioned with the "position:relative
" CSS value and
encapsulated all the logic and template generation code in an HTML helper method so it can be used
with ease anytime it is needed.
The demo application
For the purpose of this article I created a demo application that will demonstrate a hypothetical usage of the solution presented. The application will be a very
simple one containing a single view page with a dropdown list of genders, a checkbox that toggles the status of the dropdown, and a submit button. Our page
will use a view model class called PersonViewModel
that will contain a property for the selected gender and a list of the possible genders.
public class PersonViewModel
{
[Required]
public String Gender {get; set;}
public IEnumerable<SelectListItem> GendersList
{
get {…}
set {…}
...
}
The selection of a concrete gender is required to submit the form to the server, therefore the user has to select one of the two values from the dropdown list.
By unchecking the checkbox the dropdown list gets disabled but only visually, and disabling it doesn’t prevent the selected value
from being sent to the server.
Hence, the purpose of this article is fulfilled.
To design the above form we can use the following HTML, JavaScript, and Razor statements:
@using (Html.BeginForm())
{
Select gender:
@Html.DisableableDropDownListFor(x => x.Gender, Model.GendersList,
"Please select", new { id = "cbGender", style = "color: green;width:120px;"})
@Html.ValidationMessageFor(x => x.Gender)
<input type="submit" value="Submit" />
}
Enable/disable gender dropdown list
<input type="checkbox" id="cb_Toggle" checked="true" />
<script type="text/javascript">
$("#cb_Toggle").click(function () {
var $Gender = $("#cbGender");
if ($(this).attr("checked"))
$Gender.enableDropDownList();
else
$Gender.disableDropDownList();
});
</script>
As you can see, we call the DisableableDropDownListFor
helper method to generate us the markup for the dropdown list and we have a fairly simple
JavaScript code that makes the actual enabling and disabling possible. All the user of this method needs to know is the
ID of the generated element on which
to invoke the two JavaScript methods:
enableDropDownList()
disableDropDownList()
In case the ID is omitted, the generated ID in markup will be the name of the property for which the dropdown list is created. In the case of this view model
that would be Gender
, but because we defined it explicitly (to cbGender
), this won’t be taken into account. If a valid value is selected from the dropdown list
and the form is submitted, the action method invoked simply returns some JavaScript code that pops up an alert message with the selected value.
The HTML helper methods are defined in a separate class library called MvcUtilities; the HtmlControlHelper
class contains two variants that can
be used for generating a markup for a disableable dropdown list. The first variant uses a string parameter to define the name of the property
of the view model class that holds the selected value, the other variant uses an expression parameter to define the property. To avoid code repetition
I created the DropDownList
method that gets invoked by each of the variants:
static IHtmlString DropDownList(
String name,
Object htmlAttributes,
Func<dictionary<string,>, String> generator)
This is the main method that creates the markup for a disableable dropdown list. Before we get down to business let’s review the markup generated
by the invocation of this method for the current Gender parameter defined by our view model class.
<select id="ddl_cbGender" class="valid"
style="color: green; width: 120px;" name="Gender"
data-val-required="The Gender field is required." data-val="true">
<option>Please select</option>
<option value="male" selected="true">male</option>
<option value="female">female</option>
</select>
As you can see, the actual dropdown list is encapsulated in a span element and this element contains another span element having the ID
of span_Hider
that serves the purpose of hiding our actual dropdown list.
The actual dropdown list will have an ID pre-pended by “ddl_” (ddl_cbGender
in this case) while the outer span element will have the
id provided by the user or the name of the property for which the dropdown list is generated otherwise.
The hiding of the element is accomplished by the JavaScript code that gets emitted by this helper method:
<script type="text/javascript">
$(document).ready(function () {
$.fn.extend({
disableDropDownList: function () {
var $ddl = $(this);
$ddl.find('#span_Hider').css('z-index', '1');
},
enableDropDownList: function () {
var $ddl = $(this);
$ddl.find('#span_Hider').css('z-index', '-1');
}
});
});
</script>
By this code we create two global methods using jQuery that toggle the status of the span_Hider
element by increasing or decreasing the z-index of it.
History
- 9 March 2012: Initial release.