Telerik blogs

Event callbacks complete the Blazor component communication circle by allowing a child component to send information to its parent component when the user triggers an action.

Blazor uses a component-driven application model. We’re building a tree of components to form a Blazor application.

It’s common for parent components to communicate with their child components. Using parameters, we can provide data from the parent to the child.

In this article, we will use event callbacks to send information from the child to its parent component.

Parent and Child Components

Today, we will build a Blazor quiz application. You can access the code on GitHub.

A Blazor application showing a title and a quiz question with two possible answers. Both answer options have a button for the user to select the answer.

Let’s start with the Question component. It contains a Title property and an AnswerA and AnswerB property. All properties are of type string.

<b>@Title</b>
<p>
    Answer A: <button type="button" class="btn btn-primary">@AnswerA</button>
</p>
<p>
    Answer B: <button type="button" class="btn btn-secondary">@AnswerB</button>
</p>

@code {
    [Parameter]
    public string Title { get; set; }
    [Parameter]
    public string AnswerA { get; set; }
    [Parameter]
    public string AnswerB { get; set; }
}

The idea is that each Question component renders a question followed by two answer options. The user can provide an answer using the button representing each option.

All of the information is provided using component parameters. The Parameter attribute applied to each property tells Blazor to require the attribute when using the Question component.

Learn more about how Blazor components work and how parameters provide information from the parent component to its children in the Blazor Basics: Creating a Blazor Component article of this series.

In our example, the parent component is the Index page of the application.

@page "/"
<PageTitle>Blazor Quiz</PageTitle>

<h1>Blazor Quiz</h1>
<p style="margin-bottom: 24px">Welcome to the Blazor Quiz!</p>

<h2>Questions</h2>
<Question Title="Does Blazor support event callbacks?" AnswerA="Yes" AnswerB="No" />

Besides the heading and other information rendered on the screen, the Index page uses the Question component, providing three strings to its Title, AnswerA and AnswerB attributes.

Adding Event Callbacks

So far, we have provided data from the parent to the child component, but we do not communicate back.

Let’s change it by adding an event callback that fires when the user presses one of the answer buttons within the Question component.

[Parameter]
public EventCallback OnAnswerASelected { get; set; }
[Parameter]
public EventCallback OnAnswerBSelected { get; set; }

First, we add two properties of type EventCallback to the Question component and name them OnAnswerASelected and OnAnswerBSelected.

We also add the Parameter attribute because we want to provide the handler from the parent component.

As the names suggest, those callbacks will be fired when a user selects answer A or B. We fire the events by adding a reference to each of the answer buttons using their onclick attribute.

The whole Question component now looks like this:

<b>@Title</b>
<p>
    Answer A: <button type="button" class="btn btn-primary" onclick="@OnAnswerASelected">@AnswerA</button>
</p>
<p>
    Answer B: <button type="button" class="btn btn-secondary" onclick="@OnAnswerBSelected">@AnswerB</button>
</p>

@code {
    [Parameter]
    public string Title { get; set; }
    [Parameter]
    public string AnswerA { get; set; }
    [Parameter]
    public string AnswerB { get; set; }

    [Parameter]
    public EventCallback OnAnswerASelected { get; set; }
    [Parameter]
    public EventCallback OnAnswerBSelected { get; set; }
}

Handling Event Callbacks

Next, we need to provide a handler for each event callback when using the Question component on the Index page.

@page "/"
<PageTitle>Blazor Quiz</PageTitle>

<h1>Blazor Quiz</h1>
<p style="margin-bottom: 24px">Welcome to the Blazor Quiz!</p>

<h2>Questions</h2>
<Question 
    Title="Does Blazor support event callbacks?" 
    AnswerA="Yes" 
    AnswerB="No"
    OnAnswerASelected="@AnswerASelected"
    OnAnswerBSelected="@AnswerBSelected" />

<p>The user pressed: @State</p>

@code {
    public string State { get; set; } = "Nothing";

    public void AnswerASelected()
    {
        State = "A";
    }

    public void AnswerBSelected()
    {
        State = "B";
    }
}

Note the OnAnswerASelected and OnAnswerBSelected properties added to the Question component that both reference a method from the code section.

We use a simple logic that changes the text on the screen depending on what button has been pressed. In a real quiz application, you might check whether the user clicked the correct answer and add or remove points.

Notice that we do not need to manually call the StateHasChanged method because the EventCallback type handles it internally and conveniently forces a re-render of the involved components.

Firing Events from Within C# Code

Instead of using the OnAnswerASelected event callback directly as the argument of the onclick attribute of the button, we can fire events from inside C# methods.

The code would look like this:

public void OnButtonAClicked()
{
    OnAnswerASelected.InvokeAsync();
}

The EventCallback type provides an InvokeAsync method that we can use to fire the event from within any C# method.

The wiring of the OnButtonAClicked method to the component template looks like this:

@onclick="OnButtonAClicked"

As you can see, we can either use the EventCallback property as the onclick handler of a button, or we can fire an event callback from inside any C# component code.

Passing Data to the Event Callback Handler

So far, we defined an EventCallback inside the child component and added a handler method in the parent component by providing it via component parameters.

But what if we want to pass information from the child component to the parent component when the event fires?

Blazor offers a generically typed implementation of the EventCallback type. We can use it to provide context when the event fires.

Let’s define the following enum type in the root of the project, so that it is available within both, the Index page and the Question component:

namespace BlazorQuiz;
public enum QuizAnswer
{
    AnswerA,
    AnswerB
}

Next, we want to use this type to pass information from the child component to its parent. We change the implementation of the Question component like this:

<b>@Title</b>
<p>
    Answer A: <button type="button" class="btn btn-primary" @onclick="() => AnswerSelected(QuizAnswer.AnswerA)">@AnswerA</button>
</p>
<p>
    Answer B: <button type="button" class="btn btn-secondary" @onclick="() => AnswerSelected(QuizAnswer.AnswerB)">@AnswerB</button>
</p>

@code {
    [Parameter]
    public string Title { get; set; }
    [Parameter]
    public string AnswerA { get; set; }
    [Parameter]
    public string AnswerB { get; set; }

    [Parameter]
    public EventCallback<QuizAnswer> OnAnswerSelected { get; set; }

    public void AnswerSelected(QuizAnswer answer)
    {
        OnAnswerSelected.InvokeAsync(answer);
    }
}

We removed the specific event callbacks named OnAnswerASelected and OnAnswerBSelected and replaced them with a single OnAnswerSelected event callback. Notice the QuizAnswer type argument.

Next, we added an AnswerSelected method that accepts a single parameter of type QuizAnswer and fires the OnAnswerSelected event using its InvokeAsync method and passing the value received by its method parameter.

We also changed the wiring of the button tags in the component template. We call the AnswerSelected method from within the onclick attribute and provide the correct value of the QuizAnswer enum, depending on the button.

In the Index page component, we also need to make a few changes.

@page "/"
<PageTitle>Blazor Quiz</PageTitle>

<h1>Blazor Quiz</h1>
<p style="margin-bottom: 24px">Welcome to the Blazor Quiz!</p>

<h2>Questions</h2>
<Question 
    Title="Does Blazor support event callbacks?" 
    AnswerA="Yes" 
    AnswerB="No"
    OnAnswerSelected="@AnswerSelected" />

<p>The user pressed: @State</p>

@code {
    public string State { get; set; } = "Nothing";

    public void AnswerSelected(QuizAnswer answer)
    {
        if( answer == QuizAnswer.AnswerA)
        {
            State = "A";
        }
        else if( answer == QuizAnswer.AnswerB)
        {
            State = "B";
        }
    }
}

First, we provide a single event callback to the OnAnswerSelected property of the Question component. The implementation accepts a value of type QuizAnswer as its first method parameter. We set the State property depending on its value.

The implementation using the generic EventCallback type is a lot more concise and provides better readability.

Instead of having multiple callbacks with verbose names, such as OnAnswerASelected and OnAnswerBSelected, we use a single OnAnswerSelected event callback.

Blazor Components Communication Circle

When we use a child component in a parent component, we reference the child component using a custom HTML tag in the component’s template.

A parent/child example using parameters and event callbacks for communication. The event callback and the parameter are provided from the parent to the child component. The child component invokes the event to send information from the child component to its parent.

If the child component requires any parameter, we use HTML attributes to provide the information for each parameter.

When we want to send information from a child component to a parent based on a user action, we use event callbacks.

Differences Between .NET Events and Blazor EventCallback

The Blazor EventCallback type may sound a lot like classic .NET events. However, there are a few noteworthy differences.

First, .NET events can have multiple event handlers. Consider the following code:

Window.OnCloseEvent += HandleWindowClose;

We add the HandleWindowClose method to a collection of handler methods. When using Blazor EventCallback, we can only provide a single handler method. On the upside, we do not need to unsubscribe from events like we would need to do using classic .NET events.

Second, .NET events are classes, while the Blazor EventCallback<T> type is a struct. The advantage of using structs here is that we cannot assign null to a property of a struct type. Therefore, we do not need to check for null values when firing a Blazor EventCallback. Consider the following code:

OnAnswerSelected.InvokeAsync(answer);

We can call the InvokeAsync method without checking for null because the compiler makes sure that the OnAnswerSelected property always contains a value.

When using classic .NET events, the code would look like this:

OnCloseEvent?.Invoke(this, value);

There are a few more minor differences between classic .NET events and Blazor EventCallback types. However, those two points are the most important differences to remember.

Conclusion

The EventCallback type provides a simple API for communication between child and parent components in Blazor applications.

The generic EventCallback<T> type allows us to provide context information when firing the event. It helps us write concise, readable, and maintainable code.

Event callbacks complete the communication circle between Blazor components. We use parameters to provide data from a parent to its child component. And we use event callbacks to provide information from the child component to its parent.


Try Telerik UI for Blazor

Want to dive into Blazor development with all the components you could want already built natively for you? Progress Telerik UI for Blazor helps you create professional-grade web projects in half the time with a high-performing Grid and 100+ easy-to-customize Blazor components to cover any requirement. Try it for free with our 30-day trial and enjoy our industry-leading support.


Try Now


About the Author

Claudio Bernasconi

Claudio Bernasconi is a passionate software engineer and content creator writing articles and running a .NET developer YouTube channel. He has more than 10 years of experience as a .NET developer and loves sharing his knowledge about Blazor and other .NET topics with the community.

Related Posts

Comments

Comments are disabled in preview mode.