1

This drop down list is sometimes populated based on a search result. When the fields is populated, it needs to be disabled, so that the selection cannot be changed. But when the page is loaded without a result populating the field, it needs to be active.

@Html.DropDownListFor(m => m.SelectedOptions, new SelectList(this.Model.Options, "Key", "Value"), "Select...", new { @id = "ddlOption" + this.ViewBag.TabId, tabindex = 5001 })

Is there a way to accomplish this?

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
jpolo
  • 35
  • 7

2 Answers2

0

You can optionally build the htmlAttributes parameter to include disabled or you would use javascript to enable/disable it

Include disabled attribute when need to and leave it out when needs to be enabled

// Conditional check for list size, if populated, then
@Html.DropDownListFor(m => m.SelectedOptions, new SelectList(this.Model.Options, "Key", "Value"), "Select...", new { @id = "ddlOption" + this.ViewBag.TabId, tabindex = 5001, disabled = true })
// else, your original code

javascript version

// The placeholder is one of the default options, so length at least equals to 1
if (document.getElementById('ddlOption').children.length > 1) {
  document.getElementById('ddlOption').disabled = true;
}
Vincent
  • 872
  • 1
  • 7
  • 13
0

In addition to @Vincent's solutions, here are other ways to accomplish enabling/disabling a control based on a condition.

The quickest solution is the first option below, using the ExpandoObject to add on the disabled attribute when the condition is met. The last option below, the custom Select Tag Helper, provides a cleaner implementation of a <select> tag that requires some processing.

All that matters is the presence of the disabled attribute

Note the following from MDN, stated in this SO post:

All that matters is that if the [disabled] attribute is present at all, regardless of its actual value, its value is considered to be true. The absence of the attribute means its value is false.

Use ExpandoObject to add disabled attribute

@{
    dynamic htmlAttributes = new System.Dynamic.ExpandoObject();
    htmlAttributes.id = "ddlOption" + this.ViewData["TabId"];
    htmlAttributes.tabindex = 5001;
    htmlAttributes.title = "Options";
    if (this.Model.Options.Count() > 1) { htmlAttributes.disabled = "disabled"; }
}
@Html.DropDownListFor(m => m.SelectedOptions,
new SelectList(this.Model.Options, "Key", "Value"),
"Select...",
(object)htmlAttributes)

Custom HTML Helper chained to DropDownListFor

See this SO post. The custom HTML Helper allows for a cleaner implementation of C#/Razor syntax in your Razor page. The code below uses a custom HTML Helper named .DisableIfFilled(this.Model.Options.Count()) that takes one parameter.

@Html.DropDownListFor(m => m.SelectedOptions,
    new SelectList(this.Model.Options, "Text", "Value"),
    "Select...",
    new { @id = "ddlOption" + this.ViewData["TabId"], tabindex = 5001, title="Options" }).DisableIfFilled(this.Model.Options.Count())

DisableHtmlControlExtension.cs

using Microsoft.AspNetCore.Html;

namespace WebApplication1.Helpers
{
    public static class DisableHtmlControlExtension
    {
        public static IHtmlContent DisableIfFilled(
            this IHtmlContent htmlContent, int numOfOptions)
        {
            if (numOfOptions > 1)
            {
                StringWriter writer = new System.IO.StringWriter();
                htmlContent.WriteTo(writer, System.Text.Encodings.Web.HtmlEncoder.Default);
                string html = writer.ToString();

                const string disabled = "\"disabled\"";
                html = html.Insert(html.IndexOf(">",
                  StringComparison.Ordinal), " disabled= " + disabled);
                return new HtmlString(html);
            }

            return htmlContent;
        }
    }
}

Add the following to the Razor page:

@using WebApplication1.Helpers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Custom Select Tag Helper

Instead of the DropDownListFor HTML Helper, the Select Tag Helper provides clearer readability for <select> tag output.

 <select asp-for="SelectedOptions" asp-items="@this.Model.Options"
        class="ctrl" tabindex=5001 title="Options" disableif>
    <option value="">Select...</option>
</select>

DisableIfSelectTagHelper.cs

using Microsoft.AspNetCore.Razor.TagHelpers;

namespace WebApplication1.Helpers
{
    [HtmlTargetElement("select", Attributes = "disableif")]
    public class DisableIfSelectTagHelper : TagHelper
    {
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            // https://rion.io/2017/04/27/extending-tag-helpers-in-asp-net-core-applications/
            base.Process(context, output);

            string content = output.PostContent.GetContent();
            // Process only if more than on one instance of the
            // '<option>' tag exists.
            // https://stackoverflow.com/questions/17502488/how-to-identify-if-a-string-contains-more-than-one-instance-of-a-specific-charac
            if (content.IndexOf("<option") != content.LastIndexOf("<option"))
            {
                output.Attributes.Add("disabled", null);
            }
            // Remove custom 'disableif' attribute that's used
            // to trigger the tag helper.
            TagHelperAttribute attr = output.Attributes.First(t => t.Name == "disableif");
            output.Attributes.Remove(attr);
        }
    }
}

Add the following to the Razor page:

@using WebApplication1.Helpers
@addTagHelper WebApplication1.Helpers.DisableIfSelectTagHelper, WebApplication1
Dave B
  • 1,105
  • 11
  • 17