Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blazor EventCallback<T> return value to the child component [server-blazor]

I have a need to adjust a child component based on the result of EventCallback<T> async call, starting with reporting an error in validation summary. Yet I cannot seem to find a blazor-way to do this efficiently, it seems that communication is strictly one-way, from child to parent.

I read some SO answer that you can use Func<T1, T2> instead of EventCallback<T>, but that it has a serious downside of not calling StateHasChanged() when needed.

    [Parameter]
    public EventCallback<int> OnAccountEntered { get; set; }

    private async Task HandleValidSubmit()
    {
        try
        {
            DisableButton = true;
            ButtonText = "Please Wait, Validating Account Information";
            await OnAccountEntered.InvokeAsync(Model.AccountNumber ?? 0).ConfigureAwait(false);
            
            // here be dragons. how do I get the answer from parent?
        }
        finally
        {
            ButtonText = "Request";
            DisableButton = false;
        }
    }

What would be the proper way to assure this two-way communication between parent and child object?

like image 217
mmix Avatar asked Feb 11 '26 12:02

mmix


1 Answers

There's no "Serious Downside" or anything wrong with using a Func delegate. You have control over whether or not you refresh the parent component. Dragons [like the comment] are myths.

Here's a quick demo using a Func<Task, int>.

MyComponent

<div class="bg-light m-2 p-2">
    <h3>MyComponent</h3>
    <button class="btn btn-primary" @onclick=this.HandleValidSubmit>Update</button>
    <div class="bg-secondary text-white m-2 p-1">
        <pre>Counter: @counter </pre>
    </div>
</div>


@code {
    [Parameter] public Func<int, Task>? OnAccountEntered { get; set; }
    private int counter;

    private async Task HandleValidSubmit()
    {
        if (this.OnAccountEntered is not null)
        {
            // unless you're an async expert keep the await clean and simple
            await this.OnAccountEntered.Invoke(counter + 1);
            counter++;
            // put in a delay so you can see this component update afer the parent
            await Task.Delay(1000);
        }
    }
}

And Index

@page "/"

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<div class="bg-dark text-white m-2 p-1">
    <pre>Counter: @counter </pre>
</div>

<MyComponent OnAccountEntered=this.AccountChanged />

@code{
    private int counter;

    private async Task AccountChanged(int value)
    {
        counter = value;
        // pretend we're an async method getting data from some async source
        await Task.Yield();
        // call StateHasChanged if the process mutates the state of this component
        StateHasChanged();
    }
}
like image 81
MrC aka Shaun Curtis Avatar answered Feb 13 '26 09:02

MrC aka Shaun Curtis