Search code examples
asp.net-mvcasp.net-coreasp.net-core-2.0tag-helpers

ASP.NET Core Tag Helper Checkbox does not save unchecked value


I'm adding a checkbox in an MVC form with Tag Helpers:

<div class="form-group">
    <label asp-for="@Model.Billable"></label>
    <input asp-for="@Model.Billable" type="checkbox" />
    <input asp-for="@Model.Billable" type="hidden" />
</div>

When the user changes the value to Checked from Unchecked, the form value passed back to the controller is True - perfect.

However, if the value of the checkbox starts as Checked and the user changes it to Unchecked, the form value passed back to the controller is still True???


Solution

  • When the type is checkbox, the input tag helper creates a hidden element for the checkbox for you with the same name. If you check the view source of the page, you can see that

    <input name="Billable" type="hidden" value="false">
    

    When user enable/check the checkbox and submit the form, it will send 2 form data item, one for the actual check box with value True and the second for the hidden input with value False.

    If you inspect the network traffic (Chrome devtools->network), you can see this

    Billable: true
    Billable: false
    

    When model binder uses this data, it will give precedence to the True value and map that to your boolean property.

    When user uncheck the checkbox and submit the form, it will send only one form data element, just the one for the hidden input element with value false and model binder will set false value for your boolean proeprty of your action method parameter.

    Your current code is generating the checkbox element and an additional hidden input element with the same name Billable. So basically it will render 2 input elements(1 checkbox,1 hidden element which the helper created and 1 you explicitly created). When user unchecks the checkbox, It will send True for your explicitly created one and false for the one created by the tag helper.

    If you inspect the network traffic (Chrome devtools->network), you can see this

    Billable: True
    Billable: false
    

    Model binder will use this information and map the value True to your Billable property of your view model.

    The solution is to remove the extra hidden element and rely on the one created by tag helper.

    <div class="form-group">
        <label asp-for="@Model.Billable"></label>
        <input asp-for="@Model.Billable" type="checkbox" />
    </div>