A binding generator for JS, Call any JS function or property in Blazor Wasm and Server (Including MAUI hybrid) without writing JS wrappers.
Use Nuget Package Manager or .Net CLI
dotnet add package BlazorBindGen
@inject IJSRuntime runtime @using BlazorBindGen @using static BlazorBindGen.BindGen @using JSCallBack=System.Action<BlazorBindGen.JObjPtr[]>; //optional Typedef
2. Intitialize the BindGen
```cs
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
await InitAsync(runtime);
}
//on Server
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (!firstRender)
return;
await InitAsync(runtime);
}
-> Js code is for explaination purpose only , you do not need to write js code anywhere.
-> On Server use Async Version of functions (non async functions will throw PlatformNotSupportedException
)
// js equivalent
await import("https://unpkg.com/ml5@latest/dist/ml5.min.js");
//c# side
await ImportAsync("https://unpkg.com/ml5@latest/dist/ml5.min.js");
// js equivalent, importing modules
let ml5=await import("https://unpkg.com/ml5@latest/dist/ml5.min.js");
//c# side
var ml5Ptr=await ImportRefAsync("https://unpkg.com/ml5@latest/dist/ml5.min.js");
//js side
var audio=new Audio(param);
//c# side code
var_audio=Window.Construct("Audio",param); /* js reference to Audio Player */
//js equivalent
alert("Hello");
//code to call alert in C#
Window.CallVoid("alert","hello");
//js equivalent
var video = document.querySelector("#videoElement");
//here document is property of window , and dcument has function querySelector
//c# code
var video = Window["document"].CallRef("querySelector", "#videoElement");
//["documemnt"] will return reference to Property document of window , another way to write it is
JObjPtr video = Window.PropRef("document").CallRef("querySelector", "#videoElement");
//CallRef function calls JS function and Returns a reference to it, instead of whole object
// equivalent js code
var ctx = c.getContext("2d");
var grd = ctx.createRadialGradient(75, 50, 5, 90, 60, 100);
ctx.fillStyle = grd;
//c# side
var ctx=canvas.CallRef("getContext","2d");
var grad = ctx.CallRef("createLinearGradient", 0,0,400,0);
ctx.SetPropRef("fillStyle",grad);
//assign a reference to grad(a JobjPtr reference) to property fillStyle of canvas context
//js
var audio=new Audio();
audio.currentTime=6; //set
console.log(audio.currentTime); //get
//c# equivalent
JObjPtr _audio=Window.Construct("Audio"); /* js reference to Audio Player */
public double CurrentTime
{
get => _audio.PropVal<double>("currentTime");
set => _audio.SetPropVal("currentTime", value);
}
//js equivalent
var audio=new Audio();
audio.onloadeddata=()=>{ console.log("loaded"))};
//cs equivalent
{
var _audio=Window.Construct("Audio"); /* js reference to Audio Player */
_audio.SetPropCallBack("onloadedmetadata", (_) => OnLoadedMetaData?.Invoke(this));
}
public delegate void LoadedMetaDataHandler(object sender);
public event LoadedMetaDataHandler OnLoadedMetaData;
Be sure to check out sampleApp for more examples
@page "/ml5"
@using BlazorBindGen
@using static BlazorBindGen.BindGen
@using JSCallBack=System.Action<BlazorBindGen.JObjPtr[]>; //optional only needed to simplify callback type name
@inject IJSRuntime runtime
@if (isLoaded)
{
<input type="text" class="bg-dark text-white border-light" @bind="predictText" placeholder="write review here " style="font-size:18px"/>
<button class="btn btn-primary" id="mbtn" @onclick="Predict">Predict</button><br /><br />
if(score>0)
{
<div class="alert alert-primary">
<p>Review: @GetEmoji() <br />Score: @score</p>
</div>
}
}
else
{
<div class="alert alert-warning">
Fetching Movie Review Dataset (~16 MB)
</div>
}
@code
{
JWindow win;
public JObjPtr sentiment;
string predictText;
bool isLoaded = false;
double score;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
await Init(runtime);
win = Window;
await ML5Init();
}
async Task ML5Init()
{
await Import("https://unpkg.com/ml5@latest/dist/ml5.min.js");
Console.Clear();
var ml5 = win["ml5"];
sentiment = ml5.CallRef("sentiment", "movieReviews", (JSCallBack)OnModelLoaded);
}
void Predict()
{
var v = sentiment.Call<Score>("predict", predictText);
score=v.score;
StateHasChanged();
}
void OnModelLoaded(params JObjPtr[] args)
{
isLoaded = true;
StateHasChanged();
}
string GetEmoji()
{
if (score > 0.7)
return "😀";
else if (score > 0.4)
return "😐";
else
return "😥";
}
record Score(double score);
}
Above example binding could also be generated with Source Generator for WASM .
using BlazorBindGen.Attributes;
namespace SampleApp.JSBinding
{
[JSWindow] // represents JS Window class
public static partial class DomWindow
{
[JSProperty]
private static ML5 ml5; // refers to window.ml5 prop js side
}
[JSObject("https://unpkg.com/ml5@latest/dist/ml5.min.js")]
public partial class ML5
{
[JSFunction("sentiment")]
public partial Sentiment Sentiment(string modelName,OnModelLoadHandler onModelLoad);
[JSCallback]
public delegate void OnModelLoadHandler();
[JSConstruct("p5")]
public partial Sentiment Construct();
}
[JSObject]
public partial class Sentiment
{
[JSFunction("predict")]
public partial Score Predict(string text);
}
public record Score(double score);
}
see usage here