Bootstrap multiselect

Karen Payne - Apr 15 '23 - - Dev Community

Introduction

Learn how to use a dropdown for Bootstrap with a variety of options from the following library.

the component

modal example

Although the code sample is done in a Microsoft Razor Pages project with little effort the code provided can be used in many types of projects and note all JavaScript is separated from the HTML so a developer can copy and paste if so desired, make a few changes and good to go.

Recommendations

The documentation for the component does not target novice developers and with that mentioned take time to read the documentation and start out small, in a test project without the clutter of an application will make getting acquainted with the component away from your application.

Installation

Source code

Written in Microsoft Visual Studio 2022, .NET Core 7.

Using the component

The sample (taken from the docs) below will render the component and pretty much all the provided code samples are devoid of how to get selections unless the developer takes time to read the documentation.



<select id="example-getting-started" multiple="multiple">
    <option value="cheese">Cheese</option>
    <option value="tomatoes">Tomatoes</option>
    <option value="mozarella">Mozzarella</option>
    <option value="mushrooms">Mushrooms</option>
    <option value="pepperoni">Pepperoni</option>
    <option value="onions">Onions</option>
</select>


Enter fullscreen mode Exit fullscreen mode

In the provided code the select is dynamically generated using the following code and when inspecting the page will be the same as the stock example except for the identifier.



<select id="select-tops-options" required multiple="multiple">
    @{
        foreach (var condiment in MockedData.Condiments())
        {
            <option value="@condiment.Value">@condiment.Name</option>
        }
    }
</select>


Enter fullscreen mode Exit fullscreen mode

Script

Located in wwwroot/js open the file index.js.

Traversing the code top to bottom.

  • Create a multiselect with an id of select-tops-options which matches the select above.
  • buttonClass the Bootstrap class to style the select button.
  • nonSelectedText Text to display when nothing has been selected.
  • numberDisplayed how many options to display in the dropdown.
  • buttonWidth with of dropdown
  • includeSelectAllOption: true provide a select all option
  • onSelectAll the event fired when select all is checked.
  • onDeselectAll the event fired when using select all to deselect all.
  • onChange event fires each time an option is selected.
  • templates used to override default styles
  • $('form').submit in this case code for learning

C# backend code

The OnPost determines if all options are selected, if not get the selected options. In either case the options selected are serialized and passed to the results page which displays the selections.



public class IndexModel : PageModel
{
    [BindProperty]
    public string PizzaToppings { get; set; }

    [BindProperty]
    public bool AllCondimentSelected { get; set; }

    [BindProperty]
    public int[] ToppingsSelected { get; set; }

    public void OnGet()
    {

    }

    /// <summary>
    /// First check to see if all options were selected, if not than
    /// get user selected toppings
    ///
    /// Pass selected to result page
    /// </summary>
    /// <returns></returns>
    public IActionResult OnPost()
    {
        if (AllCondimentSelected)
        {
            var data = MockedData.Condiments();

            foreach (var value in data)
            {
                value.Selected = true;
            }

            return RedirectToPage("ResultsPage", new
            {
                condiments = JsonSerializer.Serialize(data, 
                    new JsonSerializerOptions
                    {
                        WriteIndented = true
                    })
            });

        }
        else
        {
            if (!string.IsNullOrWhiteSpace(PizzaToppings))
            {
                ToppingsSelected = Array.ConvertAll(PizzaToppings.Split(','), int.Parse);

                var data = MockedData.Condiments();

                foreach (var value in ToppingsSelected)
                {
                    data.FirstOrDefault(x => x.Value == value)!.Selected = true;
                }

                return RedirectToPage("ResultsPage", new
                {
                    condiments = JsonSerializer.Serialize(
                        data.Where(x => x.Selected).ToList(), 
                        new JsonSerializerOptions
                        {
                            WriteIndented = true
                        })
                });
            }

            return Redirect("Index"); // never reached
        }

    }
}


Enter fullscreen mode Exit fullscreen mode

Validation

Required will prevent the form from posting until at least one option is selected, feel free to use your own validation instead.

required attribute will counter form post and present a message

Modal dialog

modal example

The documentation and code sample for the library at first glance looked good but did not work so I added a modal example which in short uses the same logic as on the index page but in a modal.

Script

In the following code there are two buttons, first is to show the modal and second to hide the modal with a callback to set a hidden element indicating if the user made a selection or cancelled.



@section Scripts
{
    <script src="js/modalPage.js"></script>

    <script>

        $(document).ready(function() {
            $('#example-modal').multiselect();

        });
        var modalConfirm = function (callback) {

            $("#btn-confirm").on("click", function () {
                $("#mi-modal").modal('show');
            });

            $("#modal-btn-no").on("click", function () {
                callback(false);
                $("#mi-modal").modal('hide');
            });
        };

        modalConfirm(function (confirm) {
            if (confirm) {
                document.getElementById("userCancelled").value = false;
            } else {
                document.getElementById("userCancelled").value = true;
            }
        });
    </script>
}


Enter fullscreen mode Exit fullscreen mode

HTML

Using a stock example for a BootStrap modal the multi-select was inserted from the index page which now works as expected.



<div class="modal fade" 
     id="mi-modal" 
     tabindex="-1" 
     data-bs-backdrop="static" 
     data-bs-keyboard="false"
     aria-labelledby="exampleModalLabel" 
     aria-hidden="true">

    <div class="modal-dialog modal-dialog-centered">

        <div class="modal-content">

            <div class="modal-header">
                <h5 class="modal-title" id="exampleModalLabel">Available toppings</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>

            <div class="modal-body">

                <form method="post">

                    <input type="hidden" asp-for="PizzaToppings" id="PizzaToppingsValue"/>
                    <input type="hidden" asp-for="AllCondimentSelected" id="areAllSelected"/>
                    <input type="hidden" asp-for="UserCancelled" id="userCancelled"/>

                    <fieldset class="border border-secondary border-opacity-25 p-3">

                        <legend class="float-none w-auto fs-6">Pizza tops</legend>
                        <select id="select-tops-options" multiple="multiple">
                            @{
                                foreach (var condiment in MockedData.Condiments())
                                {
                                    <option id="@condiment.Value" value="@condiment.Value" aria-checked="false">@condiment.Name</option>
                                }
                            }
                        </select>

                        <div class="mt-2">
                            <button type="submit" class="btn btn-secondary float-end" id="modal-btn-no" asp-page-handler="CloseButton">Close</button>
                            <button type="submit" id="resultsButton" class="btn btn-primary float-end me-2" asp-page-handler="ConfirmButton">Select</button>
                        </div>

                    </fieldset>

                </form>

            </div>
        </div>
    </div>

</div>


Enter fullscreen mode Exit fullscreen mode

Backend code

For the close button of the modal



public IActionResult OnPostCloseButton(IFormCollection data)
{
    Log.Information($"User cancelled selecting any toppings");
    return RedirectToPage("Index",new {message = "No toppings for me"});
}


Enter fullscreen mode Exit fullscreen mode

Then in the index page backend



public void OnGet(string message)
{
    if (!string.IsNullOrWhiteSpace(message))
    {
        ViewData["message"] = message;
    }
}


Enter fullscreen mode Exit fullscreen mode

Index HTML, display a alert since the user cancelled.



@section Scripts
{
    <script src="js/index.js"></script>
    @if (ViewData["message"] != null)
    {
        <script type="text/javascript">
            window.onload = function () {

                Swal.fire({
                    icon: 'info',
                    title: '@ViewData["message"]',
                    customClass: 'swal-sm',
                    showConfirmButton: false,
                    timer: 1500
                });
            };
        </script>
    }
}


Enter fullscreen mode Exit fullscreen mode

alert for nothing selected

Summary

This article provides the basic knowledge needed to use a multi select component. There are many more things that can be done so explore the documentation.

Get the code

Clone the following GitHub repository and select the project Bootstrap5MultiSelectExample.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .