Introduction
The earlier version of Blazor supports a limited number of events. It only supports onclick and onchange events. The current version of Blazor provides pretty rich event handling. In the current version of Blazor, you can access most of the DOM events with the HTML element. The value of the attribute is treated as an event handler.
Following is Razor syntax to define the event in the Blazor component,
@on{DOM EVENT}="{DELEGATE}"
Blazor also supports an asynchronous delegate event handler that returns the Task. The delegate event handler of Blazor has automatically triggered a UI render event, so there is no need to manually call StateHasChanged every time on the event. The EventCallback<T> class is exposed as a parameter to the component so, it can easily notify consumers when something happened.
Example
In the following example, the "IncrementCount" method is called every time when the button is clicked.
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
Event arguments
Blazor also provides the event argument if event-supported event arguments are in the event method definition. For example, MouseEventArgs provide the mouse coordinates when the user moves the mouse pointer in the UI.
The following table contains supported Event arguments,
Events |
Class |
DOM Events |
Clipboard |
ClipboardEventArgs |
oncut, oncopy, onpaste |
Drag |
DragEventArgs |
ondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragend |
Error |
ErrorEventArgs |
onerror |
Event |
EventArgs |
onactivate, onbeforeactivate, onbeforedeactivate, ondeactivate, onfullscreenchange, onfullscreenerror, oncanplay, oncanplaythrough, oncuechange, ondurationchange, onemptied, etc. |
Focus |
FocusEventArgs |
onfocus, onblur, onfocusin, onfocusout |
Input |
ChangeEventArgs |
onchange, oninput |
Keyboard |
KeyboardEventArgs |
onkeydown, onkeypress, onkeyup |
Mouse |
MouseEventArgs |
onclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout |
Mouse pointer |
PointerEventArgs |
onpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture |
Mouse wheel |
WheelEventArgs |
onwheel, onmousewheel |
Progress |
ProgressEventArgs |
onabort, onload, onloadend, onloadstart, onprogress, ontimeout |
Touch |
TouchEventArgs |
ontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancel |
Example
In the following example, the MouseClick method used MouseEventArgs, and this method show the mouse coordinates of a button when it clicked.
@*MousePointerExample.razor*@
@page "/mouseclick"
<h3>Mouse Coordinates</h3>
<button class="btn btn-primary" @onclick="MouseClick">Button 1</button>
<br />
<br />
<button class="btn btn-primary" @onclick="MouseClick">Button 2</button>
<p>@mouseCoordinatesString</p>
@code {
private string mouseCoordinatesString;
private void MouseClick(MouseEventArgs e)
{
mouseCoordinatesString = $"Mouse coordinates: {e.ScreenX}:{e.ScreenY}";
}
}
Define delegate using Lambda expressions
You can also define event delegate using the Lambda expressions. It is very useful to define a small inline function with an event handler.
In the following example, I have defined an inline function to increment the counter.
@*LambdaExpressionExample.razor*@
@page "/lambdaexpressions"
<h3>Lambda Expression Example</h3>
<button @onclick="@(e => currentCount++)">
Click Me
</button>
<p> Current Count:@currentCount </p>
@code {
private int currentCount = 0;
}
You can also pass additional information as a parameter of the method along with the event argument. In the following example, I have sent the button number along with the MouseEventArgs argument.
@*LambdaExpressionExample.razor*@
@page "/lambdaexpressions"
<h3>Lambda Expression Example</h3>
<button class="btn btn-primary" @onclick="@(e => MouseClick(e, 1))">Button 1</button>
<br />
<br />
<button class="btn btn-primary" @onclick="@(e => MouseClick(e, 2))">Button 2</button>
<p>@mouseCoordinatesString</p>
@code {
private string mouseCoordinatesString;
private void MouseClick(MouseEventArgs e, int buttonNumber)
{
mouseCoordinatesString = $"Mouse coordinates of button {buttonNumber}: {e.ScreenX}:{e.ScreenY}";
}
}
Event Callback
Using event callback, you can expose events across the components. The most common scenario is to execute the parent component method from the child component's button click. The EventCallback<T> class is exposed as a parameter to the component, so it can easily notify consumers when something happened. The public property of type EventCallback<T> is declared and decorated with the Parameter attribute.
The following example demonstrates how a child component's button click event handler is set up to received event callback on the parent component. Here, I am using MouseEventArgs for even callback type when the child component's button click then the parent component's "EventFromChild" method called. As described earlier, the callback method does not require to call StateHasChanged as it automatically called when a child component event trigger.
@*ChildComponent.razor*@
<h4>Child Component</h4>
<button @onclick="OnClickCallback">
Click Me
</button>
@code {
[Parameter]
public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}
@*ParentComponent.razor*@
@page "/eventcallback"
<h3>Parent Component</h3>
<ChildComponent OnClickCallback="@EventFromChild" />
<p>@message</p>
@code {
private string message;
private void EventFromChild(MouseEventArgs e)
{
message = $"Mouse coordinates of child component button - ({e.ScreenX}:{e.ScreenY})";
}
}
The EventCallback also allows asynchronous delegates and weakly typed (allows to pass any type of argument). It is recommended to use strongly typed.
Differences between Blazor's EventCallback<T> and .NET events
There are few differences between Blazor's EventCallback<T> and .NET events,
- Blazor's EventCallback<T> is a single-cast event (it can assign to a single value or single method) handler but the .NET event is multi-cast
- Blazor's EventCallback<T> is a read-only structure, so it cannot be null but .NET Event is classes.
- Blazor's EventCallback<T> can be asynchronous but standard .NET events are synchronous
Apart from this, Blazor's EventCallback<T> can be set using Razormarkup and provides automatic state change detection
Prevent default actions
Sometimes, you want to prevent an event's default action. For example, the anchor's default action is to navigate to the URL set in the "href" attribute. Now, you want to suppress the default behavior but perform the event. The Blazor provides @on{DOM EVENT}:preventDefault directive attribute to prevent the default action for an event.
In the following example, the default action of the anchor tag is suppressed but still executes the DOM event.
@*PreventDefault.razor*@
@page "/preventDefault"
<h3>Prevent Default Example</h3>
<p>
<a href="https://www.c-sharpcorner.com/"
@onclick="KeyHandler"
@onclick:preventDefault="true">
Click Here
</a>
</p>
<p>@count</p>
@code {
private int count = 0;
private void KeyHandler()
{
count++;
}
}
If you are not specified value with @on{DOM EVENT}:preventDefault attribute, it will set to true. Also, you can provide the value of this attribute using expression.
Stop event propagation
It is also possible to stop event propagation with Blazor. The @on{DOM EVENT}:stopPropagation directive attribute is used to stop event propagation. It stops the event bubbling to the parent tag.
In this following example, there are two <div> element inside the parent <div> element. The first <div>'s event does not stop to propagate event to parent but second <div> event stop event propagation to parent.
@*StopEventPropagation.razor*@
@page "/stopeventpropagation"
<h3>Stop Event Propagation</h3>
<input @bind="stopPropagation" type="checkbox" name="stopPropagation" />
<label for="stopPropagation"> Stop Propagation</label>
<br>
<div class="m-1 p-1 border" id="primary-div" @onclick="OnClickParentDiv">
<p>
Parent Div
</p>
<div class="m-1 p-1 border" @onclick="OnClickChildDiv">
Child div doesn't stop event propagation when clicked.
</div>
<div class="m-1 p-1 border" @onclick="OnClickChildDiv"
@onclick:stopPropagation="stopPropagation">
Child div stops event propagation when clicked.
</div>
</div>
<p>
@message
</p>
@code {
private bool stopPropagation= true;
private string message;
private void OnClickParentDiv() =>
message = $"The parent div was Clicked. {DateTime.Now}";
private void OnClickChildDiv() =>
message = $"A child div was Clicked. {DateTime.Now}";
}
Summary
The current version of the Blazor provides rich event handling. It supports almost all DOM events.
You can view or download the source code from the GitHub link here.