IJSRuntime – Demo Global JS & JS Module

Cover: gọi JavaScript từ Blazor bằng global functionES module, nhận giá trị trả về, gọi async, và dispose module đúng cách.


1️⃣ Global JS – gọi hàm toàn cục từ window

Global Result: none

Cách này dùng khi hàm JavaScript được khai báo toàn cục (ví dụ trong window hoặc file JS load trực tiếp vào page).

Xem code
Razor (Pages/IJSRuntimeDemo.razor)

<button class="btn btn-primary" @onclick="Global_ShowAlert">Alert</button>
<button class="btn btn-success" @onclick="Global_GetBrowserInfo">Get Browser Info</button>
<button class="btn btn-warning" @onclick="Global_GetCurrentTime">Get Current Time</button>

<p><b>Global Result:</b> @GlobalResult</p>

@code {
    private string GlobalResult = "none";

    private async Task Global_ShowAlert()
    {
        await JS.InvokeVoidAsync("blazorGlobal.showAlert", "Hello from Blazor (Global JS)");
        GlobalResult = "✅ Alert đã được gọi";
    }

    private async Task Global_GetBrowserInfo()
    {
        GlobalResult = await JS.InvokeAsync<string>("blazorGlobal.getBrowserInfo");
    }

    private async Task Global_GetCurrentTime()
    {
        GlobalResult = await JS.InvokeAsync<string>("blazorGlobal.getCurrentTime");
    }
}
JavaScript global (wwwroot/js/ijsruntime-global-demo.js)

window.blazorGlobal = {
    showAlert: function (message) {
        alert(message);
    },

    getBrowserInfo: function () {
        return `UserAgent: ${navigator.userAgent}`;
    },

    getCurrentTime: function () {
        return new Date().toLocaleTimeString();
    }
};

2️⃣ JS Module – import module rồi gọi hàm

Module Ready: False
Module Result: none

Cách này dùng với file ES module. Đây là cách hiện đại hơn, gọn scope và dễ quản lý hơn so với global function.

Xem code
Razor (Pages/IJSRuntimeDemo.razor)
@inject IJSRuntime JS
@implements IAsyncDisposable

<button class="btn btn-dark" @onclick="Module_Init">Init Module</button>

<button class="btn btn-info text-white" @onclick="Module_AddNumbers">Add 10 + 20</button>

<button class="btn btn-secondary" @onclick="Module_FormatMessage">Format Message</button>

<button class="btn btn-outline-danger" @onclick="Module_Dispose">Dispose Module</button>

<p><b>Module Ready:</b> @ModuleReady</p>
<p><b>Module Result:</b> @ModuleResult</p>



@code {
private IJSObjectReference? _module;
private string ModuleResult = "none";
private bool ModuleReady = false;

private async Task EnsureModuleAsync()
{
    if (_module is null)
    {
        _module = await JS.InvokeAsync<IJSObjectReference>(
            "import",
            "./js/ijsruntime-module-demo.js");

        ModuleReady = true;
    }
}

private async Task Module_Init()
{
    await EnsureModuleAsync();
    ModuleResult = "Module initialized";
}

private async Task Module_AddNumbers()
{
    await EnsureModuleAsync();
    var result = await _module!.InvokeAsync<int>("addNumbers", 10, 20);
    ModuleResult = $"10 + 20 = {result}";
}

private async Task Module_FormatMessage()
{
    await EnsureModuleAsync();
    ModuleResult = await _module!.InvokeAsync<string>(
        "formatMessage",
        "Hello from Blazor Module");
}

private async Task Module_Dispose()
{
    if (_module is not null)
    {
        await _module.DisposeAsync();
        _module = null;
        ModuleReady = false;
        ModuleResult = "Module disposed";
    }
}

public async ValueTask DisposeAsync()
{
    if (_module is not null)
    {
        await _module.DisposeAsync();
    }
}
}
JavaScript module (wwwroot/js/moduleInterop.js)

export function addNumbers(a, b) {
    return a + b;
}

export function formatMessage(message) {
    return `[Module] ${message} at ${new Date().toLocaleTimeString()}`;
}

3️⃣ So sánh nhanh: Global vs Module

  • Global JS: gọi nhanh, phù hợp demo nhỏ hoặc code cũ, nhưng dễ làm ô nhiễm global scope.
  • JS Module: hiện đại hơn, tách scope rõ ràng, dễ bảo trì và nên ưu tiên trong dự án lớn.
  • Khi dùng module, nhớ dispose IJSObjectReference nếu component có thể bị hủy nhiều lần.


4️⃣ JS gọi C# (JS → .NET)

Result: none

JavaScript có thể gọi trực tiếp method C# bằng [JSInvokable].

Xem code
Razor

<button @onclick="CallJsToInvokeDotNet">
    JS gọi C#
</button>

<p><b>Result:</b> @DotNetResult</p>
C#

private string DotNetResult = "none";

private async Task CallJsToInvokeDotNet()
{
    await JS.InvokeVoidAsync("blazorGlobal.callDotNet");
}

[JSInvokable]
public static string DotNetHello()
{
    return "Hello from C#";
}
JavaScript

window.blazorGlobal.callDotNet = async function () {

    const result = await DotNet.invokeMethodAsync(
        'BlazorSample',
        'DotNetHello'
    );

    alert(result);
}

An error has occurred. This application may no longer respond until reloaded. Reload 🗙
Web hosting by Somee.com