Hack Dag
Hack Dag

Reputation: 21

Razor components, value change in child component callback not reflected in UI

Trying out the Razor Components template project in Visual Studio Enterprise 2019 Preview 3.0.

When updating a UI bound element in a callback from a child component, the change is not reflected in the UI as expected.

Parent component, binding variable "Status" to UI:

@page "/parent"
@using System.Diagnostics
@using System.Threading.Tasks

Status: @Status

<Child OnUpdate="@Updated"></Child>

@functions {
    public string Status { get; set; }

    protected override async Task OnInitAsync()
    {
        Status = "Waiting...";
    }

    public void Updated()
    {
        Debug.WriteLine("Updated callback performed");
        Status = "Updated!";
    }
}

Child component, performing callback to parent:

@using System
@using Microsoft.AspNetCore.Components

<button onclick="@OnUpdate">Do the update thing</button>

@functions {
    [Parameter] public Action OnUpdate { get; set; }
}

The callback is performed as expected, but the UI is not updated! Any suggestions on how to solve this?

Upvotes: 2

Views: 3075

Answers (3)

revobtz
revobtz

Reputation: 616

You need to add an event on the child component and then call the parent event. This should work.

@using System
@using Microsoft.AspNetCore.Components

<button onclick=@(() => OnClick())>Do the update thing</button>

@functions {
    [Parameter] public Action OnUpdate { get; set; }
    void OnClick()
    {
        OnUpdate?.Invoke();
    }
}

Upvotes: 0

HAL1789
HAL1789

Reputation: 1

I always read Chris's blog on Blazor, great information... EventCallback is a basic building block to the Components programming model. EventCallback is a value type that wraps a delegate and resolve problems using delegates between components. First the component:

<button onclick="@OnClick">Click here and see what happens!</button>

@functions
{
   [Parameter] EventCallback<UIMouseEventArgs> OnClick { get; set; }
}

Second the component user:

@page "/callback"

<div>@text</div>
<div>@textAsync</div>

<MyButton OnClick="ShowMessage" />
<MyButton OnClick="ShowMessageAsync" />

@functions
{
   string text;

   void ShowMessage(UIMouseEventArgs e)
   {
        text = "Hello, world!";
   }
}

@functions {
    string textAsync;

    async Task ShowMessageAsync(UIMouseEventArgs e)     
    {
        await Task.Yield();
        textAsync = "Hello, world async!";
    }
}

The compiler has built-in support for converting a delegate to an EventCallback and will do some other things to make sure that the rendering process has enough information to dispatch the event properly, the EventCallback is always created with a reference to the component that created it. So the EventCallback is always created with a reference to the component that created it. From the point of view of MyButton - it gets a value of EventCallback<> and passes that off to the onclick event handler. Event handlers in Components now understand EventCallback<> as well as delegates.

Upvotes: 0

Chris Sainty
Chris Sainty

Reputation: 8521

If you change your child Components OnUpdate parameter type from Action to EventCallback then your parent component should get updated.

Upvotes: 1

Related Questions