Skip to content

Commit 453b2e9

Browse files
authored
Blazor FocusAsync coverage (#20236)
1 parent 6fafc7c commit 453b2e9

4 files changed

Lines changed: 66 additions & 26 deletions

File tree

aspnetcore/blazor/call-javascript-from-dotnet.md

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to invoke JavaScript functions from .NET methods in Blazo
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 10/02/2020
8+
ms.date: 10/20/2020
99
no-loc: ["ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR]
1010
uid: blazor/call-javascript-from-dotnet
1111
---
@@ -192,40 +192,46 @@ The following example shows capturing a reference to the `username` `<input>` el
192192
>
193193
> If JS interop mutates the contents of element `MyList` and Blazor attempts to apply diffs to the element, the diffs won't match the DOM.
194194
195-
As far as .NET code is concerned, an <xref:Microsoft.AspNetCore.Components.ElementReference> is an opaque handle. The *only* thing you can do with <xref:Microsoft.AspNetCore.Components.ElementReference> is pass it through to JavaScript code via JS interop. When you do so, the JavaScript-side code receives an `HTMLElement` instance, which it can use with normal DOM APIs.
196-
197-
For example, the following code defines a .NET extension method that enables setting the focus on an element:
195+
An <xref:Microsoft.AspNetCore.Components.ElementReference> is passed through to JavaScript code via JS interop. The JavaScript code receives an `HTMLElement` instance, which it can use with normal DOM APIs. For example, the following code defines a .NET extension method that enables sending a mouse click to an element:
198196
199197
`exampleJsInterop.js`:
200198
201199
```javascript
202-
window.exampleJsFunctions = {
203-
focusElement : function (element) {
204-
element.focus();
200+
window.interopFunctions = {
201+
clickElement : function (element) {
202+
element.click();
205203
}
206204
}
207205
```
208206
209-
To call a JavaScript function that doesn't return a value, use <xref:Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync%2A?displayProperty=nameWithType>. The following code sets the focus on the username input by calling the preceding JavaScript function with the captured <xref:Microsoft.AspNetCore.Components.ElementReference>:
207+
::: moniker range=">= aspnetcore-5.0"
208+
209+
> [!NOTE]
210+
> Use [`FocusAsync`](xref:blazor/components/event-handling#focus-an-element) in C# code to focus an element, which is built-into the Blazor framework and works with element references.
211+
212+
::: moniker-end
213+
214+
To call a JavaScript function that doesn't return a value, use <xref:Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync%2A?displayProperty=nameWithType>. The following code triggers a client-side `Click` event by calling the preceding JavaScript function with the captured <xref:Microsoft.AspNetCore.Components.ElementReference>:
210215

211-
[!code-razor[](call-javascript-from-dotnet/samples_snapshot/component1.razor?highlight=1,3,11-12)]
216+
[!code-razor[](call-javascript-from-dotnet/samples_snapshot/component1.razor?highlight=14-15)]
212217

213218
To use an extension method, create a static extension method that receives the <xref:Microsoft.JSInterop.IJSRuntime> instance:
214219

215220
```csharp
216-
public static async Task Focus(this ElementReference elementRef, IJSRuntime jsRuntime)
221+
public static async Task TriggerClickEvent(this ElementReference elementRef,
222+
IJSRuntime jsRuntime)
217223
{
218224
await jsRuntime.InvokeVoidAsync(
219-
"exampleJsFunctions.focusElement", elementRef);
225+
"interopFunctions.clickElement", elementRef);
220226
}
221227
```
222228

223-
The `Focus` method is called directly on the object. The following example assumes that the `Focus` method is available from the `JsInteropClasses` namespace:
229+
The `clickElement` method is called directly on the object. The following example assumes that the `TriggerClickEvent` method is available from the `JsInteropClasses` namespace:
224230

225-
[!code-razor[](call-javascript-from-dotnet/samples_snapshot/component2.razor?highlight=1-4,12)]
231+
[!code-razor[](call-javascript-from-dotnet/samples_snapshot/component2.razor?highlight=15)]
226232

227233
> [!IMPORTANT]
228-
> The `username` variable is only populated after the component is rendered. If an unpopulated <xref:Microsoft.AspNetCore.Components.ElementReference> is passed to JavaScript code, the JavaScript code receives a value of `null`. To manipulate element references after the component has finished rendering (to set the initial focus on an element) use the [`OnAfterRenderAsync` or `OnAfterRender` component lifecycle methods](xref:blazor/components/lifecycle#after-component-render).
234+
> The `exampleButton` variable is only populated after the component is rendered. If an unpopulated <xref:Microsoft.AspNetCore.Components.ElementReference> is passed to JavaScript code, the JavaScript code receives a value of `null`. To manipulate element references after the component has finished rendering use the [`OnAfterRenderAsync` or `OnAfterRender` component lifecycle methods](xref:blazor/components/lifecycle#after-component-render).
229235
230236
When working with generic types and returning a value, use <xref:System.Threading.Tasks.ValueTask%601>:
231237

@@ -244,7 +250,12 @@ public static ValueTask<T> GenericMethod<T>(this ElementReference elementRef,
244250

245251
## Reference elements across components
246252

247-
An <xref:Microsoft.AspNetCore.Components.ElementReference> instance is only guaranteed valid in a component's <xref:Microsoft.AspNetCore.Components.ComponentBase.OnAfterRender%2A> method (and an element reference is a `struct`), so an element reference can't be passed between components. For a parent component to make an element reference available to other components, the parent component can:
253+
An <xref:Microsoft.AspNetCore.Components.ElementReference> can't be passed between components because:
254+
255+
* The instance is only guaranteed to exist after the component is rendered, which is during or after a component's <xref:Microsoft.AspNetCore.Components.ComponentBase.OnAfterRender%2A>/<xref:Microsoft.AspNetCore.Components.ComponentBase.OnAfterRenderAsync%2A> method executes.
256+
* An <xref:Microsoft.AspNetCore.Components.ElementReference> is a [`struct`](/csharp/language-reference/builtin-types/struct), which can't be passed as a [component parameter](xref:blazor/components/index#component-parameters).
257+
258+
For a parent component to make an element reference available to other components, the parent component can:
248259

249260
* Allow child components to register callbacks.
250261
* Invoke the registered callbacks during the <xref:Microsoft.AspNetCore.Components.ComponentBase.OnAfterRender%2A> event with the passed element reference. Indirectly, this approach allows child components to interact with the parent's element reference.
Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
@inject IJSRuntime JSRuntime
22

3-
<input @ref="username" />
4-
<button @onclick="SetFocus">Set focus on username</button>
3+
<button @ref="exampleButton">Example Button</button>
4+
5+
<button @onclick="TriggerClick">
6+
Trigger button click on exampleButton
7+
</button>
58

69
@code {
7-
private ElementReference username;
10+
private ElementReference exampleButton;
811

9-
public async Task SetFocus()
12+
public async Task TriggerClick()
1013
{
1114
await JSRuntime.InvokeVoidAsync(
12-
"exampleJsFunctions.focusElement", username);
15+
"interopFunctions.clickElement", exampleButton);
1316
}
1417
}
Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
@inject IJSRuntime JSRuntime
22
@using JsInteropClasses
33

4-
<input @ref="username" />
5-
<button @onclick="SetFocus">Set focus on username</button>
4+
<button @ref="exampleButton" />
5+
6+
<button @onclick="TriggerClick">
7+
Trigger button click on exampleButton
8+
</button>
69

710
@code {
8-
private ElementReference username;
11+
private ElementReference exampleButton;
912

10-
public async Task SetFocus()
13+
public async Task TriggerClick()
1114
{
12-
await username.Focus(JSRuntime);
15+
await exampleButton.TriggerClickEvent(JSRuntime);
1316
}
1417
}

aspnetcore/blazor/components/event-handling.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn about Blazor's event handling features, including event argum
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 09/17/2020
8+
ms.date: 10/20/2020
99
no-loc: ["ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR]
1010
uid: blazor/components/event-handling
1111
---
@@ -273,3 +273,26 @@ In the following example, selecting the check box prevents click events from the
273273
Console.WriteLine($"A child div was selected. {DateTime.Now}");
274274
}
275275
```
276+
277+
::: moniker range=">= aspnetcore-5.0"
278+
279+
## Focus an element
280+
281+
Call `FocusAsync` on an [element reference](xref:blazor/call-javascript-from-dotnet#capture-references-to-elements) to focus an element in code:
282+
283+
```razor
284+
<input @ref="exampleInput" />
285+
286+
<button @onclick="ChangeFocus">Focus the Input Element</button>
287+
288+
@code {
289+
private ElementReference exampleInput;
290+
291+
private async Task ChangeFocus()
292+
{
293+
await exampleInput.FocusAsync();
294+
}
295+
}
296+
```
297+
298+
::: moniker-end

0 commit comments

Comments
 (0)