Xaphann
Xaphann

Reputation: 3677

Blazor Checkbox two-way binding and change event

What is the correct way to bind a checkbox and have an event fire when that checkbox changes? I have tried a couple of different ways all not working exactly as I had hoped. Note the checkbox is in a component.

<input type="checkbox" checked="@IsChecked" @onchange="CheckboxChanged">
@code{
      [Parameter]
      public bool IsChecked { get; set; } = true;
      private void CheckboxChanged()
      {
           Console.WriteLine($"Checkbox changed {IsChecked}");
      }
}

When the page loads it reads the value that is given to IsChecked, and when the CheckBox is checked the method fires. However, the value for IsChecked is not updated. Then if the binding value for IsChecked is changed outside of the component, the method does not fire but the value for IsChecked is changed (should note that UI is updated correctly).

I figured I needed an actual bind like this:

<input type="checkbox" @bind="IsChecked" @onchange="CheckboxChanged" >

However, this gives an error that onchange is used two or more

<input type="checkbox" @bind="IsChecked" @onclick="CheckboxChanged" >

When the user clicks the checkbox it does fire the method however, IsChecked is at the old value (I am assuming the click happens before the bind). Then if the value for IsChecked is changed outside of the component, once again the method does not fire.

What is the correct way?

Upvotes: 28

Views: 52866

Answers (5)

Wiktor
Wiktor

Reputation: 856

Like @hans-kesting mentioned, you can use InputCheckbox. If you would like to have a custom logic on value changed event you can achieve it with this:

<InputCheckbox ValueChanged="@((e) => CheckboxChanged(e))" ValueExpression="@(() => IsChecked)"/>

Note, that you cannot use @bind-Value and ValueChanged together. That's why ValueChanged and ValueExpression are required to achieve similar behavior.

Additionally, an example of how one might implement simple CheckboxChanged.

private void CheckboxChanged(bool e)
{
    IsChecked = e;
}

Upvotes: 7

CoderR
CoderR

Reputation: 31

<input class="form-check-input" type="checkbox" value="@record.IsChecked" checked="@record.IsChecked" @onchange="@((args) => CheckboxChanged((bool)args.Value))"/>

Upvotes: 3

aryeh
aryeh

Reputation: 1040

As of .NET 7 you can use the @bind-value:after to tap into the change event after it's happened.

<input type="checkbox" @bind-value="@IsChecked" @bind-value:after="CheckboxChanged">

@code{
      [Parameter]
      public bool IsChecked { get; set; } = true;
      private void CheckboxChanged()
      {
           Console.WriteLine($"Checkbox changed {IsChecked}");
      }
}

Upvotes: 30

Hans Kesting
Hans Kesting

Reputation: 39283

There exists also an InputCheckbox control:

  <InputCheckbox @bind-Value=@boolProperty />

This correctly two-way binds to a property of type bool (non-nullable). Note the capital V in @bind-Value.

This control needs to be inside an EditForm control.

Upvotes: 3

MrC aka Shaun Curtis
MrC aka Shaun Curtis

Reputation: 30046

There are two issues with your code/component:

  1. You should not modify [Parameters] within your code. These are set whenever the component updates.
  2. The bind uses the OnChanged event to update isChecked, so you can't also use it.

Here's commented code that works.

  1. Uses an internal field to hold the checkbox state.
  2. Wired up the OnInput event.
@page "/"
<input type="checkbox" checked="@isChecked" @oninput="CheckboxChanged">

@code{
    [Parameter]
    public bool IsChecked { get; set; } = true;

    // Internal field holding checkbox state
    private bool isChecked;

    // updates the internal value whwenever the component is updated
    // You may not want that??
    protected override void OnParametersSet()
    {
        isChecked = this.IsChecked;
    }

    private void CheckboxChanged(ChangeEventArgs e)
    {
        // get the checkbox state
        var value = e.Value;
        Console.WriteLine($"Checkbox changed {IsChecked}");
      }
}

Upvotes: 34

Related Questions