I'm trying to invoke a Blazor method in JavaScript inside of an OnSuccess callback for the Plaid API.
Here's the JavaScript that's being run:
async function InitializePlaidLink(objRef, linkToken) {
//console.log("linkToken:" linkToken);
const handler = Plaid.create({
token: linkToken,
onSuccess: (public_token, metadata) => {
//console.log("public_token: ");
//console.log(public_token);
objRef.invokeMethodAsync('OnPlaidLinkSuccess', public_token);
//console.log("After Invoke Method Async")
},
onl oad: () => {},
onExit: (err, metadata) => {},
onEvent: (eventName, metadata) => {},
//required for OAuth; if not using OAuth, set to null or omit:
//receivedRedirectUri: window.location.href,
});
handler.open();
}
Here's the Blazor code being used:
private string LinkToken { get; set; } = string.Empty;
private string PublicToken { get; set; } = string.Empty;
private async Task InitializePlaid()
{
this.LinkToken = await this.apiService.GetPlaidLinkToken();
var dotNetReference = DotNetObjectReference.Create(this);
await this.jsRuntime.InvokeVoidAsync
(
"InitializePlaidLink",
dotNetReference,
this.LinkToken
);
}
[JSInvokable]
public void OnPlaidLinkSuccess(string publicToken)
{
this.PublicToken = publicToken;
}
The Blazor method InitializePlaid is being called to invoke the JS method InitializePlaidLink. Then, on success, the Blazor method OnPlaidLink Success should be called.
I used log statements to confirm that there is a public_token and the JS after the objRef.invokeMethodAsync() is being reached. Also I was able to invoke a Blazor method in a similar way with a different JS method, just not a method with the Plaid API and the onSuccess callback.
CodePudding user response:
The problem is that the OnPlaidLinkSuccess
method must be static as follows:
[JSInvokable]
public static void OnPlaidLinkSuccess(string publicToken)
{
this.PublicToken = publicToken;
}
If you have to define a non-static function, then it will be a bit more complicated. In this case, it is necessary to send a reference of the current component to the JavaScript method. What follows is a solution that you have to adapt yourself with your own codes.
For this reason, I first create this reference using the DotNetObjectReference.Create method and then send it to the JavaScript code using the jSRuntime.InvokeVoidAsync method. In the example below, JsSample is the name of the current component.
Also defined here, onclick refers to a method inside this component.
This reference should also be disposed at the end of the component's work. That's why you see @IDisposable implements.
@page "/js-sample" @implements IDisposable @inject IJSRuntime jSRuntime <button @onclick="CallInstanceMethod">Invoke Instance Method</button> @code { private DotNetObjectReference<JsSample> objectReference; [JSInvokable] public string GetAddress() { return "123 Main Street"; } protected override async Task OnAfterRenderAsync(bool firstRender) { if(firstRender) { objectReference = DotNetObjectReference.Create(this); } } private async Task CallInstanceMethod() { await jSRuntime.InvokeVoidAsync("JsFunctionHelper.invokeDotnetInstanceFunction", objectReference); } public void Dispose() { objectReference?.Dispose(); } }
Now the javascript code that uses this receiving slot will be as follows. In these codes, addressProvider is the received objectReference that can be used to call the component's non-static GetAddress method:
window.JsFunctionHelper = {
invokeDotnetInstanceFunction: function (addressProvider) {
addressProvider.invokeMethodAsync("GetAddress").then((data) => {
console.log(data);
});
}
};
CodePudding user response:
OnPlaidLinkSuccess
was being called correctly. The property this.PublicToken
was being correctly updated, but the DOM was not being updated for the user to see. Calling this.StateHasChanged()
fixed this.