Search code examples
blazorblazor-webassemblyblazor-component

Blazor Checkbox Group Two-Way Binding


I'm a newbie with Blazor and have not been able to perform a two-way binding using a group of checkboxes, no matter if I check or uncheck the checkboxes within the child component, the count is not reflected in the parent.

public class Item
{
    public string Name { get; set; }
    public bool Selected { get; set; }
}

Child Component

<div class="btn-group">
    @foreach(Item item in Items)
    {
        <input id="[email protected]" type="checkbox" class="btn-check" @bind="item.Selected">
        <label for="[email protected]" class="btn btn-success">@item.Name</label>
    }
</div>

@code {
    [Parameter]
    public List<Item> Items { get; set; } = new();
}

Parent Component

<Child Items="items"></Child>
<p>@items.Where(n => n.Selected).Count() Items Selected</p>

@code {
    private List<Item> items = new()
    {
        new Item { Name = "Foo" },
        new Item { Name = "Bar" }  
    };
}

Thanks in advance


Solution

  • It doesn't work quite like classic Bootstrap.

    You need to change the elements around a little.

    <div class="btn-group" >
        @foreach (Item item in Items)
        {
            <button class="btn @(item.Selected ? "btn-primary": "btn-outline-primary")" @onclick="() => SetCheck(item)">@item.Name</button>
        }
    </div>
    
    @code {
        [Parameter] public List<Item> Items { get; set; } = new();
        [Parameter] public EventCallback ItemsChanged { get; set; }
    
        private async Task SetCheck(Item item)
        {
            item.Selected = !item.Selected;
            await ItemsChanged.InvokeAsync();
        }
    }
    

    And Index

    @page "/"
    
    <PageTitle>Index</PageTitle>
    
    <h1>Hello, world!</h1>
    
    <Child Items="items" ItemsChanged=this.OnItemsChanged></Child>
    
    <div class="bg-dark text-white mt-3 p-2">
        <pre>@items.Where(n => n.Selected).Count() Items Selected</pre>
    </div>
    
    @code {
        private List<Item> items = new()
        {
            new Item { Name = "Foo" },
            new Item { Name = "Bar" }
        };
         
        //Don't need to do anything.
        // Will trigger a UI update by it's presence
        private Task OnItemsChanged()
            => Task.CompletedTask;
        
    }