DEV Community

Cover image for ASP.NET Core/Razor pages working with Checkboxes
Karen Payne
Karen Payne

Posted on

ASP.NET Core/Razor pages working with Checkboxes

There are two lessons, how to create a list of checkboxes and also how to set aria-checked for each checkbox using JavaScript.

Note
aria-checked The aria-checked attribute indicates whether the element is checked (true), unchecked (false), or if the checked status is indeterminate (mixed), meaning it is neither checked nor unchecked.

Finished page

finish page showing list of checkboxes

Data

In code the following model is used to represent automobile parts with just enough properties for rendering checkboxes and on post have the primary key for each selected part selected by the visitor.

public class AutoPart
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Mocked data

So there are no external dependences e.g. a database, static data is used.

public class MockedData
{
    /// <summary>
    /// For a real app data would come from a data source eg. database
    /// </summary>
    public static List<AutoPart> PartsList() =>
        new()
        {
            new () { Id = 1, Name = "Headlights" },
            new () { Id = 2, Name = "Brake Light Switches" },
            new () {Id = 3, Name = "Wiper Switches" },
            new () {Id = 4, Name = "Door Jamb Switches" }
        };
}
Enter fullscreen mode Exit fullscreen mode

Rendering data with checkboxes

Code behind

Using the following model, setup a list property.

public class ServiceModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool Checked { get; set; }
    public override string ToString() => $"{Id}  {Name}  {Checked}";
}
Enter fullscreen mode Exit fullscreen mode

The property

public class Index1Model : PageModel
{
    [BindProperty]
    public List<ServiceModel> CheckModels { get; set; }
Enter fullscreen mode Exit fullscreen mode

Next, use the following method to populate CheckModels.

public Index1Model()
{
    LoadParts();
}

private void LoadParts()
{
    CheckModels = new List<ServiceModel>();
    foreach (var part in MockedData.PartsList())
    {
        CheckModels.Add(part.Id % 2 == 0
            ? new ServiceModel() { Id = part.Id, Name = part.Name, Checked = true }
            : new ServiceModel() { Id = part.Id, Name = part.Name });
    }
}
Enter fullscreen mode Exit fullscreen mode

Frontend code

  • @Html.HiddenFor keeps a reference to the identity for each part
  • @Html.CheckBoxFor
    • An anonymous object for storing
      • The part identifier
      • form-check-input the Bootstrap class for rendering the checkbox, not this is also used in JavaScript below to provide dynamic toggling for aria-checked attribute
      • Set the initial value for aria-checked
      • Set the initial value for aria-label

🛑 Important

  • Note that setting an aria attribute use an underscore rather than a hyphen, Visual Studio will handle the conversion.
  • Some parts will be set to true while others to false, once the page has been rendered and a checkbox check state changes without the proper JavaScript the aria-checked property will not change.
@for (var index = 0; index < Model.CheckModels.Count(); index++)
{

    <div class="row">

        <div class="col-6 ms-3">
            @* note setting initial value of aria-checked using aria_checked*@
            @Html.HiddenFor(item => @Model.CheckModels[index].Id)
            @Html.CheckBoxFor(item => @Model.CheckModels[index].Checked,
                new
                {
                    @id = @Model.CheckModels[index].Id,
                    @class = "form-check-input",
                    aria_checked = @Model.CheckModels[index].Checked.ToString().ToLower(),
                    aria_label = @Model.CheckModels[index].Name,
                })

            <input type="hidden" asp-for="@Model.CheckModels[index].Name"/>
            <label class="form-check-label"
               for="@Model.CheckModels[index].Id" aria-labelby="@Model.CheckModels[index].Id">
                 @Model.CheckModels[index].Name
            </label>

        </div>

    </div>

}
Enter fullscreen mode Exit fullscreen mode

JavaScript

The following code assigns a click event for each checkbox, if the checkbox is set to true, aria-checked is set to true while when the checkbox is unchecked its aria-check is set to false.

var $checkboxHelper = $checkboxHelper || {};
$checkboxHelper = function () {
    var setupCheckboxesClickEvents = function (checkboxes) {

        for (let index = 0; index < checkboxes.length; index++) {

            checkboxes[index].onclick = function () {

                if (checkboxes[index].getAttribute('aria-checked') === 'true') {
                    checkboxes[index].setAttribute('aria-checked', 'false');
                } else {
                    checkboxes[index].setAttribute('aria-checked', 'true');
                }
            };
        }
    }

    // for testing 
    var setCheckboxesAriaChecked = function (checkboxes) {

        for (let index = 0; index < checkboxes.length; index++) {
            checkboxes[index].onclick = function () {
                checkboxes[index].setAttribute('aria-checked', 'false');
            };
        }
    }


    return {
        initialize: setupCheckboxesClickEvents,
        setAriaCheckedFalse: setCheckboxesAriaChecked
    };
}();
Enter fullscreen mode Exit fullscreen mode

The following code run the method above in document load of the page


@section Scripts
    {
    <script>
        document.addEventListener("DOMContentLoaded", () => {
            $checkboxHelper.initialize(document.getElementsByClassName("form-check-input"));
        });
    </script>
}
Enter fullscreen mode Exit fullscreen mode

Watch aria-checked

Open developer tools in your browser and toggle a checkbox, below is with Chrome developer tools.

developer tools

On Post

The code asserts there are checked items and if so display them else write out none were checked.

public Task<IActionResult> OnPostResendAsync()
{
    var checkedItems = CheckModels.Where(x => x.Checked).ToList();

    if (checkedItems.Any())
    {
        Log.Information("Checked items on Index1 post");
        foreach (var model in checkedItems)
        {
            Log.Information("Id: {Id} Name: {name}", model.Id, model.Name);
        }
    }
    else
    {
        Log.Information("Nothing check for index1 post");
    }


    return Task.FromResult<IActionResult>(RedirectToPage("Index1"));
}
Enter fullscreen mode Exit fullscreen mode

OnPost results for two checkboxes checked

Source code

Clone the following GitHub repository.

Top comments (2)

Collapse
 
xgrois profile image
xgrois

Thank you so much for explaining this topic because there is no documentation. I cannot understand how working with checkboxes is so weird in asp net core razor pages. Unbelievable.

Collapse
 
karenpayneoregon profile image
Karen Payne

Your welcome!