How do I initiate call to DotNet method from JS.
- My index.razor calls JS 'Create' function and passes json filename that need to be opened.
- index.js opens the file and parses its content. As you could see that only after the file is parsed (after satifysing (data[i].name === "something") condition), window.sendName can return value to blazor.
- So, I would like to know how JS(index.js) could initiate call to blazor by itself, rather than initiated from navbar.razor.
- Because when call initiated from navbar.razor as below, navbar is loaded before json is parsed, so cant return proper value.
My code:
Index.razor:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await JSRuntime.InvokeVoidAsync("Create", fileName);
}
JS:
function Create(fileName) {
$.getJSON(fileName, function (data) {
data.forEach((eachline, i) => {
if (data[i].name === "something") {
window.sendName= () => {
var val = "Abc";
return val;
}
}
}
}
}
NavBar.Razor:
<a href="" @onclick=getName>GetName</a>
public string? Name { get; set; }
[JSInvokable]
private async Task getName()
{
Name= await JSRuntime.InvokeAsync<string>("sendName");
}
I tried using example in below link. But doesn't seem to work as I expect.
1 Answer
First, you need to create a helper class. The class should have a JSInvokable method that raises an event when called.
SendNameHelper.cs:
public class SendNameHelper
{
public event Action<string>? OnNameSent;
[JSInvokable]
public Task SendNameAsync(string name)
{
OnNameSent?.Invoke(name);
return Task.CompletedTask;
}
}
Register this class as a service in Program.cs. Blazor components are now able to inject the service and subscribe to the event.
Program.cs:
// for blazor wasm
builder.Services.AddSingleton<SendNameHelper>();
// if blazor server add as scoped
builder.Services.AddScoped<SendNameHelper>();
Index.razor should use IJSRuntime to call the create JS function and pass to the function a reference to the SendNameHelper service.
Index.razor:
@inject IJSRuntime JS
@inject SendNameHelper SendNameHelper
...
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var sendNameHelperReference = DotNetObjectReference.Create(SendNameHelper);
await JS.InvokeVoidAsync("create", fileName, sendNameHelperReference);
}
}
}
NavBar.razor should simply inject the SendNameHelper service and subscribe to the OnNameSent event.
NavBar.razor:
@inject SendNameHelper SendNameHelper
@implements IDisposable
...
@code {
protected override void OnInitialized()
{
SendNameHelper.OnNameSent += HandleNameSent;
}
private void HandleNameSent(string name)
{
// do stuff with name
Console.WriteLine(name);
}
public void Dispose()
{
SendNameHelper.OnNameSent -= HandleNameSent;
}
}
And finally create function should use the SendNameHelper reference to invoke the SendName method:
JS:
window.create = (fileName, dotNetHelper) => {
$.getJSON(fileName, function (data) {
data.forEach((eachline, i) => {
if (data[i].name === 'something') {
dotNetHelper.invokeMethodAsync('SendNameAsync', 'something');
}
});
dotNetHelper.dispose();
});
};