Blazor can invoke JavaScript function from .NET methods. Similary through JavaScript we can invoke .NET methods. This whole process is called Blazor JavaScript Interop or JavaScript Interoperability. The JS Interop makes it easy for integrating JavaScript libraries in Blazor application like Chart.js, Popper.js, Babylon.js, and so many more.
Page Contents
In this tutorial we are going to cover the whole process of JS Interop in Blazor by taking multiple examples.
Calling JavaScript function from Blazor Components requires IJSRuntime Interface of the Microsoft.JSInterop which we can inject into the Razor components as shown below:
@inject IJSRuntime JS
Alternately, you can also do the injection by applying the [Inject] attribute on a C# property. See below code:
[Inject]
public IJSRuntime JSRuntime { get; set; }
JavaScript functions can be called from Blazor by the use 2 methods of the IJSRuntime Interface. These methods are describe below:
1. InvokeAsync<T>(name, args) – Invokes the specified JavaScript function asynchronously. Here “name” is the name of JS function to be invoked and “args” are the arguments that will be passed to the JS function. The type parameter “T” specify the result type that this JS function will return like string, int, etc.
2. InvokeVoidAsync(name, args) – Invokes the JavaScript function asynchronously. The JS function invoked in this case does not return a value.
Let us show JavaScript alert box in Blazor. So, create a new razor component called CallJS.razor inside the Pages folder of your app. Add the following code to it.
@using Microsoft.JSInterop
@inject IJSRuntime JS;
@page "/CallJS"
<h1 class="bg-info text-white">Call JavaScript from Blazor</h1>
<div class="form-group">
<button class="btn btn-secondary" @onclick="ShowAlert">Show JavaScript Alert</button>
</div>
@code {
public async void ShowAlert()
{
await JS.InvokeVoidAsync("JSAlert");
}
}
In the first 2 code lines we have imported the namespace Microsoft.JSInterop and injected the IJSRuntime.
@using Microsoft.JSInterop
@inject IJSRuntime JS;
We created a button, on whose click event, we are calling a JavaScript function by the name of JSAlert. We am using the InvokeVoidAsync method to do this job. Notice that no parameter is passes to this method which makes sense since it will only be showing an alert box.
await JS.InvokeVoidAsync("JSAlert");
Next create a JavaScript file called example.js inside the wwwrooot/JS folder of you app. Add the function called JSAlert that shows the alert box with a text “Hello”. The code is given below:
function JSAlert() {
alert("Hello");
}
Now in the _Host.cshtml file, create a script tag with “src” attribute targetting this example.js JavaScript file. We have to do this just before the ending “body” tag. The code is shown in highlighted way below:
@page "/"
@using Microsoft.AspNetCore.Components.Web
@namespace BlazorJS.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<link href="BlazorJS.styles.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png"/>
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
<component type="typeof(App)" render-mode="ServerPrerendered" />
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.server.js"></script>
<script src="~/JS/example.js"></script>
</body>
</html>
Run your app and go to the URL – https://localhost:44366/CallJS and click the button. You will see the alert box with Hello. See the below video.
Another thing which we can do with Blazor JavaScript Interop is to change the DOM. We can append a row to an HTML table so it becomes DOM changing work. Here also we will use the InvokeVoidAsync JavaScript Interop method.
In a new razor component called DOM.razor, create an HTML table with 2 rows of data. Also add a button which on clicking will add a 3rd row to the table by using JavaScript. The code is shown below.
@using Microsoft.JSInterop
@inject IJSRuntime JS;
@page "/dom"
<h1 class="bg-info text-white">Call JavaScript from Blazor</h1>
<div class="form-group">
<table class="table table-sm table-bordered table-striped ">
<thead>
<tr>
<th>Name</th>
<th>City</th>
</tr>
</thead>
<tbody @ref="RowReference">
<tr>
<td>Jack Sparrow</td>
<td>New York</td>
</tr>
<tr>
<td>Bruce Wayne</td>
<td>Gotham</td>
</tr>
</tbody>
</table>
<button class="m-2 btn btn-secondary" @onclick="AddRow">Add a new Row</button>
</div>
@code {
public ElementReference RowReference { get; set; }
public async void AddRow()
{
await JS.InvokeVoidAsync("AddTableRow", RowReference, "Clark Kent", "Metropolis");
}
}
In this code we have used @ref
attribute on the tbody element inorder to create a reference to it. Inside the button’s click, we are calling the JS function called “AddTableRow” and passing this reference of the tbody element as first argument.
We have also passed the first and the last names as the second and third arguments to this function.
await JS.InvokeVoidAsync("AddTableRow", RowReference, "Clark Kent", "Metropolis");
Next, add the “AddTableRow” JS function to the example.js file:
function AddTableRow(elem, firstname, lastname) {
let row = document.createElement("tr");
let cell1 = document.createElement("td");
let cell2 = document.createElement("td");
cell1.innerText = firstname;
cell2.innerText = lastname;
row.append(cell1);
row.append(cell2);
elem.append(row);
}
This function receives the reference of the tbody element as the first argument. Then at the last line of code, appending the row element to it:
elem.append(row);
Run and see how it works. See the video which shows this working:
The row variable contains – a tr element containing 2 td’s that contain the first name and last name send as arguments from C#.
In this example we will be using InvokeAsync<T>(name, args) method to calculate the sum of 2 numbers. So, in a new razor component called Sum.razor, create 2 text boxes for entering numbers and a button. Also add a paragraph which will show the sum of numbers. The code is shown below.
@using Microsoft.JSInterop
@inject IJSRuntime JS;
@page "/Sum"
<h1 class="bg-info text-white">Call JavaScript from Blazor</h1>
<div class="form-group">
<button class="btn btn-secondary" @onclick="ShowAlert">Show JavaScript Alert</button>
</div>
<div class="form-group">
<p class="bg-light text-danger">Sum is: @sum</p>
<label>Number 1</label>
<input type="text" class="form-control" @bind="no1"/>
<label>Number 2</label>
<input type="text" class="form-control" @bind="no2"/>
<button class="m-2 btn btn-secondary" @onclick="ShowSum">Show Sum</button>
</div>
@code {
private string no1;
private string no2;
private int sum;
public async void ShowAlert()
{
await JS.InvokeVoidAsync("JSAlert");
}
public async void ShowSum()
{
sum = await JS.InvokeAsync<int>("FindSum", no1, no2);
StateHasChanged();
}
}
On the button click the JavaScript method called FindSum will be called. We are passing 2 numbers to it as arguments.
sum = await JS.InvokeAsync<int>("FindSum", no1, no2);
Next, add the FindSum JS function in the example.js file.
function FindSum(no1, no2) {
sum = parseInt(no1) + parseInt(no2);
return sum;
}
This JS method calculates the sum of the 2 numbers and returns the result back to Blazor.
The “Sum” variable given in the Razor Component receives the result and it is shown inside the paragraph element.
<p class="bg-light text-danger">Sum is: @sum</p>
Since the state of Sum variable is changed so we have to explicitly tell Blazor to re-render the component. That is why we used the StateHasChanged method.
You can now run and see how it works. We have shown this in the below video:
JavaScript can be use to call Razor Component’s C# methods. The method that invokes C# functions from JS is DotNet.invokeMethodAsync(). It returns a JavaScript Promise. Let us take some example to understand it further.
Create a new Razor Component called CallBlazor.razor inside the Pages folder of your app. Next add the following code to it:
@using Microsoft.JSInterop
@page "/CallBlazor"
<h1 class="bg-info text-white">Call Blazor from JavaScript</h1>
<div class="form-group">
<p class="bg-light text-danger">2nd Indexed No from { 10, 20, 30, 40 } is: <span class="bg-warning text-black-50" id="noIndex"></span></p>
<button class="btn btn-primary" onclick="GetNumber(2)">Call Static method</button>
</div>
@code {
[JSInvokable]
public static Task<int> ReturnArrayAsync(int noIndex)
{
int[] nos = { 10, 20, 30, 40 };
return Task.FromResult(nos[noIndex]);
}
}
There is a button on whose click the JavaScript function GetNumber will be called. We have applied onclick attribute to the button, and it is different than @onclick
event since it calls the JavaScript method and not the C# method.
You have to add this JS method “GetNumber” inside the example.js file of your app. It’s code is given below:
function GetNumber(noIndex) {
var result = DotNet.invokeMethodAsync("BlazorJS", 'ReturnArrayAsync', parseInt(noIndex));
result.then(function (val) {
document.getElementById("noIndex").innerHTML = val;
});
}
The first argument of the invokeMethodAsync method is the name of the assembly containing the function. It is the name of the app which in my case is “BlazorJS”. The second argument is the name of the method to be called. The next arguments are the parameters to be passed to the method that is called by JS.
So, the working of the code will be like this:
result.then(function (val) {
document.getElementById("noIndex").innerHTML = val;
});
Notice the [JSInvokable] applied on the static method so that it can be called by the JS function.
Now run your app and go to the URL – https://localhost:44366/CallBlazor and you will see the result like shown below:
Next example will call instance method of the Razor Component.
In calling an Instance method of Razor Component the procedure is:
Let us create a small example which shows Hello message with the name of the user. The name is sent by the JS function during the call.
So, create a new Razor Component called CallBlazorE.razor with the code given below.
@using Microsoft.JSInterop
@page "/CallBlazorE"
<h1 class="bg-info text-white">Call Blazor from JavaScript</h1>
<div class="form-group">
<p>Message: <span class="btn-warning">@message</span></p>
<button class="btn btn-primary" onclick="SayHello('Lara Croft')">Call JS Method</button>
</div>
@code {
private static Action<string> action;
private string message;
protected override void OnInitialized()
{
action = UpdateMessage;
}
private void UpdateMessage(string name)
{
message = "Hello " + name;
StateHasChanged();
}
[JSInvokable]
public static void ShowHello(string name)
{
action.Invoke(name);
}
}
Explanation : The button will call the JS function SayHello. The code of this function is given below. You need to add it to example.js file:
function SayHello(name) {
DotNet.invokeMethodAsync("BlazorJS", "ShowHello", name);
}
It calls the static method whose name is ShowHello and passes name argument to it. We passed this name as “Lara Croft”, see on button’s click event – onclick="SayHello('Lara Croft')"
.
The “ShowHello” method is a static method that return void and has [JSInvokable] attribute. It invokes action delegate and passes name (which is Lara Croft) to it.
[JSInvokable]
public static void ShowHello(string name)
{
action.Invoke(name);
}
The action delegate code is:
private static Action<string> action;
The action delegate will invoke the Instance method of the Razor Component. It’s type is string which means the Instance method should have a “single” string type as argument.
Note that Action Delegate does not have return type so methods invoked by them should be void return type. To invoke methods that return some value use Func Delegate instead.
On the OnInitialized Lifecycle event, which is called at the very beginning, we have specified that the Action delegate will call UpdateMessage method.
protected override void OnInitialized()
{
action = UpdateMessage;
}
And finally, we have defined this Instance method which the Action Delegate will call.
private void UpdateMessage(string name)
{
message = "Hello " + name;
StateHasChanged();
}
In this method we changed the value of message variable to “Hello Lara Croft” and called the StateHasChanged method to re-render the component, and so the updated message will be shown on the span element.
<span class="btn-warning">@message</span>
Now run your app and go to the URL – https://localhost:44366/CallBlazorE and you will see the result like shown below:
Next, we will take up 2 examples that will use Action Delegate and Func Delegate to call Instance Razor Component method using JavaScript.
Create a new Razor Component file called CallBlazorX.razor and add the following code to it:
@using Microsoft.JSInterop
@page "/CallBlazorX"
<h1 class="bg-info text-white">Call Blazor from JavaScript (instance method)</h1>
<div class="form-group">
<p class="bg-light text-danger">Multiplication is: @mResult</p>
<label>Number 1</label>
<input type="text" class="form-control" @bind="no1" />
<label>Number 2</label>
<input type="text" class="form-control" @bind="no2" />
<button class="m-2 btn btn-secondary" @onclick="FindMultiplication">Calculate</button>
</div>
@code {
private string no1;
private string no2;
private int mResult;
[Inject]
public IJSRuntime JSRuntime { get; set; }
public async Task FindMultiplication()
{
await JSRuntime.InvokeVoidAsync("CallCalculateMultiplication", no1, no2);
}
private static Action<int, int> action;
protected override void OnInitialized()
{
action = Calculate;
}
[JSInvokable]
public static void CalculateMultiplication(int fno, int sno)
{
action.Invoke(fno, sno);
}
public void Calculate(int no1, int no2)
{
mResult = Convert.ToInt32(no1) * Convert.ToInt32(no2);
StateHasChanged();
}
}
Now in your example.js file add the following JS function:
function CallCalculateMultiplication(no1, no2) {
DotNet.invokeMethodAsync("BlazorJS", "CalculateMultiplication", parseInt(no1), parseInt(no2));
}
Explanation : There is a html table that contains 2 text boxes for entering 2 number. We will calculate their multiplication on the button click event.
The button click calls C# method – “FindMultiplication” which in turn call JS function – “CallCalculateMultiplication” and passes the 2 numbers as arguments.
In the JS function, we called the static method “CalculateMultiplication” and passes these 2 numbers as arguments.
We have defined the Action Delegate to invoke a method that accepts 2 arguments of int, int types. See below code:
private static Action<int, int> action;
And we have assigned the instance method that will be called by this delegate inside the OnInitialized lifecycle method:
protected override void OnInitialized()
{
action = Calculate;
}
So, when the Calculate method is called it calculates the multiplication of 2 numbers and updates the mResult variable whose value is shown inside the paragraph element.
public void Calculate(int no1, int no2)
{
mResult = Convert.ToInt32(no1) * Convert.ToInt32(no2);
StateHasChanged();
}
Now run your app and go to the URL – https://localhost:44366/CallBlazorX and you will see the result of the multiplication as the video explains.
Let us now call instance method of Razor Component using Func Delegate. Create a new Razor Component called CallBlazorG.razor inside the Pages folder and add to it the following code:
@using Microsoft.JSInterop
@page "/CallBlazorG"
<h1 class="bg-info text-white">Call Blazor from JavaScript (instance method)</h1>
<div class="form-group">
<p class="bg-light text-danger">Division is: <span id="mResult"></span></p>
<label>Number 1</label>
<input type="text" class="form-control" @bind="no1" />
<label>Number 2</label>
<input type="text" class="form-control" @bind="no2" />
<button class="m-2 btn btn-secondary" @onclick="FindDivision">Calculate</button>
</div>
@code {
private string no1;
private string no2;
[Inject]
public IJSRuntime JSRuntime { get; set; }
public async Task FindDivision()
{
await JSRuntime.InvokeVoidAsync("CallCalculateDivision", no1, no2);
}
public int Calculate(int no1, int no2)
{
int division = no1 / no2;
return division;
}
private static Func<int, int, int> func;
[JSInvokable]
public static int CalculateDivision(int fno, int sno)
{
int result = func.Invoke(fno, sno);
return result;
}
protected override void OnInitialized()
{
func = Calculate;
}
}
Next add the JS function “CallCalculateDivision” inside the example.js file:
function CallCalculateDivision(no1, no2) {
var result = DotNet.invokeMethodAsync("BlazorJS", "CalculateDivision", parseInt(no1), parseInt(no2));
result.then(function (val) {
document.getElementById("mResult").innerHTML = val;
});
}
Explanation : Here we are calculating the division of 2 numbers and are using Func Delegate.
The JS function CallCalculateDivision receives the 2 numbers and in turn calls the static razor component method – “CalculateDivision”.
This static method in turn calls the instance method using Func. The Func is declared as:
private static Func<int, int, int> func;
The first 2 types to the Func specifies the method that will be invoked should have these types of parameters. While the last type specifies the return type of the method. The method is the instance method called “Calculate” and it’s parameters are the same type as the 2 types of func. The return type of calculate is int type – same as that of last parameter of func.
public int Calculate(int no1, int no2)
{
int division = no1 / no2;
return division;
}
In this case the static method returns the result of the division to the JS method.
[JSInvokable]
public static int CalculateDivision(int fno, int sno)
{
int result = func.Invoke(fno, sno);
return result;
}
And once the JS method get’s this result (which is in JavaScript Promise), it shows it inside the span element.
Now run your app and go to the URL – https://localhost:44366/CallBlazorG and you will see the result of the division as the video explains.
With JavaScript you can also call C# class and invoke it’s method. This is useful to do high voltage works like data processing, image processing, scheduled tasks, etc and get the result back to the JS. Let us see this with an example.
First create a new class called Hello.cs in your app. It’s code is given below.
using Microsoft.JSInterop;
namespace BlazorJS
{
public class Hello
{
public Hello(string name)
{
Name = name;
}
public string Name { get; set; }
[JSInvokable]
public string SayHello() => $"Hello, {Name}!";
}
}
It is a simple class that has a JSInvokable method called SayHello(). It returns “hello message” back to the JS function which will call it.
Next, create a new Razor Component called CallClassJS.razor with the following code:
@using Microsoft.JSInterop
@inject IJSRuntime JS;
@page "/CallClassJS"
<h1 class="bg-info text-white">Call Class with JavaScript from Blazor</h1>
<div class="form-group">
<button class="btn btn-secondary" @onclick="HandleClick">
Call
</button>
</div>
@code {
[Inject]
public IJSRuntime JSRuntime { get; set; }
public async Task HandleClick()
{
await JSRuntime.InvokeVoidAsync("CallClass", DotNetObjectReference.Create(new Hello("Dave")));
}
}
In this Razor Component there is a button, on it’s click event the JavaScript function called CallClass is called. Notice we are passing the object of the class Hello.cs as the argument to this JS method.
To create the object I have used DotNetObjectReference.Create() method.
await JSRuntime.InvokeVoidAsync("CallClass", DotNetObjectReference.Create(new BlazorJS.Models.Hello("Dave")));
Next, add the CallClass JS function inside the example.js whose code is given below.
function CallClass(obj) {
var result = obj.invokeMethodAsync("SayHello");
result.then(function (val) {
alert(val);
});
}
This JavaScript function calls the Hello.cs class method “SayHello”. It is able to do it as it receives the object of the class in it’s argument.
var result = obj.invokeMethodAsync("SayHello");
The value received back is shown in an alert box.
result.then(function (val) {
alert(val);
});
Now run your app and go to the URL – https://localhost:44366/CallClassJS to see how it works.
You can download the full source codes:
In this tutorial we covered every topic related to Blazor JavaScript Interop. Now you can easily integrate any JS library or custom code in your Blazor app.
I wonder why MS made the decision to have [JSInvokable] only bind to static functions. Maybe it’s a security thing. To me it seems like a workaround from an unrelated issue.