Bootstrap-Razor-Model Checkboxes and Radio Button Groups


Ken Haggerty
Created 01/10/2019 - Updated 04/04/2019 18:25
Update 04/04/2019

The cut and paste results were confusing. I found and corrected the InputProperties type in the Radio List > The Model: > OnGet > RadioButtons = new List<InputProperties>() was not properly escaped.

Update 03/07/2019

I updated KenHaggerty.Com to Bootstrap Native and no longer require jQuery, therefore I updated the article with the vanilla JavaScript for the select all checkbox functions.

I have used sprites to make custom checkboxes and radio button groups but it involved a lot of css like span before label and a sprite image with negative positioning. Bootstrap 4 makes this easier to implement even if it may be doing something similar under the hood. What sent me searching was how to get the selected radio button on post. The answer is set each radio value and the asp-for to a model property. If you set the property on get, it will be the default selection. On post, the property equals selected value.

A little bonus. If you want a pointer on hover, add this to css:
.custom-control-input ~ .custom-control-label {
    cursor: pointer;
}

Checkboxes

First the model:

public class InputProperties
{
    public string Name { get; set; }
    public string ElementId { get; set; }
    public bool IsSelected { get; set; }
    public bool IsDisabled { get; set; }
}

[BindProperty]
public List<InputProperties> Checkboxes { get; set; }

public void OnGet()
{
    Checkboxes = new List<InputProperties>()
    {
        new InputProperties() { Name = "Debug", ElementId = "CheckboxDebug" },
        new InputProperties() { Name = "Information", ElementId = "CheckboxInformation", IsSelected=true },
        new InputProperties() { Name = "Warning", ElementId = "CheckboxWarning" },
        new InputProperties() { Name = "Error", ElementId = "CheckboxError", IsSelected=true },
        new InputProperties() { Name = "Critical", ElementId = "CheckboxCritical" }
    };
}

Now the razor part:

<form method="post">
    <div class="custom-control custom-checkbox custom-control-inline">
        <input type="checkbox" class="custom-control-input" id="CheckboxSelectAll" />
        <label class="custom-control-label" for="CheckboxSelectAll">
            Select All
        </label>
    </div>
    @for (var i = 0; i < Model.Checkboxes.Count(); i++)
    {
        <input type="hidden" asp-for="@Model.Checkboxes[i].Name" />
        <div class="custom-control custom-checkbox custom-control-inline">
            @if (Model.Checkboxes[i].IsDisabled)
            {
                <input class="custom-control-input demo" id="@Model.Checkboxes[i].ElementId" asp-for="Checkboxes[i].IsSelected" disabled />
            }
            else
            {
                <input class="custom-control-input demo" id="@Model.Checkboxes[i].ElementId" asp-for="Checkboxes[i].IsSelected" />
            }
            <label class="custom-control-label" for="@Model.Checkboxes[i].ElementId">
                @Model.Checkboxes[i].Name
            </label>
        </div>
    }
    <button type="submit" class="btn btn-primary">Post</button>
</form>

OnPost():

foreach (var cb in Checkboxes)
{
    if (cb.IsSelected)
    {
        var cbName = cb.Name;
    }
}

Finally the jQuery for Select All:

@section scripts {
    <script>
        $(function () {
            // Set '#CheckboxSelectAll' to checked if all other boxes are already checked
            $('#CheckboxSelectAll').prop('checked', $('.demo').length == $('.demo:checked').length);

            // Add click function to '#CheckboxSelectAll' to select all other boxes
            $('#CheckboxSelectAll').click(function () {
                $('.demo').prop('checked', this.checked);
            });

            // Add click function to each child checkbox
            $('.demo').click(function () {
                $('#CheckboxSelectAll').prop('checked', $('.demo').length == $('.demo:checked').length);
            });
        })
    </script>
}

Section references:

Vanilla JavaScript for Select All:

@section scripts {
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            
            // Check for '#CheckboxSelectAll' exists
            if (document.querySelector('#CheckboxSelectAll')) {

                var demoCheckboxes = document.querySelectorAll('.demo');
                var dcl = demoCheckboxes.length;
                var i = 0;

                // Set '#CheckboxSelectAll' to checked if all other boxes are already checked
                document.querySelector('#CheckboxSelectAll').checked = dcl === document.querySelectorAll('.demo:checked').length;

                // Add click function to '#CheckboxSelectAll' to select all other boxes
                document.querySelector('#CheckboxSelectAll').addEventListener('click', function () {
                    for (i = 0; i < dcl; i++) {
                        demoCheckboxes[i].checked = this.checked;
                    }
                });

                // Add click function to each child  css class demo checkbox
                for (i = 0; i < dcl; i++) {
                    demoCheckboxes[i].addEventListener('click', function () {
                        document.querySelector('#CheckboxSelectAll').checked = dcl === document.querySelectorAll('.demo:checked').length;
                    });
                }
            }
        })
    </script>
}

Radio List

The model:

public class InputProperties
{
    public string Name { get; set; }
    public string ElementId { get; set; }
    public bool IsSelected { get; set; }
    public bool IsDisabled { get; set; }
}

[BindProperty]
public List<InputProperties> RadioButtons { get; set; }

[BindProperty]
public string SelectedRadio { get; set; }

public void OnGet()
{
    RadioButtons = new List()
    {
        new InputProperties() { Name = "Debug", ElementId = "RadioDebug" },
        new InputProperties() { Name = "Information", ElementId = "RadioInformation" },
        new InputProperties() { Name = "Warning", ElementId = "RadioWarning" },
        new InputProperties() { Name = "Error", ElementId = "RadioError" },
        new InputProperties() { Name = "Critical", ElementId = "RadioCritical" }
    };

    SelectedRadio = "Warning";
}

The razor part:

<form method="post">
    @for (var i = 0; i < Model.RadioButtons.Count(); i++)
    {
        <div class="custom-control custom-radio custom-control-inline">
            @if (Model.RadioButtons[i].IsDisabled)
            {
                <input type="radio" value="@Model.RadioButtons[i].Name" class="custom-control-input" id="@Model.RadioButtons[i].ElementId"  asp-for="@Model.SelectedRadio" disabled />
            }
            else
            {
                <input type="radio" value="@Model.RadioButtons[i].Name" class="custom-control-input" id="@Model.RadioButtons[i].ElementId"  asp-for="@Model.SelectedRadio" />
            }
            <label class="custom-control-label" for="@Model.RadioButtons[i].ElementId">
                @Model.RadioButtons[i].Name
            </label>
        </div>
    }
    <button type="submit" class="btn btn-primary">Post</button>
</form>

OnPost():

var selectedRadio = SelectedRadio;

Article references:
For Bootstrap custom styling. Bootstrap 4 Custom Forms
For Razor Pages. Learn Razor Pages
For code styling in html. JavaScript code prettifier

Article Tags:

Bootstrap BootstrapNative

3 Following


Comment Count = 0

Please log in to comment or follow.

Login Register