Skip to content

Commit 7a8a2ed

Browse files
committed
[Pre4] New JavaScript interop features
1 parent 5694813 commit 7a8a2ed

File tree

3 files changed

+221
-2
lines changed

3 files changed

+221
-2
lines changed

Diff for: aspnetcore/blazor/javascript-interoperability/call-javascript-from-dotnet.md

+132-2
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,113 @@ IJSRuntime JS { get; set; }
453453

454454
[!INCLUDE[](~/blazor/includes/js-interop/synchronous-js-interop-call-js.md)]
455455

456+
:::moniker range=">= aspnetcore-10.0"
457+
458+
<!-- UPDATE 10.0 - API Browser cross-links in the next
459+
two H2 sections. -->
460+
461+
## Create an instance of a JS object using a constructor function
462+
463+
Create an instance of a JS object using a constructor function and get the <xref:Microsoft.JSInterop.IJSObjectReference>/<xref:Microsoft.JSInterop.IJSInProcessObjectReference> .NET handle for referencing the instance with the following API.
464+
465+
.NET API call examples for `InvokeNewAsync`/`InvokeNew` in this section use the following JS constructor function example (`TestClass`):
466+
467+
```javascript
468+
class TestClass {
469+
constructor(text) {
470+
this.text = text;
471+
}
472+
473+
getTextLength() {
474+
return this.text.length;
475+
}
476+
}
477+
478+
window.jsInteropTests = {
479+
TestClass: TestClass
480+
};
481+
```
482+
483+
### Asynchronous `InvokeNewAsync`
484+
485+
Use `InvokeNewAsync(string identifier, object?[]? args)` on <xref:Microsoft.JSInterop.IJSRuntime> and <xref:Microsoft.JSInterop.IJSObjectReference> to invoke the specified JS constructor function asynchronously. The function is invoked with the `new` operator. In the following example, `jsInteropTests.TestClass` is a constructor function, and `classRef` is an <xref:Microsoft.JSInterop.IJSObjectReference>.
486+
487+
```csharp
488+
var classRef = await JSRuntime.InvokeNewAsync("jsInteropTests.TestClass",
489+
"text value");
490+
var text = await classRef.GetValueAsync<string>("text");
491+
var textLength = await classRef.InvokeAsync<int>("getTextLength");
492+
```
493+
494+
An overload is available that takes a <xref:System.Threading.CancellationToken> argument or <xref:System.TimeSpan> timeout argument.
495+
496+
### Synchronous `InvokeNew`
497+
498+
Use `InvokeNew(string identifier, object?[]? args)` on <xref:Microsoft.JSInterop.IJSInProcessRuntime> and <xref:Microsoft.JSInterop.IJSInProcessObjectReference> to invoke the specified JS constructor function synchronously. The function is invoked with the `new` operator. In the following example, `jsInteropTests.TestClass` is a constructor function, and `classRef` is an <xref:Microsoft.JSInterop.IJSInProcessObjectReference>.
499+
500+
```csharp
501+
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime);
502+
var classRef = inProcRuntime.InvokeNew("jsInteropTests.TestClass", "text value");
503+
var text = await classRef.GetValueAsync<string>("text");
504+
var textLength = await classRef.InvokeAsync<int>("getTextLength");
505+
```
506+
507+
An overload is available that takes a <xref:System.Threading.CancellationToken> argument or <xref:System.TimeSpan> timeout argument.
508+
509+
## Read or modify the value of a JS object property
510+
511+
Read or modify the value of a JS object property, both data and accessor properties, with
512+
513+
.NET API call examples for `GetValueAsync`/`SetValueAsync`/`GetValue`/`SetValue` in this section use the following JS object example (`testObject`):
514+
515+
```javascript
516+
const testObject = {
517+
num: 10
518+
}
519+
520+
window.jsInteropTests = {
521+
testObject: testObject
522+
};
523+
```
524+
525+
### Asynchronous `GetValueAsync` and `SetValueAsync`
526+
527+
Use `GetValueAsync<TValue>(string identifier)` to read the value of the specified JS property asynchronously. The property can't be a `set`-only property. A <xref:Microsoft.JSInterop.JSException> is thrown if the property doesn't exist. The following example returns a value of 10 from the property:
528+
529+
```csharp
530+
var valueFromDataPropertyAsync = await JSRuntime.GetValueAsync<int>(
531+
"jsInteropTests.testObject.num");
532+
```
533+
534+
The special overload `IJSObjectReference.GetValueAsync<TValue>()` doesn't take an identifier and simply returns the value of the object. `TValue` is a model of the object's properties that the caller is interested in.
535+
536+
Use `SetValueAsync<TValue>(string identifier, TValue value)`to update the value of the specified JS property asynchronously. The property can't be a `get`-only property. If the property isn't defined on the target object, the property is created. In the following example, `testObject.num` is set to 20, and `num2` is created with a value of 30 on `testObject`:
537+
538+
```csharp
539+
await JSRuntime.SetValueAsync("jsInteropTests.testObject.num", 20);
540+
await JSRuntime.SetValueAsync("jsInteropTests.testObject.num2", 30);
541+
```
542+
543+
### Synchronous `GetValue` and `SetValue`
544+
545+
Use `GetValue<TValue>(string identifier)` to read the value of the specified JS property synchronously. The property can't be a `set`-only property. A <xref:Microsoft.JSInterop.JSException> is thrown if the property doesn't exist. The following example returns a value of 10 from the property:
546+
547+
```csharp
548+
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime);
549+
var valueFromDataProperty = inProcRuntime.GetValue<int>(
550+
"jsInteropTests.testObject.num");
551+
```
552+
553+
Use `SetValue<TValue>(string identifier, TValue value)` to update the value of the specified JS property synchronously. The property can't be a `get`-only property. If the property isn't defined on the target object, the property is created. In the following example, `testObject.num` is set to 20, and `num2` is created with a value of 30 on `testObject`:
554+
555+
```csharp
556+
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime);
557+
inProcRuntime.SetValue("jsInteropTests.testObject.num", 20);
558+
inProcRuntime.SetValue("jsInteropTests.testObject.num2", 30);
559+
```
560+
561+
:::moniker-end
562+
456563
## JavaScript location
457564

458565
Load JavaScript (JS) code using any of approaches described by the [article on JavaScript location](xref:blazor/js-interop/javascript-location):
@@ -519,12 +626,35 @@ For browser compatibility, see [Can I use: JavaScript modules: dynamic import](h
519626

520627
In server-side scenarios, JS interop calls can't be issued after Blazor's SignalR circuit is disconnected. Without a circuit during component disposal or at any other time that a circuit doesn't exist, the following method calls fail and log a message that the circuit is disconnected as a <xref:Microsoft.JSInterop.JSDisconnectedException>:
521628

629+
:::moniker-end
630+
631+
:::moniker range=">= aspnetcore-10.0"
632+
633+
<!-- UPDATE 10.0 - API Browser cross-links -->
634+
522635
* JS interop method calls
523636
* <xref:Microsoft.JSInterop.IJSRuntime.InvokeAsync%2A?displayProperty=nameWithType>
524637
* <xref:Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync%2A?displayProperty=nameWithType>
525-
* <xref:Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync%2A?displayProperty=nameWithType>)
638+
* <xref:Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync%2A?displayProperty=nameWithType>
639+
* `InvokeNewAsync`
640+
* `GetValueAsync`
641+
* `SetValueAsync`
526642
* `Dispose`/`DisposeAsync` calls on any <xref:Microsoft.JSInterop.IJSObjectReference>.
527643

644+
:::moniker-end
645+
646+
:::moniker range=">= aspnetcore-5.0 < aspnetcore-10.0"
647+
648+
* JS interop method calls
649+
* <xref:Microsoft.JSInterop.IJSRuntime.InvokeAsync%2A?displayProperty=nameWithType>
650+
* <xref:Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync%2A?displayProperty=nameWithType>
651+
* <xref:Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync%2A?displayProperty=nameWithType>
652+
* `Dispose`/`DisposeAsync` calls on any <xref:Microsoft.JSInterop.IJSObjectReference>.
653+
654+
:::moniker-end
655+
656+
:::moniker range=">= aspnetcore-5.0"
657+
528658
In order to avoid logging <xref:Microsoft.JSInterop.JSDisconnectedException> or to log custom information in server-side Blazor, catch the exception in a [`try-catch`](/dotnet/csharp/language-reference/keywords/try-catch) statement.
529659

530660
For the following component disposal example:
@@ -627,7 +757,7 @@ In the preceding example:
627757

628758
Dynamically importing a module requires a network request, so it can only be achieved asynchronously by calling <xref:Microsoft.JSInterop.IJSRuntime.InvokeAsync%2A>.
629759

630-
`IJSInProcessObjectReference` represents a reference to a JS object whose functions can be invoked synchronously in client-side components. For more information, see the [Synchronous JS interop in client-side components](#synchronous-js-interop-in-client-side-components) section.
760+
<xref:Microsoft.JSInterop.IJSInProcessObjectReference> represents a reference to a JS object whose functions can be invoked synchronously in client-side components. For more information, see the [Synchronous JS interop in client-side components](#synchronous-js-interop-in-client-side-components) section.
631761

632762
> [!NOTE]
633763
> When the external JS file is supplied by a [Razor class library](xref:blazor/components/class-libraries), specify the module's JS file using its stable static web asset path: `./_content/{PACKAGE ID}/{SCRIPT PATH AND FILE NAME (.js)}`:

Diff for: aspnetcore/blazor/javascript-interoperability/index.md

+19
Original file line numberDiff line numberDiff line change
@@ -328,12 +328,31 @@ Don't assume that observing `document.body`, instead of `target.parentNode`, is
328328

329329
JavaScript (JS) interop calls can't be issued after Blazor's SignalR circuit is disconnected. Without a circuit during component disposal or at any other time that a circuit doesn't exist, the following method calls fail and log a message that the circuit is disconnected as a <xref:Microsoft.JSInterop.JSDisconnectedException>:
330330

331+
:::moniker range=">= aspnetcore-10.0"
332+
333+
<!-- UPDATE 10.0 - API Browser cross-links -->
334+
331335
* JS interop method calls
332336
* <xref:Microsoft.JSInterop.IJSRuntime.InvokeAsync%2A?displayProperty=nameWithType>
333337
* <xref:Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync%2A?displayProperty=nameWithType>
334338
* <xref:Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync%2A?displayProperty=nameWithType>
339+
* `InvokeNewAsync`
340+
* `GetValueAsync`
341+
* `SetValueAsync`
335342
* `Dispose`/`DisposeAsync` calls on any <xref:Microsoft.JSInterop.IJSObjectReference>.
336343

344+
:::moniker-end
345+
346+
:::moniker range="< aspnetcore-10.0"
347+
348+
* JS interop method calls
349+
* <xref:Microsoft.JSInterop.IJSRuntime.InvokeAsync%2A?displayProperty=nameWithType>
350+
* <xref:Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync%2A?displayProperty=nameWithType>
351+
* <xref:Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync%2A?displayProperty=nameWithType>
352+
* `Dispose`/`DisposeAsync` calls on any <xref:Microsoft.JSInterop.IJSObjectReference>.
353+
354+
:::moniker-end
355+
337356
In order to avoid logging <xref:Microsoft.JSInterop.JSDisconnectedException> or to log custom information, catch the exception in a [`try-catch`](/dotnet/csharp/language-reference/keywords/try-catch) statement.
338357

339358
For the following component disposal example:

Diff for: aspnetcore/release-notes/aspnetcore-10/includes/blazor.md

+70
Original file line numberDiff line numberDiff line change
@@ -280,3 +280,73 @@ else
280280
```
281281

282282
For more information, see <xref:blazor/components/prerender?view=aspnetcore-10.0#persist-prerendered-state>. Additional API implementation notes, which are subject to change at any time, are available in [[Blazor] Support for declaratively persisting component and services state (`dotnet/aspnetcore` #60634)](https://github.com/dotnet/aspnetcore/pull/60634).
283+
284+
<!-- PREVIEW 4
285+
286+
### New JavaScript interop features
287+
288+
Blazor adds support for the following JS interop features:
289+
290+
* Create an instance of a JS object using a constructor function and get the <xref:Microsoft.JSInterop.IJSObjectReference>/<xref:Microsoft.JSInterop.IJSInProcessObjectReference> .NET handle for referencing the instance.
291+
* Read or modify the value of a JS object property, both data and accessor properties.
292+
293+
The following asynchronous methods are available on <xref:Microsoft.JSInterop.IJSRuntime> and <xref:Microsoft.JSInterop.IJSObjectReference> with the same scoping behavior as the existing <xref:Microsoft.JSInterop.IJSRuntime.InvokeAsync%2A?displayProperty=nameWithType> method:
294+
295+
* `InvokeNewAsync(string identifier, object?[]? args)`: Invokes the specified JS constructor function asynchronously. The function is invoked with the `new` operator. In the following example, `jsInteropTests.TestClass` is a constructor function, and `classRef` is an <xref:Microsoft.JSInterop.IJSObjectReference>:
296+
297+
```csharp
298+
var classRef = await JSRuntime.InvokeNewAsync("jsInteropTests.TestClass",
299+
"text value");
300+
var text = await classRef.GetValueAsync<string>("text");
301+
var textLength = await classRef.InvokeAsync<int>("getTextLength");
302+
```
303+
304+
* `GetValueAsync<TValue>(string identifier)`: Reads the value of the specified JS property asynchronously. The property can't be a `set`-only property. A <xref:Microsoft.JSInterop.JSException> is thrown if the property doesn't exist. The following example returns a value from a data property:
305+
306+
```csharp
307+
var valueFromDataPropertyAsync = await JSRuntime.GetValueAsync<int>(
308+
"jsInteropTests.testObject.num");
309+
```
310+
311+
* `SetValueAsync<TValue>(string identifier, TValue value)`: Updates the value of the specified JS property asynchronously. The property can't be a `get`-only property. If the property isn't defined on the target object, the property is created. In the following example, `num` is created on `testObject` with a value of 30 if it doesn't exist:
312+
313+
```csharp
314+
await JSRuntime.SetValueAsync("jsInteropTests.testObject.num", 30);
315+
```
316+
317+
Overloads are available for each of the preceding methods that take a <xref:System.Threading.CancellationToken> argument or <xref:System.TimeSpan> timeout argument.
318+
319+
The special overload `IJSObjectReference.GetValueAsync<TValue>()` doesn't take an identifier and simply returns the value of the object (`TValue` is a model of the object's properties that the caller is interested in).
320+
321+
The following synchronous methods are available on <xref:Microsoft.JSInterop.IJSInProcessRuntime> and <xref:Microsoft.JSInterop.IJSInProcessObjectReference> with the same scoping behavior as the existing <xref:Microsoft.JSInterop.IJSInProcessObjectReference.Invoke%2A?displayProperty=nameWithType> method:
322+
323+
* `InvokeNew(string identifier, object?[]? args)`: Invokes the specified JS constructor function synchronously. The function is invoked with the `new` operator. In the following example, `jsInteropTests.TestClass` is a constructor function, and `classRef` is an <xref:Microsoft.JSInterop.IJSInProcessObjectReference>:
324+
325+
```csharp
326+
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime);
327+
var classRef = inProcRuntime.InvokeNew("jsInteropTests.TestClass", "text value");
328+
var text = await classRef.GetValueAsync<string>("text");
329+
var textLength = await classRef.InvokeAsync<int>("getTextLength");
330+
```
331+
332+
* `GetValue<TValue>(string identifier)`: Reads the value of the specified JS property synchronously. The property can't be a `set`-only property. A <xref:Microsoft.JSInterop.JSException> is thrown if the property doesn't exist. The following example returns a value from a data property:
333+
334+
```csharp
335+
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime);
336+
var valueFromDataProperty = inProcRuntime.GetValue<int>(
337+
"jsInteropTests.testObject.num");
338+
```
339+
340+
* `SetValue<TValue>(string identifier, TValue value)`: Updates the value of the specified JS property synchronously. The property can't be a `get`-only property. If the property isn't defined on the target object, the property is created. In the following example, `num` is created on `testObject` with a value of 20 if it doesn't exist:
341+
342+
```csharp
343+
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime);
344+
inProcRuntime.SetValue("jsInteropTests.testObject.num", 20);
345+
```
346+
347+
For more information, see the following sections of the *Call JavaScript functions from .NET methods* article:
348+
349+
* [Create an instance of a JS object using a constructor function](xref:blazor/js-interop/call-javascript-from-dotnet#create-an-instance-of-a-js-object-using-a-constructor-function)
350+
* [Read or modify the value of a JS object property](xref:blazor/js-interop/call-javascript-from-dotnet#read-or-modify-the-value-of-a-js-object-property)
351+
352+
-->

0 commit comments

Comments
 (0)