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