Scenario Description
Greetings, I am currently working on a Blazor WebAssembly project that involves JavaScript interop. Initially, I had this functionality working in a .razor page. However, I now intend to encapsulate and centralize these JavaScript invocations into a separate class for better organization and reusability across different pages.
Current Challenge
The new class where I plan to consolidate the JavaScript invokes is located in Classes/JSFunctionHandler_Shared.cs, accessing a JavaScript function in TestEmbed.js. This integration is supposed to work on the page Pages/TestJSEmbed.razor for testing purposes, but unfortunately, it results in an exception upon initializing the JavaScript part within the new class.
Blazor Page Direct JavaScript Access (currently functional):
@page "/TestJS"
@inject IJSRuntime JsRuntime
<h3>Testing JavaScript (within razor component)</h3>
<button @onclick="onTestJS">Test JavaScript</button>
@code {
public async Task onTestJS()
{
await JsRuntime.InvokeAsync<object>("TestJS"); // invoking Test.js
}
}
Blazor Page utilizing JS in a Class (not functioning as expected):
@page "/TestJSEmbed"
@using Classes
@inject IJSRuntime JsRuntime
<h3>Testing JS Embed (interop through a class)</h3>
<button @onclick="onTestJSEmbed">Test JavaScript</button>
@code {
JSFunctionHandler JSTest = new JSFunctionHandler();
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
await JSTest.Init();
}
public async Task onTestJSEmbed()
{
await JSTest.TestFunction_JSTestEmbed();
}
}
Class with JavaScript Handling:
using Microsoft.JSInterop;
using Microsoft.AspNetCore.Components;
namespace Classes
{
public partial class JSFunctionHandler
{
[Inject]
public IJSRuntime JSRuntime { get; set; }
private IJSObjectReference _jsModule;
public async Task Init()
{
_jsModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./JS/TestEmbed.js");
}
public async Task TestFunction_JSTestEmbed()
{
await _jsModule.InvokeAsync<object>("JSTestEmbed");
}
}
}
It's important to note that I have not directly added the JavaScript file I aim to access in the "JSFunctionHandler" class to the index.html file. Instead, I load it dynamically within the init() method. This approach was chosen due to the lack of concrete examples using index.html for such task. Naturally, this can be modified in the future.
A sample project showcasing both scenarios mentioned above is available on Github
Exception Encountered (when opening the TestJSEmbed.razor page)
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Value cannot be null. (Parameter 'jsRuntime') System.ArgumentNullException: Value cannot be null. (Parameter 'jsRuntime') at Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync[IJSObjectReference](IJSRuntime jsRuntime, String identifier, Object[] args) at Classes.JSFunctionHandler.Init() in C:\Users\Operator\Documents\GitHub\testdata\BlazorWASM_JSInvoke\ExperimentalTest\Classes\JSFunctionHandler_Shared.cs:line 16 at ExperimentalTest.Pages.TestJSEmbed.OnAfterRenderAsync(Boolean firstRender) in C:\Users\Operator\Documents\GitHub\testdata\BlazorWASM_JSInvoke\ExperimentalTest\Pages\TestJSEmbed.razor:line 16