2

EditForm element rerenders it's child content when model changes. As a side effect, the active (focused) input element is removed from DOM and focus is lost.

<EditForm Model="model">
    <!-- Focus will not be retained when model changes  -->
    <InputText @bind-Value="model.Name" /> 
    ...dozen of other inputs
</EditForm>

See demonstration: https://blazorrepl.com/repl/mbbEcJaB56u8TmG400

When the EditForm is rerendred I would like to retain focus on the same input - whatever input had the focus.

How can I retain focus on the same input when EditForm is rerendered?

I would ideally have a generic solution since I there are many forms with many various inputs in my projects


EDIT: I know how to set focus to an element programmatically, either by using ElementRef.Focus() or JS.

This question is about keeping focus in whatever input was focused by user.

Liero
  • 25,216
  • 29
  • 151
  • 297
  • Blazor has a `FocusAsync` method for elements (use `@ref`). You can also use JavaScript Interop to call for focus on an element whenever you want. – Bennyboy1973 Oct 25 '21 at 08:54
  • https://stackoverflow.com/questions/60309188/how-do-i-set-focus-to-a-text-box-in-blazor – Steve Greene Oct 25 '21 at 12:53

2 Answers2

2

Until somebody comes with better solution, following works for me:

//restore focus after EditForm.Model changes, since the elements are removed from DOM 

//when active element is removed from DOM, `focusout` event bubbles up to document
document.addEventListener('focusout', (evt) => {
    if (evt.target.form && evt.target.form.parentElement) {

        //parent of the EditForm will stay connected to DOM.
        const parent = evt.target.form.parentElement; //get editform's

        let elementSelector = evt.target.tagName;
        if (evt.target.name) {
            elementSelector += `[name='${evt.target.name}']`;
        }
        //we will need this to find new version of element after DOM updates
        const elementPosition = [...parent.querySelectorAll(elementSelector)].indexOf(evt.target);

        setTimeout(() => {  //wait for rerender
            // check whether the original active element was removed from DOM
            if (document.activeElement == document.body && !evt.target.isConnected) {
                const rerenderedElement = parent.querySelectorAll(elementSelector)[elementPosition];

                if (rerenderedElement) {
                    rerenderedElement.focus();
                }

            }
        }, 1);
    }
});
Liero
  • 25,216
  • 29
  • 151
  • 297
1

You answered your own question before you even asked it.

the active (focused) input element is removed from DOM and focus is lost.

How can I retain focus on the same input when EditForm is rerendered?

Do you see? You cannot. The best you can do is set focus on the new element.

The general approach would be to keep track of the most recently focussed input and restore focus to the new version of that input as needed, using the tools provided in comments above.

Mister Magoo
  • 7,452
  • 1
  • 20
  • 35
  • Thanks. You described exactly what I want to achieve - focus a new DOM element representing logically the same input. You just haven't shown how. It's a non trivial task. – Liero Oct 29 '21 at 13:35