JS Interop in MAUI Hybrid App on target Android not working with inheritation

69 Views Asked by At

I have a Maui App targeting Android and Windows. In this app I use scoped JS files for my custom components. All custom components are inheriting from a base class called ComponentBaseExtended which inherits from ComponentBase. in ComponentBaseExtended i have a method trying to load JS modules for the custom component if existing.

This is part of my scoped CS (SwipeItem.razor.cs) where i invoke the method "SwipeRight" not working:

if (swipeDirection == MudBlazor.SwipeDirection.LeftToRight && !_editDrawerOpen)
{
    // from default to edit
    motionClass = "move-right";
    deleteIconClass = "icon-hidden";
    editIconClass = "icon-visible";
    await JSRuntime.InvokeVoidAsync("SwipeRight");
}

This is my scoped JS (SwipeItem.razor.js):

let isModuleLoaded = false;

export function initModule() {
    console.log("initModule - Value of isModuleLoaded:", isModuleLoaded);
    isModuleLoaded = true;
}


export function SwipeRight() {
    console.log("adjustWidthOnSwipeRight - Value of swipeDistance:");
}

export function moduleLoaded() {
    console.log("moduleLoaded - Value of isModuleLoaded:", isModuleLoaded);
    return isModuleLoaded;
}

This is how i load the module and execute its functions (ComponentBaseExtended.razor.cs):

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        var type = typeof(TComponent);
        var namespaceParts = type.Namespace?.Split('.') ?? Array.Empty<string>();
        var folderPath = string.Join("/", namespaceParts.Skip(1)); // Skip the root namespace
        var componentName = type.Name;
        var scriptPath = $"./{folderPath}/{componentName}.razor.js";

        try
        {
            // Load the JS module
            var module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", scriptPath);
            await module.InvokeVoidAsync("initModule");
            var isLoaded = await module.InvokeAsync<bool>("moduleLoaded");
            if (!isLoaded)
            { }
            else
            {
                await module.InvokeVoidAsync("SwipeRight");
            }
        }
        catch (JSException jsex)enter code here
        {
            // Handle the case where the script doesnt exist
            Console.WriteLine($"No JS module found for {componentName}, or there was an error in loading it.");
        }
    }
}

Well on my ComponentBaseExtended i successfully can load the module, after that i successfully execute methods of this module called initModule, SwipeRight and moduleLoaded. I also see the debug lines in Output. But SwipeRight method can not be executed from SwipeItem.razor.cs, I get this error: [chromium] Error: Could not find "adjustWidthOnSwipeRight" ("adjustWidthOnSwipeRight" was undefined).

I guess i am having some issues due to scope of module, which seems to be lost in custom component. How to get rid of this?!

1

There are 1 best solutions below

0
GeKu On

Found my error. It seems that - and correct me if I am wrong - JSRuntime is a scoped service which means its lifecycle scoped to base class where my functions work fine. But in my custom component i do have another scope, so i loose the loaded module. The trick was to load the module in base class and store it in a protected field for usage in my custom component. Instead of this call:

    await JSRuntime.InvokeVoidAsync("SwipeRight");

i now call it from my field:

    await this.module.InvokeVoidAsync("SwipeRight");