Day 8: JavaScript Interop

Call JavaScript from C# and vice versa, use JS isolation, and integrate JS libraries.
1. Why JavaScript Interop?
Access browser APIs (e.g.,
localStorage
, geolocation).Use existing JavaScript libraries (e.g., charts, animations).
Direct DOM manipulation when needed.
2. Call JavaScript from C# (IJSRuntime
)
Use IJSRuntime
to invoke JS functions.
Example: Show a Browser Alert
@page "/js-demo"
@inject IJSRuntime JSRuntime
<button @onclick="ShowAlert">Show Alert</button>
@code {
private async Task ShowAlert()
{
await JSRuntime.InvokeVoidAsync("alert", "Hello from Blazor!");
}
}
3. Call C# from JavaScript
Use DotNetObjectReference
to pass C# methods to JS.
Example: JS Timer that Updates Blazor UI
Component (C#):
@page "/timer"
@implements IDisposable
@inject IJSRuntime JSRuntime
<h3>Timer: @currentCount</h3>
@code {
private int currentCount = 0;
private DotNetObjectReference<TimerComponent>? dotNetRef;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
dotNetRef = DotNetObjectReference.Create(this);
await JSRuntime.InvokeVoidAsync("startTimer", dotNetRef);
}
}
[JSInvokable]
public void UpdateTimer() => currentCount++;
public void Dispose() => dotNetRef?.Dispose();
}
JavaScript (wwwroot/js/timer.js
):
function startTimer(dotNetRef) {
setInterval(() => {
dotNetRef.invokeMethodAsync('UpdateTimer');
}, 1000);
}
Import JS in index.html
(Blazor WebAssembly):
<script src="js/timer.js"></script>
Run HTML
4. JavaScript Isolation (ES6 Modules)
Load JS modules directly in components for better organization.
Component:
@page "/module-demo"
@inject IJSRuntime JSRuntime
<button @onclick="CallModule">Call JS Module</button>
@code {
private async Task CallModule()
{
var module = await JSRuntime.InvokeAsync<IJSObjectReference>(
"import",
"./js/utilities.js"
);
await module.InvokeVoidAsync("showConfetti");
}
}
JavaScript (wwwroot/js/utilities.js
):
export function showConfetti() {
// Add confetti animation logic
}
5. Real-World Example: Clipboard API
Integrate the browser’s clipboard API to copy text.
Component:
@page "/clipboard"
@inject IJSRuntime JSRuntime
<input @bind="textToCopy" />
<button @onclick="CopyToClipboard">Copy</button>
@code {
private string textToCopy = "";
private async Task CopyToClipboard()
{
await JSRuntime.InvokeVoidAsync("navigator.clipboard.writeText", textToCopy);
}
}
6. Error Handling
Wrap JS interop calls in try-catch
blocks:
try {
await JSRuntime.InvokeVoidAsync("someJSFunction");
}
catch (JSException ex) {
Console.WriteLine($"JS Error: {ex.Message}");
}
7. Practice Task
Create a WindowSize
Component:
Use JS interop to get the browser window’s width/height.
Display the values in Blazor.
Update the values when the window resizes.
Solution:
@page "/window-size"
@inject IJSRuntime JSRuntime
@implements IDisposable
<h3>Window Size</h3>
<p>Width: @width px</p>
<p>Height: @height px</p>
@code {
private int width;
private int height;
private DotNetObjectReference<WindowSize>? dotNetRef;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
dotNetRef = DotNetObjectReference.Create(this);
await JSRuntime.InvokeVoidAsync("setupResizeListener", dotNetRef);
}
}
[JSInvokable]
public void UpdateSize(int newWidth, int newHeight)
{
width = newWidth;
height = newHeight;
StateHasChanged();
}
public void Dispose() => dotNetRef?.Dispose();
}
JavaScript (wwwroot/js/windowResize.js
):
function setupResizeListener(dotNetRef) {
window.addEventListener('resize', () => {
dotNetRef.invokeMethodAsync('UpdateSize', window.innerWidth, window.innerHeight);
});
}
8. Key Takeaways
IJSRuntime
: Invoke JS functions from C#.DotNetObjectReference
: Pass C# methods to JS.JS Isolation: Use ES6 modules for cleaner code.
Error Handling: Catch JS exceptions in C#.
Subscribe to my newsletter
Read articles from Abdullah Al Masum directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
