Amir Imam
Amir Imam

Reputation: 1043

Why Blazor app showing an error with any page reload

I am working on a project with Blazor. I sometimes need to use JavaScript, and I need to include different js in each page. As far as I know, the only way to do so is by adding it using a JS function and Blazor JS invoke. So what I did is:

in _Host.razor

function addScriptFile(fileName){
    var script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.setAttribute("src", file);
    document.getElementById(divName).appendChild(script);
}

Then in each page (component):

@inject IJSRuntime Js;
@functions{
    protected override async void OnAfterRender()
    {
        await Js.InvokeAsync<object>("addScriptFile","~/js/myFile.js");
    }
}

The problem happens when the page is re-loaded. It throws an error

System.InvalidOperationException: JavaScript interop calls cannot be issued at this time. This is because the component is being prerendered and the page has not yet loaded in the browser or because the circuit is currently disconnected. Components must wrap any JavaScript interop calls in conditional logic to ensure those interop calls are not attempted during prerendering or while the client is disconnected.

From what I understand, I am trying to invoke some javascript code before render completed. So I have used IComponentContext to make sure that the server is connected.

In my attempt to fix this issue, I have created a new Blazor project without any JS files, but it throws the same error on reloading page

I tried to make this:

@inject IComponentContext ComponentContext
@functions{
    protected override void OnAfterRender()
    {
        if(ComponentContext.IsConnected)
        {
            //adding scripts
        }
    }
}

How can I make JavaScript work with Blazor in this way, and how can I fix that error?

Upvotes: 5

Views: 10854

Answers (2)

Rdq
Rdq

Reputation: 46

For me it turned out that in _Layout.cshtml were missing

<base href="/" />

in the header.

I've spend full day struggling with 0 errors in logs and rolling back to prev version line by line.

Upvotes: 0

Chris Sainty
Chris Sainty

Reputation: 8521

In your code sample, there are a couple of issues.

@inject IJSRuntime Js;

@functions {
    protected override async void OnAfterRender()
    {
        await Js.InvokeAsync<object>("addScriptFile","~/js/myFile.js");
    }
}

Firstly, you should use code not functions. Code is specific to Blazor components, functions is used for Razor Pages and MVC.

Secondly, never use async void in Blazor, the exception to the rule would be to run async code in an event handler. See this article for more info.

Thirdly, you have the ~ character at the start of your script location. This character doesn’t work with Blazor (and is pretty pointless anyway in my opinion), it’s only valid with MVC and Razor Pages. If you want to load a script from the root of your application then just use a /, if you want to load it from a relative location then don’t prefix the location with anything.

So with all that said, I think your code should look like this.

@inject IJSRuntime Js;
@inject IComponentContext ComponentContext

@code {
    protected override async Task OnAfterRenderAsync()
    {
        if (!ComponentContext.IsConnected)
        {
            return;
        }

        await Js.InvokeAsync<object>("addScriptFile","/js/myFile.js");
    }
}

Upvotes: 6

Related Questions