Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i get Javascript Callback in .Net Blazor?

Tags:

c#

interop

blazor

Is there a way to add callback to Javascript and get the result in Blazor? Apart from JS Promises.

for example, let say i want to load a file

Javascript Code

window.readFile = function(filePath, callBack) {
    var reader = new FileReader();
    reader.onload = function (evt) {
        callBack(evt.target.result);
    };
    reader.readAsText(filePath);
}

Can i have something like this in Blazor C#

    // read file content and output result to console
    void GetFileContent() {
        JsRuntime.InvokeAsync<object>("readFile", "file.txt", (string text) => {
            Console.Write(text);
        });
    }

Or Maybe something like this

    // read with javascript
    void ReadFileContent() {
        JsRuntime.InvokeAsync<object>("readFile", "file.txt", "resultCallbackMethod");
    }

    // output result callback to console
    void resultCallbackMethod(string text) {
        Console.Write(text);
    }

Thanks

like image 606
samtax01 Avatar asked Jun 17 '19 08:06

samtax01


People also ask

How do you call a JavaScript file in Blazor?

To call a Blazor method, you use the invokeMethodAsync function of the JavaScript DotNet object. You must pass that method the name of the assembly holding your C# code and the name of the "JavaScript-invokable" static method that you want to call (more on "JavaScript-invokable" later).

Can you use JavaScript in Blazor?

A Blazor app can invoke JavaScript (JS) functions from . NET methods and . NET methods from JS functions. These scenarios are called JavaScript interoperability (JS interop).

How JavaScript callbacks are implemented?

A custom callback function can be created by using the callback keyword as the last parameter. It can then be invoked by calling the callback() function at the end of the function. The typeof operator is optionally used to check if the argument passed is actually a function. console.


1 Answers

UPDATE 1:

After re-reading your question, I think this would cover your 2nd example

I think you have the option of implementing a JS proxy function that handle the calling. Something like this:

UPDATE 2:

Code was updated with a functional (but not deeply tested) version, you can also find a working example in blazorfiddle.com

JAVASCRIPT CODE

// Target Javascript function
window.readFile = function (filePath, callBack) {

    var fileInput = document.getElementById('fileInput');
    var file = fileInput.files[0];

    var reader = new FileReader();

    reader.onload = function (evt) {
        callBack(evt.target.result);
    };

    reader.readAsText(file);

}

// Proxy function
// blazorInstance: A reference to the actual C# class instance, required to invoke C# methods inside it
// blazorCallbackName: parameter that will get the name of the C# method used as callback
window.readFileProxy = (instance, callbackMethod, fileName) => {

    // Execute function that will do the actual job
    window.readFile(fileName, result => {
        // Invoke the C# callback method passing the result as parameter
        instance.invokeMethodAsync(callbackMethod, result);
    });

}

C# CODE

@page "/"

@inject IJSRuntime jsRuntime

<div>
    Select a text file:
    <input type="file" id="fileInput" @onchange="@ReadFileContent" />
</div>
<pre>
    @fileContent
</pre>

Welcome to your new app.

@code{

    private string fileContent { get; set; }

    public static object CreateDotNetObjectRefSyncObj = new object();

    public async Task ReadFileContent(UIChangeEventArgs ea)
    {
        // Fire & Forget: ConfigureAwait(false) is telling "I'm not expecting this call to return a thing"
        await jsRuntime.InvokeAsync<object>("readFileProxy", CreateDotNetObjectRef(this), "ReadFileCallback", ea.Value.ToString()).ConfigureAwait(false);
    }


    [JSInvokable] // This is required in order to JS be able to execute it
    public void ReadFileCallback(string response)
    {
        fileContent = response?.ToString();
        StateHasChanged();
    }

    // Hack to fix https://github.com/aspnet/AspNetCore/issues/11159    
    protected DotNetObjectRef<T> CreateDotNetObjectRef<T>(T value) where T : class
    {
        lock (CreateDotNetObjectRefSyncObj)
        {
            JSRuntime.SetCurrentJSRuntime(jsRuntime);
            return DotNetObjectRef.Create(value);
        }
    }

}
like image 144
Henry Rodriguez Avatar answered Sep 23 '22 16:09

Henry Rodriguez