Skip to content

[Blazor] Does @bind-{PARAMETER}:set behave differently than {PARAMETER}Changed for component parameters? #64671

@UniMichael

Description

@UniMichael

I opened this issue in the AspNetCore.Docs repository, and was told to open an issue here after some discussion.

I'm wondering if there's a functional difference between using @bind-{PARAMETER}:set and {PARAMETER}Changed when dealing with component parameters. From my testing, they appear to behave the same.


From the original issue:

I'm not sure what you mean by 'functional difference.'

The earlier docs mention that @bind:get/@bind:set differs from something like @onchange in that it informs the framework that your intent is to modify the value. So it'll update the DOM after the handler. When dealing with component parameters, though, you're not really dealing with the DOM anymore, right?

If you'll excuse the slightly longer example:

MyPage.razor:

@page "/"

<div>@_value</div>
<input value="@_value" @onchange="HandleValueChanged" />
<input @bind:get="_value" @bind:set="HandleBoundValueChanged" />

@code
{
    private string _value = string.Empty;

    private void HandleValueChanged(ChangeEventArgs args) => 
        HandleBoundValueChanged(args.Value?.ToString() ?? string.Empty);

    private void HandleBoundValueChanged(string value) =>
        _value = value.Length > 3 ? value[..3] : value;
}

With the above code, if I take the first input (old style change handling), and I type out "12345", it'll get turned into "123" and the <div> will show "123". If I then add "45" (so "12345" again), the <div> will continue showing "123", but the input will still have "12345".

The second input doesn't have this problem, because it uses @bind:get/@bind:set, and that's precisely the type of problem it solves.


I convert the "keep 3 characters in my input" logic into its own component which uses @bind:get/@bind:set:

ThreeCharacterInput.razor:

<input @bind:get="Value" @bind:set="HandleValueChangedAsync" />

@code
{
    [Parameter]
    public string Value { get; set; } = string.Empty;

    [Parameter]
    public EventCallback<string> ValueChanged { get; set; }

    private async Task HandleValueChangedAsync(string value) =>
        await ValueChanged.InvokeAsync(value.Length > 3 ? value[..3] : value);
}

Is there supposed to be any difference between these two uses below? From my testing, they both work the same (I can't reproduce the "12345" bug with either of them).

MyPage.razor:

@page "/"

<div>@_value</div>
<ThreeCharacterInput Value="@_value" ValueChanged="@(value => _value = value)" />
<ThreeCharacterInput @bind-Value:get="@_value" @bind-Value:set="@(value => _value = value)" />

@code
{
    private string _value = string.Empty;
}

So when I ask about "functional" differences, I mean is there an inherent reason to use one version over the other when dealing with component parameters? Is the guidance to use @bind-{PARAMETER}:get/@bind-{PARAMETER}:set with component parameters just to be consistent with HTML bindings? Am I missing some subtle issue in the non @bind-based approach?


cc: @guardrex dotnet/AspNetCore.Docs#36435

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-blazorIncludes: Blazor, Razor Components

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions