Search code examples
asp.net-coremvc-editor-templatestag-helpersasp.net-core-tag-helpers

How can I make a fancy checkbox template for ASP.NET Core?


I've got a lot of booleans in my model, and we're using Bootstrap, so for every boolean property I'm copy/paste refactoring:

<div class="form-group">
    <div class="custom-control custom-checkbox ">
        <input asp-for="IsFoo"/>
        <label asp-for="IsFoo"></label>
    </div>
</div>

... but that's dumb. I tried adding this to Views/Shared/EditorTemplates/bool.cshtml:

@model bool?
<div class="form-group">
    <div class="custom-control custom-checkbox ">
        <input asp-for="@Model"/>
        <label asp-for="@ViewData.TemplateInfo.FormattedModelValue"></label>
    </div>
</div>

... and calling it with @Html.EditorFor(m => m.IsFoo) but all I'm getting back is a plain input element from the default template.

  1. what am I doing wrong here name the template 'boolean.cshtml'
  2. is ViewData.TemplateInfo.FormattedValue the right value to get the Display(Name="xxx") Attribute from the property nope. ViewData.ModelMetadata.DisplayName
  3. is there some new & improved version instead of Editor Templates in ASP.NET Core that I should be using (like Tag Helpers?) instead of the "old" way, and if so, how do I go about it?

Solution

  • Use the <partial> tag-helper:

    <partial name="MyCheckbox" for="IsFoo" />
    

    It works with binding properties too:

    class MyModel
    {
        public List<MyCheckboxModel> MyCheckboxList { get; set; }
    }
    
    class MyCheckboxModel
    {
        public Boolean IsChecked { get; set; }
    }
    
    @for( Int32 i = 0; i < this.Model.MyCheckboxList.Count; i++ )
    {
        <partial name="MyCheckbox" for="MyCheckboxList[i]"
    }
    

    Change your partial-view to:

    @model MyCheckboxModel
    <div class="form-group">
        <div class="custom-control custom-checkbox">
            <input asp-for="@Model"/>
            <label asp-for="@Model"></label>
        </div>
    </div>
    

    The for="" attribute causes the name/id/binding context in the partial to match the named property, so ASP.NET will do the magic to ensure that <input asp-for="@Model" /> will correspond to Model.MyCheckBoxList[0] and so on.