By design, when you build a server-side Blazor app, and you pass parameters to a component when those parameters change inside the component the changes are not reflected in the host. With a little hack, we can make that happen. It’s INotifyPropertyChanged all over again!
This gem came from my online 8-hour Blazor Workshop. You can purchase the video and materials or sign up for the next class.
In Visual Studio 2019 (or higher) create a new Blazor app called NotifyComponentDemo.,
Add a new class called Customer with two string properties: Name and Email.
Right-click on the Pages folder and select Add / New Item.
Select Web from the list on the left and then Razor Comopnent from the list.on the right.
Name the component Editor and replace with the following:
<div style="background-color:lightgray;"> <div style="padding:1vw;"> Name: <br /> <input @bind="@Customer.Name" @bind:event="oninput" /> <br/><br/> Email: <br /> <input @bind="@Customer.Email" @bind:event="oninput" /> </div> </div> @code { [Parameter] public Customer Customer { get; set; } }
Now open Index.razor from the Pages folder and replace wiht the following:
@page "/" <Editor Customer="Customer" /> <br /> <br /> Name: @Customer.Name <br /> Email: @Customer.Email <br /> @code { Customer Customer = new Customer(); protected override void OnInitialized() { Customer = new Customer { Name = "Ben Goofin", Email = "ben@bengoofin.com" }; } }
Our component accepts a customer object as a parameter. It allow you to edit the name and email properties.
Press F5 and run. One might expect that as you edit the values, your Index page would show the changes as you type, especially since we are using the @bind:event=oninput syntax.
Not so, and this is by design.
In order to make this happen we have to first capture the keystrokes in the input boxes. Change the input tags to the following:
Name: <br /> <input @bind="@Customer.Name" @bind:event="oninput" @onkeyup="KeyPressed" /> <br/><br/> Email: <br /> <input @bind="@Customer.Email" @bind:event="oninput" @onkeyup="KeyPressed" />
Now we need to handle that keypress event, but what should we do when a key is pressed?
We need to add an event handler to notify the host (Index.razor) that the state of the component (namely the Customer object) has changed.
Add the following code to the code block in the component:
[Parameter] public EventCallback<string> ComponentDataUpdated { get; set; } async Task KeyPressed(KeyboardEventArgs args) { await ComponentDataUpdated.InvokeAsync(""); }
Go back to the host (Index.razor) and modify as follows:
@page "/" <Editor Customer="Customer" ComponentDataUpdated="ComponentUpdated" /> <br /> <br /> Name: @Customer.Name <br /> Email: @Customer.Email <br /> @code { Customer Customer = new Customer(); protected override void OnInitialized() { Customer = new Customer { Name = "Ben Goofin", Email = "ben@bengoofin.com" }; } void ComponentUpdated(string args) { StateHasChanged(); } }
So, on every key press our component raises the ComponentUpdated event, which we handle in the host page in a like-named method, ComponentUpdated. The string argument is ignored but necessary.
All our code does is call StateHasChanged() and magically, Blazor updates the UI in the host that displays properties of the Customer object.
Voila'