ETFairfax
ETFairfax

Reputation: 3814

Html.DropDownList - Disabled/Readonly

What option do I need to set to make a drop down box readonly when using MVCs Html.DropDownList?

I've tried things like....

Html.DropDownList("Types", Model.Types, new { _Enabled = "false" })

...and many different things along this line; alas no joy!

I thought this would be an easy.....and it probably is!

Upvotes: 84

Views: 238087

Answers (15)

Gary Mason
Gary Mason

Reputation: 9

You can set the select as readonly and then run some jquery to disable the options except the selected value. You cant change the value and it's included when the form is submitted.

$(document).ready(function () {
    $('select option').removeAttr('disabled');
    $('#readonlyTest').find('select[readonly] option').not('select[readonly] option[selected]').attr('disabled', 'disabled');
});

$('#submitButton').click(function(e) {
    var formData = $('form').serialize();
  $('#formData').html(formData);
});
body {
  margin: 50px;
}
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
  <div class="form-group">
    <label for="scopeReadonlyNoJs">Scope Readonly No Js</label>
    <select class="form-control" id="scopeReadonlyNoJs" name="scopeReadonlyNoJs" readonly="readonly">
      <option value="">Select..</option>
      <option selected="selected" value="readonlyNoJsScopeValue1">Scope Value 1</option>
      <option value="readonlyNoJsScopeValue2">Scope Value 2</option>
    </select>
    <small id="scopeReadonlyNoJsHelp" class="form-text text-muted">This is read only and no js is applied. It looks disabled but you can change the values.</small>
  </div>
  <div id="readonlyTest" class="form-group">
    <label for="scopeReadonly">Scope Readonly</label>
    <select class="form-control" id="scopeReadonly" name="scopeReadonly" readonly="readonly">
      <option value="">Select..</option>
      <option selected="selected" value="readonlyScopeValue1">Scope Value 1</option>
      <option value="readonlyScopeValue2">Scope Value 2</option>
    </select>
    <small id="scopeReadonlyHelp" class="form-text text-muted">This is read only and is disabled via js by disabling the options except the selected one.</small>
  </div>
  <div class="form-group">
    <label for="scopeDisabled">Scope Disabled</label>
    <select class="form-control" id="scopeDisabled" name="scopeDisabled" disabled="disabled">
      <option value="">Select..</option>
      <option selected="selected" value="disabledScopeValue1">Scope Value 1</option>
      <option value="disabledScopeValue2">Scope Value 2</option>
    </select>
    <small id="scopeDisabledHelp" class="form-text text-muted">This is disabled and wont be posted.</small>
  </div>
  <button id="submitButton" type="button">
    Submit
  </button>
</form>
<p id="formData">
</p>

Upvotes: 0

Alfrodop
Alfrodop

Reputation: 1

try with @disabled and jquery, in that way you can get the value on the Controller.

Html.DropDownList("Types", Model.Types, new {@class = "your_class disabled", @disabled= "disabled" })

Add a class called "disabled" so you can enabled by searching that class(in case of multiples disabled fields), then you can use a "setTimeout" in case of not entering controller by validation attributes

<script>

  function clickSubmit() {
    $("select.disabled").attr("disabled", false);
    setTimeout(function () {
        $("select.disabled").attr("disabled", true);
    }, 500);
  }
</script>

submit button like this.

 <button type="submit" value="Submit" onclick="clickSubmit();">Save</button>

in case of inputs, just use @readonly="readonly"

@Html.TextBoxFor("Types",Model.Types, new { @class = "form-control", @readonly= "readonly" })

Upvotes: 0

You could use this approach

Disabling all the options except the selected one:

<select>
    <option disabled>1</option>
    <option disabled>2</option>
    <option selected>3</option>
</select>

This way the dropdown still submits, but the user can not select another value.

With jQuery

<script>
    $(document).ready(function () {
        $('#yourSelectId option:not(:selected)').prop("disabled", true);
    });
</script>

Upvotes: 0

Antonio Bakula
Antonio Bakula

Reputation: 20693

For completeness here is the HTML Helper for DropDownListFor that adds enabled parameter, when false select is disabled. It keeps html attributes defined in markup, or it enables usage of html attributes in markup, it posts select value to server and usage is very clean and simple.

Here is the code for helper:

public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, object htmlAttributes, bool enabled)
{
  if (enabled)
  {
    return SelectExtensions.DropDownListFor<TModel, TProperty>(html, expression, selectList, htmlAttributes);
  }

  var htmlAttributesAsDict = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
  htmlAttributesAsDict.Add("disabled", "disabled");
  string selectClientId = html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(ExpressionHelper.GetExpressionText(expression));
  htmlAttributesAsDict.Add("id", selectClientId + "_disabled");

  var hiddenFieldMarkup = html.HiddenFor<TModel, TProperty>(expression);
  var selectMarkup = SelectExtensions.DropDownListFor<TModel, TProperty>(html, expression, selectList, htmlAttributesAsDict);
  return MvcHtmlString.Create(selectMarkup.ToString() + Environment.NewLine + hiddenFieldMarkup.ToString());
}

and usage, goal is to disable select if there is just one item in options, markup:

@Html.DropDownListFor(m => m.SomeValue, Model.SomeList, new { @class = "some-class" }, Model.SomeList > 1)

And there is one even more elegant HTML Helper example, no post support for now (pretty straight forward job, just use HAP and add hidden input as root element sibling and swap id's):

public static MvcHtmlString Disable(this MvcHtmlString previous, bool disabled, bool disableChildren = false)
{
  if (disabled)
  {
    var canBeDisabled = new HashSet<string> { "button", "command", "fieldset", "input", "keygen", "optgroup", "option", "select", "textarea" };
    var doc = new HtmlDocument();
    doc.LoadHtml(previous.ToString());
    var rootElements = doc.DocumentNode.Descendants().Where(
      hn => hn.NodeType == HtmlNodeType.Element && 
      canBeDisabled.Contains(hn.Name.ToLower()) && 
      (disableChildren || hn.ParentNode.NodeType == HtmlNodeType.Document));

    foreach (var element in rootElements)
    {
      element.SetAttributeValue("disabled", "");
    }
    string html = doc.DocumentNode.OuterHtml;
    return MvcHtmlString.Create(html);
  }
  return previous;
}

For example there is a model property bool AllInputsDisabled, when true all html inputs should be disabled:

@Html.TextBoxFor(m => m.Address, new { placeholder = "Enter address" }).Disable(Model.AllInputsDisabled)

@Html.DropDownListFor(m => m.DoYou, Model.YesNoList).Disable(Model.AllInputsDisabled)

Upvotes: 0

Michael
Michael

Reputation: 31

A tip that may be obvious to some but not others..

If you're using the HTML Helper based on DropDownListFor then your ID will be duplicated in the HiddenFor input. Therefore, you'll have duplicate IDs which is invalid in HTML and if you're using javascript to populate the HiddenFor and DropDownList then you'll have a problem.

The solution is to manually set the ID property in the htmlattributes array...

@Html.HiddenFor(model => model.Entity)

@Html.EnumDropDownListFor(
  model => model.Entity, 
  new { 
         @class = "form-control sharp", 
         onchange = "", 
         id =` "EntityDD", 
         disabled = "disabled" 
       }
)

Upvotes: 3

cagedwhale
cagedwhale

Reputation: 51

I had to disable the dropdownlist and hide the primary ID

<div class="form-group">
        @Html.LabelFor(model => model.OBJ_ID, "Objs", htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownList("OBJ_ID", null, htmlAttributes: new { @class = "form-control", @disabled = "disabled"})
            @Html.HiddenFor(m => m.OBJ_ID)
            @Html.ValidationMessageFor(model => model.OBJ_ID, "", new { @class = "text-danger" })
        </div>
    </div>

Upvotes: 3

Roger Tello
Roger Tello

Reputation: 59

Html.DropDownList("Types", Model.Types, new { @disabled = "disabled" }) @Html.Hidden(Model.Types) and for save and recover the data, use a hidden control

Upvotes: 0

Andrew Day
Andrew Day

Reputation: 607

@Html.DropDownList("Types", Model.Types, new { @disabled = "" })

Works

Upvotes: 1

kirk
kirk

Reputation: 1007

Put this in style

 select[readonly] option, select[readonly] optgroup {
        display: none;
    }

Upvotes: 2

Tharanga
Tharanga

Reputation: 57

I've create this answer after referring above all comments & answers. This will resolve the dropdown population error even it get disabled.

Step 01

Html.DropDownList("Types", Model.Types, new {@readonly="readonly"})

Step 02 This is css pointerevent remove code.

<style type="text/css">
    #Types {
        pointer-events:none;
    }
</style>
Then you can have expected results

Tested & Proven

Upvotes: -1

I just do this and call it a day

Model.Id > -1 ? Html.EnumDropDownListFor(m => m.Property, new { disabled = "disabled" }) : Html.EnumDropDownListFor(m => m.Property)

Upvotes: 1

BGStack
BGStack

Reputation: 1144

Regarding the catch 22:

If we use @disabled, the field is not sent to the action (Mamoud) And if we use @readonly, the drop down bug still lets you change the value

Workaround: use @disabled, and add the field hidden after the drop down:

@Html.HiddenFor(model => model.xxxxxxxx)

Then it is truly disabled, and sent to the to the action too.

Upvotes: 104

Tadas Šukys
Tadas Šukys

Reputation: 4220

Try this

Html.DropDownList("Types", Model.Types, new { @disabled = "disabled" })

Upvotes: 166

Muhammad Mubashir
Muhammad Mubashir

Reputation: 1657

<script type="text/javascript">
$(function () {
        $(document) .ajaxStart(function () {
                $("#dropdownID").attr("disabled", "disabled");
            })
            .ajaxStop(function () {
                $("#dropdownID").removeAttr("disabled");

            });

});
</script>

Upvotes: 7

Bruce
Bruce

Reputation: 53

Or you can try something like this:

Html.DropDownList("Types", Model.Types, new { @readonly = "true" })

Upvotes: 2

Related Questions