JS Interop – Working with JavaScript in Blazor

JS Interop – Working with JavaScript in Blazor

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.

In this tutorial we are going to cover the whole process of JS Interop in Blazor by taking multiple examples.

IJSRuntime Interface

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; }

Calling JavaScript functions from Blazor

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.

You will be interested to read my previous tutorial called How to use Razor Components in Blazor where I provided complete information about this topic.

Example of InvokeVoidAsync – JavaScript Alert box in Blazor

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.

Blazor JavaScript Interop alert box

Changing DOM with JavaScript in Blazor

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#.

Blazor JS Interop InvokeAsync DOM with JavaScript

Understand Razor Components Lifecycle Methods of Blazor and use it to create high performance Razor Components.

Example of InvokeAsync<T>(name, args) – Calculating Sum with JavaScript in Blazor

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:

Blazor JavaScript interoperability InvokeAsync example

Calling Blazor methods (C# functions) from JavaScript

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.

The C# methods that are invoked with JS function should have [JSInvokable] attribute.

Static Blazor Method Call from JavaScript

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:

  • 1. The button click will call the JS function GetNumber and passes an argument of 2. This argument specifies the 2nd index number to be fetched from an int array.
  • 2. The JS function calls ReturnArrayAsync static method given on the Razor Component and passes “2” as an argument. The function DotNet.invokeMethodAsync() calls this method, and it receives back a JavaScript promise which contain the 2nd Index value from the number array. See the code of ReturnArrayAsync method.
  • 3. Finally, the ReturnArrayAsync method returns the result (2nd index number) which is received back in the JS function. Then it is shown inside the noIndex span.
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:

Static Blazor Method Call from JavaScript

Next example will call instance method of the Razor Component.

I have explained in my tutorial how to create Advanced Razor Components features in Blazor, you will love it.

Calling Instance method of Razor Component with JavaScript

In calling an Instance method of Razor Component the procedure is:

  • 1. The JS method calls the Static method of the Component.
  • 2. The static method in turn invokes the instance method by the use of delegate.

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:

Instance Blazor Method Call from JavaScript

Next, we will take up 2 examples that will use Action Delegate and Func Delegate to call Instance Razor Component method using JavaScript.

Example 1 – Multiplication of Numbers using Action Delegate

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.

Blazor js interop blazor action delegate

Example 2 – Division of Numbers using Func Delegate

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.

Related tutorialBlazor Events and Data Bindings

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.

Call Class with JS in Blazor

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:

Download

Conclusion

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.

Next tutorial – Blazor forms and validation

SHARE THIS ARTICLE

  • linkedin
  • reddit
yogihosting

ABOUT THE AUTHOR

I hope you enjoyed reading this tutorial. If it helped you then consider buying a cup of coffee for me. This will help me in writing more such good tutorials for the readers. Thank you. Buy Me A Coffee donate

Comments

  1. RG says:

    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.

Leave a Reply

Your email address will not be published. Required fields are marked *