Skip to content

Commit fc4c09e

Browse files
authored
Enable getting IJSObjectReference to a JS function in Blazor interop (#61453)
1 parent 3fc864b commit fc4c09e

File tree

4 files changed

+42
-3
lines changed

4 files changed

+42
-3
lines changed

src/Components/test/E2ETest/Tests/InteropTest.cs

+4
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ public void CanInvokeInteropMethods()
107107
["invokeNewWithClassConstructorAsync.dataProperty"] = "abraka",
108108
["invokeNewWithClassConstructorAsync.function"] = "6",
109109
["invokeNewWithNonConstructorAsync"] = "Success",
110+
// Function reference tests
111+
["changeFunctionViaObjectReferenceAsync"] = "42"
110112
};
111113

112114
var expectedSyncValues = new Dictionary<string, string>
@@ -171,6 +173,8 @@ public void CanInvokeInteropMethods()
171173
["invokeNewWithClassConstructor.dataProperty"] = "abraka",
172174
["invokeNewWithClassConstructor.function"] = "6",
173175
["invokeNewWithNonConstructor"] = "Success",
176+
// Function reference tests
177+
["changeFunctionViaObjectReference"] = "42"
174178
};
175179

176180
// Include the sync assertions only when running under WebAssembly

src/Components/test/testassets/BasicTestApp/DotNetToJSInterop.razor

+12-2
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
<div style="margin-top: 2em">
9393
<button @onclick="CreateInstanceByConstructorFunction">Call constructor function InvokeNewAsync</button>
9494
<button @onclick="CreateInstanceByClassConstructor">Call class constructor with InvokeNewAsync</button>
95+
<button @onclick="ChangeInstanceMethodWithFunctionReference">Change instance method with function reference</button>
9596
<span>@InstanceMessage</span>
9697
</div>
9798

@@ -146,13 +147,13 @@
146147

147148
private async Task CreateInstanceByConstructorFunction()
148149
{
149-
var dogRef = await JSRuntime.InvokeNewAsync("Dog", ["Igor"]);
150+
var dogRef = await JSRuntime.InvokeNewAsync("Dog", "A dog");
150151
InstanceMessage = await dogRef.InvokeAsync<string>("bark");
151152
}
152153

153154
private async Task CreateInstanceByClassConstructor()
154155
{
155-
var catRef = await JSRuntime.InvokeNewAsync("Cat", ["Whiskers"]);
156+
var catRef = await JSRuntime.InvokeNewAsync("Cat", "A cat");
156157
InstanceMessage = await catRef.InvokeAsync<string>("meow");
157158
}
158159

@@ -166,6 +167,15 @@
166167
await JSRuntime.SetValueAsync<int>("testObject.getOnlyProperty", 123);
167168
}
168169

170+
private async Task ChangeInstanceMethodWithFunctionReference()
171+
{
172+
var dogRef = await JSRuntime.InvokeNewAsync("Dog", "A dog");
173+
var dogFuncRef = await dogRef.GetValueAsync<IJSObjectReference>("bark");
174+
var catRef = await JSRuntime.InvokeNewAsync("Cat", "A cat");
175+
await catRef.SetValueAsync("meow", dogFuncRef);
176+
InstanceMessage = await catRef.InvokeAsync<string>("meow");
177+
}
178+
169179
class TestObjectModel
170180
{
171181
public int Num { get; set; }

src/Components/test/testassets/BasicTestApp/InteropComponent.razor

+25
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,13 @@
301301
InvokeNewTests();
302302
}
303303

304+
await FunctionReferenceAsyncTests();
305+
306+
if (shouldSupportSyncInterop)
307+
{
308+
FunctionReferenceTests();
309+
}
310+
304311
Invocations = invocations;
305312
DoneWithInterop = true;
306313
}
@@ -601,6 +608,24 @@
601608
}
602609
}
603610

611+
private async Task FunctionReferenceAsyncTests()
612+
{
613+
var funcRef = await JSRuntime.GetValueAsync<IJSObjectReference>("jsInteropTests.nonConstructorFunction");
614+
var testClassRef = await JSRuntime.InvokeNewAsync("jsInteropTests.TestClass", "abraka");
615+
await testClassRef.SetValueAsync("getTextLength", funcRef);
616+
ReturnValues["changeFunctionViaObjectReferenceAsync"] = (await testClassRef.InvokeAsync<int>("getTextLength")).ToString();
617+
}
618+
619+
private void FunctionReferenceTests()
620+
{
621+
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime);
622+
623+
var funcRef = inProcRuntime.GetValue<IJSObjectReference>("jsInteropTests.nonConstructorFunction");
624+
var testClassRef = inProcRuntime.InvokeNew("jsInteropTests.TestClass", "abraka");
625+
testClassRef.SetValue("getTextLength", funcRef);
626+
ReturnValues["changeFunctionViaObjectReference"] = testClassRef.Invoke<int>("getTextLength").ToString();
627+
}
628+
604629
public class PassDotNetObjectByRefArgs
605630
{
606631
public string StringValue { get; set; }

src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export module DotNet {
155155
* @throws Error if the given value is not an Object.
156156
*/
157157
export function createJSObjectReference(jsObject: any): any {
158-
if (jsObject && typeof jsObject === "object") {
158+
if (jsObject && (typeof jsObject === "object" || jsObject instanceof Function)) {
159159
cachedJSObjectsById[nextJsObjectId] = new JSObject(jsObject);
160160

161161
const result = {

0 commit comments

Comments
 (0)