0

How would you go about updating a form template (handlebars) each time the data updates and keep the input element focused? In my code sample you will find a form field to which is attached a keyup event listener that updates the data.

But on each update I am re-rendering the form which causes the input to lose focus.

JavaScript

import "./styles.css";
import $ from "jquery";
import Handlebars from 'handlebars';

const updateHtml = data => {
  const app = $('#app');
  const html = template(data);
  app.html(html);
}

const app = $('#app');
const data = {
  foo: 'default value',
}

const template = Handlebars.compile(`<form><input type="text" id="foo" value="{{foo}}"></form>`);
updateHtml(data);

app.on('change keyup', function(e){
  const val = $(e.target).val();
  data.foo = val;
  updateHtml(data);
});

I have created a codesandbox for you to test https://codesandbox.io/s/magical-leftpad-ry2lx?file=/src/index.js

Try typing in the input and you will find it loses focus after a keyup. So, how to solve this problem so that I can write in the input and the data object updates itself according to the inbox?

Update

I would like to provide more context on the actual application I am developing. I cam creating a complex form that includes, checkboxes, radio buttons, repeater fields which changes inputs depending on another input (conditional fields).

I do not want to update dom elements (adding/inserting/removing) by event listeners. Dom should update when data updates. That is why I am using handlebars templating system.

Sisir
  • 2,668
  • 6
  • 47
  • 82
  • What is the purpose of re-rendering the form on keyup? – 76484 Jul 18 '21 at 21:59
  • How would you update UI without re-rendering? – Sisir Jul 19 '21 at 05:34
  • Perhaps my question should have been, Why do you need to update the UI? From the example you have given, nothing changes for the user by re-rendering the form (except for removing the focus from the input), so what is the purpose of doing it? – 76484 Jul 19 '21 at 12:31
  • @76484 ah, I see now. I've added more information on the question to provide context. If needed I can create more complex example to work on. – Sisir Jul 20 '21 at 09:00
  • With this implementation you are replacing the entire form on each keyup event. This is why your input "loses" focus, it is being replaced with a completely new input element. You will need to set its focus after each call to `updateHtml`, but you will need individual logic for each form element that was interacted with. Also, by setting the focus, the cursor will be at the start of the input and you will need to move it to the end of the text, see: https://stackoverflow.com/q/511088/3397771 . Here is a fork of your example with an implementation: https://codesandbox.io/s/elated-bell-epj5r – 76484 Jul 20 '21 at 20:48
  • @76484 Thank you. I was able to fix the issue. Could you create an answer? – Sisir Jul 21 '21 at 08:50

1 Answers1

0

I am not sure that this is the best implementation for what you want to achieve. As the complexities of the form have been left out of the example, it is difficult to properly assess this solution and to propose an alternative.

The problem with this implementation is that you are removing your form element and creating a new one upon each change and keyup event. This gets to the heart of your question about your input losing focus. The input is not losing focus; the input is being removed and replaced with a new element. The only way for the new input element to have focus is for you to directly add it via code.

As you are using jQuery and have given an ID of "foo" to your input element, you can assign it focus using:

$("#foo").focus();

However, setting focus to an element will place the cursor at the beginning of the input text and this will be painful to your user as the standard behaviour is for the cursor to remain at the end of the text; allowing the user to continue typing without first moving the cursor.

Setting the cursor position is possible via code as well. Here is a link to where the question has been asked and answered before: Use JavaScript to place cursor at end of text in text input element

The jQuery code to set the focus and set the cursor would be:

$("#foo").focus().get(0).setSelectionRange(-1, -1);

I have forked your codesandbox and added this line.

This code may work for the simplified example you have provided, but I fear it won't scale.

For example, if your form was to include even just a second text input, you would need to track which input was being changed in order to set the focus and cursor on the correct input, rather than jumping focus to the other.

I think a better solution would be to show/hide dependent parts of the form on change events rather than to replace the entire form on every change and keyup event.

76484
  • 8,498
  • 3
  • 19
  • 30