javascriptblazorblazor-webassemblyblazor-component

Blazor JSInvokable without static function


I have my Blazor component with some JavaScript code. When there is a click detected by the JavaScript code, I want to call an JSInvokable function in my Blazor component to update the UI.

So, I created a function like this

[JSInvokable]
public static async Task ChangeTab(string val)
{
    Console.WriteLine(val);
}

in the JavaScript, I added the following line:

DotNet.invokeMethodAsync('myComponent', 'ChangeTab', tabText);

This code is working and the function ChangeTab receives the value I expected. The problem is that this function is static. So, I can't change the variables. I tried to change the code like this (ActivatePage is a function in the component)

[JSInvokable("ChangeTab")]
public async Task ChangeTab(string val)
{
    ActivatePage(val);
}

but in this case I get an error because the function is not static.

Error: System.ArgumentException: The assembly 'PSC.Blazor.Components.ScrollTabs' does not contain a public invokable method with [JSInvokableAttribute("ChangeTab")]

enter image description here

I checked the Microsoft documentation but I don't understand how to change the JSInvokable function to not be static.


Solution

  • You need to pass a DotNetObjectReference of the component (which has the JSInvokable method) to JavaScript. This is usually done after the component renders.

    Example.razor:

    @implements IDisposable
    @inject IJSRuntime JS
    
    @code {
        private DotNetObjectReference<Example>? dotNetHelper;
    
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                dotNetHelper = DotNetObjectReference.Create(this);
                await JS.InvokeVoidAsync("Helpers.setDotNetHelper", dotNetHelper);
            }
        }
    
        [JSInvokable("ChangeTab")]
        public async Task ChangeTab(string val)
        {
            ActivatePage(val);
        }
    
        public void Dispose()
        {
            dotNetHelper?.Dispose();
        }
    }
    

    Then use that reference to call your component's method from JavaScript:

    <script>
      class Helpers {
        static dotNetHelper;
    
        static setDotNetHelper(value) {
          Helpers.dotNetHelper = value;
        }
    
        static async changeTab(tabText) {
          await Helpers.dotNetHelper.invokeMethodAsync('ChangeTab', tabText);
        }
      }
    
      window.Helpers = Helpers;
    </script>
    

    Call Helpers.changeTab from JavaScript when you want to change the tab.

    Documentation