7

I have created a Blazor Webassembly Project and added a key listener in JavaScript, which is listening to every key stroke on the DOM document. Everything works as expected, however when I open the Blazor page where the key listener is registered and later open it again, the following error occurs in the Web Browser:

There is no tracked object with id '2'. Perhaps the DotNetObjectReference instance was already disposed. (Parameter 'dotNetObjectId')

Obviously the object "dotnethelper" is disposed but the Javascript is still listening / getting called.

Basically I implemented the "Component instance .NET method helper class" from the Microsoft Documentation.

Blazor Page:

Note: The IDisposable is injected on the top and the Dispose function is getting called.

@code {
    private KeyListenerInvokeHelper _keyListenerInvokeHelper;
    private DotNetObjectReference<KeyListenerInvokeHelper>? objRef;

    protected override async Task OnInitializedAsync()
    {
        objRef = DotNetObjectReference.Create(_keyListenerInvokeHelper);
        await JS.InvokeVoidAsync("initializeKeyListener", objRef);    
    }

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

Javascript File:

window.initializeKeyListener = (dotnetHelper) => {
    document.addEventListener('keydown', logKey);
    function logKey(e) {     
        dotnetHelper.invokeMethod('OnKeyDown', e.key);
        console.log('key down ' + e.key);
    }
}

KeyListenerInvokeHelper:

public class KeyListenerInvokeHelper
{
    private readonly Action<string> action;

    public KeyListenerInvokeHelper(Action<string> action)
    {
        this.action = action;
    }

    [JSInvokable("OnKeyDown")]
    public void OnKeyDown(string key)
    {
        action.Invoke(key);
    }
}

What have I tried so far?

  • I tried to reset the function on window.initializeKeyListener (i.e. setting window.initializeKeyListener), however this did not achieve anything
  • I tried removing the eventlistener on the 'keydown' event.
1
  • See here for related issue and solutions. Commented Dec 27, 2022 at 23:25

1 Answer 1

6

When you dispose of your object, you need to remove the event listener as well. You mentioned I tried removing the eventlistener on the 'keydown' event., but perhaps the way you did it was not correct? My javascript is a little rusty, but I think you could do something like the following:

var logkey;
window.initializeKeyListener = (dotnetHelper) => {
    logkey = (e) => {
        dotnetHelper.invokeMethod('OnKeyDown', e.key);
        console.log('key down ' + e.key);
    };
    document.addEventListener('keydown', logkey);
}

window.removeKeyListener = () => {
    document.removeEventListener('keydown', logkey);
}

and then in your component:

@implements IAsyncDisposable

public async ValueTask DisposeAsync()
{
    await JSRuntime.InvokeVoidAsync("removeKeyListener");
    objRef?.Dispose();
}

Having said that, perhaps calling a static method in C# using [JSInvokable] would be better suited for your use case?

Sign up to request clarification or add additional context in comments.

2 Comments

This is very good, and I added a request for them to add it to the docs.
mind, for BLAZOR SERVER this suffers from the following issue: when reloading the page (or simply click home button to go to blank) this will cause a Microsoft.JSInterop.JSDisconnectedException: 'JavaScript interop calls cannot be issued at this time. This is because the circuit has disconnected and is being disposed.' see: stackoverflow.com/questions/72488563/… github.com/dotnet/aspnetcore/issues/33336

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.