Search code examples
asp.netasp.net-mvctwitter-bootstrapcheckboxmvc-editor-templates

How to create an EditorTemplate for bootstrap checkbox?


I am working with a bootstrap template and its checkbox template is like this:

<div class="checkbox">
    <label>
        <input type="checkbox" class="checkbox style-1" checked="checked">
        <span>Checkbox 1</span>
    </label>
</div>

I need an MVC EditorTemplate for boolean values to use this template. MVC CheckBoxFor default template is not like this template, it has another hidden input field to hold data and there is no span to show checkbox icon (it uses a default icon not stylable by css).

MVC CheckBoxFor default template :

<input checked="checked" data-val="true" data-val-required="required." id="IsActive" 
       name="IsActive" type="checkbox" value="true">
<input name="IsActive" type="hidden" value="false">

I tried many ways to do this with no success. For example if I use a conditional template like below, it does not return value after submit.

My Boolean EditorTemplate:

@model Boolean?
<div class="checkbox">
    <label>
        @if (Model.Value)
        {
            <input id="@ViewData.TemplateInfo.GetFullHtmlFieldId("")" name="@ViewData.TemplateInfo.GetFullHtmlFieldId("")"
                   type="checkbox" class="checkbox style-1" checked="checked" value="true" />
        }
        else
        {
            <input id="@ViewData.TemplateInfo.GetFullHtmlFieldId("")" name="@ViewData.TemplateInfo.GetFullHtmlFieldId("")"
                   type="checkbox" class="checkbox style-1" value="false" />
        }
        <span>@Html.LabelFor(m => m)</span>
    </label>
</div>

Can anyone help please?

Update:

A part of css codes relevent to checkbox icon :

label input[type=checkbox].checkbox + span:before {
    font-family: FontAwesome;
    font-size: 12px;
    border-radius: 0;
    content: " ";
    display: inline-block;
    text-align: center;
    vertical-align: middle;
    padding: 1px;
    height: 12px;
    line-height: 12px;
    min-width: 12px;
    margin-right: 5px;
    border: 1px solid #bfbfbf;
    background-color: #f4f4f4;
    font-weight: 400;
    margin-top: -1px;
}

label input[type=checkbox].checkbox + span:before {
    content: " ";
}

label input[type=checkbox].checkbox:checked + span:before {
    content: "";
    color: #2e7bcc;
}

label input[type=checkbox].checkbox:checked + span {
    font-weight: 700;
}

Solution

  • The CheckBoxFor() method generate 2 inputs to ensure a value is posted back (unchecked checkboxes to not submit a value so the hidden input ensures false is submitted), and you should not attempt to change this behavior. Your attempt at an EditorTempate could not work for a number of reasons including a checkbox (which has 2 states) cannot bind to a nullable bool (which has 3 states) and your else block means that a vale of false will always be submitted, even if the checkbox is checked.

    Instead, use the CheckBoxFor() method, but adjust your css selectors

    <div class="checkbox">
        <label>
            @Html.CheckBoxFor(m => m.IsActive, new { @class = "checkbox style-1" })
            <span>Checkbox 1</span>
        </label>
    </div>
    

    will generate

    <div class="checkbox">
        <label>
            <input type="checkbox" name="IsActive" class="checkbox style-1" ... value="true">
            <input type="hidden" name="IsActive" value="false">
            <span>Checkbox 1</span>
        </label>
    </div>
    

    So your current selector

    label input[type=checkbox].checkbox + span:before {
    

    which gets the span element placed immediately after the checkbox element needs to be changed to

    label input[type=checkbox].checkbox ~ span:before {
    

    And ditto for the other selectors (i.e. change + to ~). The ~ selector matches the second element if it is preceded by the first, and both share a common parent (refer General sibling selectors)