Blazor EditForm loses focus on data binding

2k Views Asked by At

I have a requirement to load new data into my form when a user clicks the up or down arrow. And the expectation is whatever cell has the focus, retains the focus after new data is loaded.

The following code can trap the keyboard input, and load the correct record into my form using data binding. However I find, the form loses focus as soon as new data gets bound.

MyComponent.razor:

<span @onkeypress="@KeyHandler" @onkeydown="@KeyHandler">
    <EditForm Model="@CurrentRecord">
        <DataAnnotationsValidator />
        <ValidationSummary />
        @Content
    </EditForm>
</span>

@code {
[Parameter]
public RenderFragment Content { get; set; }
public List<MyModel> Data { get; set; } = new List<MyModel>();
private int currentIndex;

protected async Task KeyHandler(KeyboardEventArgs e)
{
    if (e.Key == "DownArrow") await LoadNextRecord();
}

async Task LoadNextRecord()
{
    CurrentRecord = Data.ElementAt(++currentIndex);
    // Form loses focus here!!
}
}

Now I can implement a simple javascript to focus the first element when the data is re-binded. But my requirement is to keep the focus where it is. I could not find a generic way to get the focused element and then re-focus without having to assign an Id or an @ref for every element in my form.

Is there another way to solve this problem?

1

There are 1 best solutions below

1
On BEST ANSWER

Is there another way to solve this problem?

No, there isn't... There is no generic way to do that, not right now, and probably not in the near future.

Currently, at most you can set the focus of an input in Blazor, as follows:

<button @onclick="() => textInput.FocusAsync()">Set focus</button>
<input @ref="textInput"/>

Note that the code snippet above works in Asp.Net Core 5.0 (preview) only.

The only solution I can propose is to devise a way to discover what input element had the focus last, and then re-focus it from the OnAfterRender/Async methods. You'll have to apply the @ref directive to each of your input elements or the id attribute. There is no other way to do that.