MVC3 EditorTemplate for a nullable boolean using RadioButtons

前端 未结 6 1870
深忆病人
深忆病人 2020-12-05 10:55

I have a property on one of my objects that is a nullable boolean, I want my logic to have true represent Yes, false to be No and null to be N/A. Now because I am going to h

相关标签:
6条回答
  • 2020-12-05 11:19

    The problem is that you need to set the checked attribute because the Html.RadioButtonFor does not check a radio button based on a nullable bool (which appears to be a flaw).

    Also by putting the radio buttons inside of the label tag, you can select value by clicking the label.

    Shared/EditorTemplates/Boolean.cshtml

    @model bool?
    <label>
        <span>n/a</span>
        @Html.RadioButtonFor(x => x, "", !Model.HasValue ? new { @checked=true } : null) 
    </label>
    <label>
        <span>Yes</span>
        @Html.RadioButtonFor(x => x, true, Model.GetValueOrDefault() ? new { @checked = true } : null)
    </label>
    <label>
        <span>No</span>
        @Html.RadioButtonFor(x => x, false, Model.HasValue && !Model.Value ? new { @checked = true } : null)
    </label>
    
    0 讨论(0)
  • 2020-12-05 11:19

    You just need to handle the special null case like so:

    <label class="radio">
      @Html.RadioButtonFor(x => x.DefaultBillable, "", new { @checked = !this.Model.DefaultBillable.HasValue })
      Not set
    </label>
    <label class="radio">
      @Html.RadioButtonFor(x => x.DefaultBillable, "false")
      Non-Billable
    </label>
    <label class="radio">
      @Html.RadioButtonFor(x => x.DefaultBillable, "true")
      Billable
    </label>
    
    0 讨论(0)
  • 2020-12-05 11:23
    @model bool?
    <div data-ui="buttonset">
    @{
        Dictionary<string, object> yesAttrs = new Dictionary<string, object>(); 
        Dictionary<string, object> noAttrs = new Dictionary<string, object>(); 
        Dictionary<string, object> nullAttrs = new Dictionary<string, object>(); 
    
        yesAttrs.Add("id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "Yes");
        noAttrs.Add("id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "No");
        nullAttrs.Add("id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "NA");
    
        if (Model.HasValue && Model.Value)
        {
            yesAttrs.Add("checked", "checked");
        }
        else if (Model.HasValue && !Model.Value)
        {
            noAttrs.Add("checked", "checked");
        }
        else
        {
            nullAttrs.Add("checked", "checked");
        }
    }
    
    @Html.RadioButtonFor(x => x, "true", yesAttrs) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))Yes">Yes</label>
    @Html.RadioButtonFor(x => x, "false", noAttrs) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))No">No</label>
    @Html.RadioButtonFor(x => x, "null", nullAttrs) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))NA">N/A</label>
    </div>
    
    0 讨论(0)
  • 2020-12-05 11:26

    How about some extension method fun to keep that "one line to rule them all". :-)

    public static class DictionaryHelper
    {
        // This returns the dictionary so that you can "fluently" add values
        public static IDictionary<TKey, TValue> AddIf<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, bool addIt, TKey key, TValue value)
        {
            if (addIt)
                dictionary.Add(key, value);
            return dictionary;
        }
    }
    

    And then in your template file you simply change the signature of how you are adding the additional parameters including the checked="checked" attribute to the element.

    @model bool?
    <div data-ui="buttonset">
    @Html.RadioButtonFor(x => x, true, new Dictionary<string,object>()
        .AddIf(true, "id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "Yes")
        .AddIf(Model.HasValue && Model.Value, "checked", "checked")
    ) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))Yes">Yes</label>
    
    @Html.RadioButtonFor(x => x, false, new Dictionary<string,object>()
        .AddIf(true, "id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "No")
        .AddIf(Model.HasValue && !Model.Value, "checked", "checked")
    ) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))No">No</label>
    
    @Html.RadioButtonFor(x => x, "null", new Dictionary<string,object>()
        .AddIf(true, "id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "NA")
        .AddIf(!Model.HasValue, "checked", "checked")
    ) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))NA">N/A</label>
    </div>
    
    0 讨论(0)
  • 2020-12-05 11:44

    You can use a @helper to simplify the accepted answer:

    @model bool?
    
    <div data-ui="buttonset">
        @Radio(true,  "Yes", "Yes")
        @Radio(false, "No",  "No")
        @Radio(null,  "N/A", "NA")
    </div>
    
    @helper Radio(bool? buttonValue, string buttonLabel, string buttonId)
    {
        Dictionary<string, object> attrs = new Dictionary<string, object>(); 
    
        // Unique button id
        string id = ViewData.TemplateInfo.GetFullHtmlFieldId("") + buttonId;
    
        attrs.Add("id", id);
    
        // Check the active button
        if (Model == buttonValue)
        {
            attrs.Add("checked", "checked");
        }
    
        @Html.RadioButtonFor(m => m, buttonValue, attrs) <label for="@id">@buttonLabel</label>
    }
    
    0 讨论(0)
  • 2020-12-05 11:45

    using Canvas example above I built a customization model and view so you can control the values via a model and edit them in code, bools aren't always a yes/no/(n/a) so Here's how it looks in MVC5.

    using a generic model for the nullable bool

    public class Customisable_NullableRadioBool
        {
            public bool? Result { get; set; }
            public string TrueLabel { get; set; }
            public string FalseLabel { get; set; }
            public string NullLabel { get; set; }
            public string AttributeTitle { get; set; }
        }
    

    Here's the CSHTML to be stored in: ~/Views/Shared/EditorTemplates/Customisable_NullableRadioBool.cshtml

    @model Customisable_NullableRadioBool
    @Model.AttributeTitle<br />
    <div class="control-group">
        <label>
            @Html.RadioButtonFor(x => x.Result, "", !Model.Result.HasValue ? new { @checked = true } : null)
            <span>@Model.NullLabel</span>
        </label>
        <br />
        <label>
            @Html.RadioButtonFor(x => x.Result, true, Model.Result.GetValueOrDefault() ? new { @checked = true } : null)
            <span>@Model.TrueLabel</span>
        </label>
        <br />
        <label>
            @Html.RadioButtonFor(x => x.Result, false, Model.Result.HasValue && !Model.Result.Value ? new { @checked = true } : null)
            <span>@Model.FalseLabel</span>
        </label>
    </div>
    

    And then you can reference the generic class and the editor template through the rest of your project and render the editor template like this.

    @Html.EditorFor(m => m.YourCustomisable_NullableBool, "Customisable_NullableRadioBool")
    

    And the rendered output examples

    0 讨论(0)
提交回复
热议问题