Handlebars form template, input loses focus when updates using keyup - javascript

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.

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.

Related

Refocus input field after page gets refreshed in wicket

Is it somehow possible to refocus an input field after a refresh which was last focused before the page was requested?
I have a Wicket Form within my WebPage and in this Form there are quite some input fields (like text fields) the user can use to filter my data view. But when the user for example has the focus on the second input field and then clicks on 'go to next page' within the data view he loses the focus, but due to accessibility it is necessary to refocus the second input field.
My idea was to first tag the input field with jQuery with "regain-focus" when focused:
$("input").focus(function() {
$("input").removeAttr("regain-focus");
$(this).attr("regain-focus", "regain-focus");
});
Then on server update search for the element with the "regain-focus" tag - but that's the part, I don't know how to do that... - tag the corresponding component with "autofocus":
input.add(AttributeModifier.append("autofocus", "autofocus"));
and refocus with javascript:
$('[autofocus]').focus();
Since you have JavaScript experience it would be much simpler to do it completely client side: $(document).on('focusin', 'input textarea', function(event) {localStorage.setItem('focus:'+location.pathname, event.target.id)}) and then use jQuery.ready() based logic to read the entry and use it.
When your page DOM/elements change between requests/refresh/ajax calls, it is better to use a CSS selector using optimal-select to store just a unique identifier for the element and use a JQuery selector to find it again for focus setting. I used this in the NoWicket web framework to remember the focused element on ajax calls. Example JS code here.

Update individual form element values in database via ajax?

I have quite a few input elements on a page that a user can change. I don't want to submit a form. I just want the database value to be changed after the user changes the value inside one of the elements.
I'm currently experimenting with binding focusout to each of the inputs. Is this the way it's usually done (facebook, etc..)?
$('input').focusout(function() {
var current_val = $(this).val();
var preset_val = $(this).attr('rel');//attribute set with original value
if (current_val !== preset_val) {
alert ('Value changed.');//where I would post to php page to update database
}
});"
The way it is "usually done" is to wait until the user clicks a button to save or commit the changes. If you're going to update each change, you should make sure to be very clear about that to the user.
The appropriate event to use will be dictated by how aggressive you want to be in capturing changes. For per-keystroke updates, keyup would be appropriate for inputs, click for selects and radios/checkboxes. Less aggressive would be blur or change.
One way to be extremely proactive about capturing any possible change is to attach a click and a keyup to the form element itself. This will also save the overhead of adding a listener to every element. Each time an event is fired on the form, you can either a) check the original target, or b) ajax the entire form, or c) loop all the elements and detect changes, only ajax changed fields.
onbeforeupload can be used to do a final check of the form in case the window is closed, as well, but that's probably being a little too hyper.
Documentation
https://developer.mozilla.org/en-US/docs/DOM/HTMLFormElement
https://developer.mozilla.org/en-US/docs/DOM/element.onkeyup
https://developer.mozilla.org/en-US/docs/DOM/element.onchange
https://developer.mozilla.org/en-US/docs/DOM/element.onblur
https://developer.mozilla.org/en-US/docs/DOM/element.onclick

How to do a live update to an HTML form using javascript

I need to live update a text field in html using javascript, that is as the user is typing text in one field, the contents are being displayed in another as they type. i need just a short code snippet to do that. eg as a person is typing their name, the name is being typed one letter at a time at another position on the screen.
Give the two fields an id each, then use something like this:
document.getElementById("field1").onkeyup = function() {
document.getElementById("field2").value = this.value;
}
All it does is bind an event listener to the onkeyup event, which fires every time a key is released. In the event listener, it simply copies the value of the field which received the event to another field, specified by id.
Here's a working example.

Setting a field based on a ComboBox selection

I'm not a newb to JavaScript but this is my first foray into Acrobat Scripting.
What I'm trying to do is change a text field based on the value selected in a comboBox.
Since I have many different comboboxes with the same set of options, and many text fields that are supposed to be bound to those, I would prefer a document scope function that could be reused for all of those.
I'm not sure if this is possible but here's what I'm thinking...
Detect when a combo box is changed. On the change event submission, take the export value from that and make it the value for the related text field.
Here's the steps:
capture combo box onmouseup event
detect which combo box triggered the event
match up the name of the combo box to its associated text field using an array listing
use a getField() to fetch the text field
set the text fields value to be the export value of the combo box
Any help with this would be appreciated. Especially good sources about Acrobat event triggers and how they work. I have been through a great deal of the API documentation and can't find anything on it.
Found it!
After exhaustive hours/days of Googling I finally found a solution that works.
The handler function needs to be bound to the 'Keystroke' event.
The handler function should contain:
if(!event.willCommit) {
this.getField('[field]').value = event.change;
}
Note: Where 'field' is the name of the field being updated and event.change is the value selected in the combobox.
To fetch the export value of the selection use the following:
if(!event.willCommit) {
this.getField('[field]').value = event.changeEx;
}
Apparently, 'Keystroke' is fired any time a UI element is interacted with. If you don't want it to execute when the document loads, be sure to bind the handler function to the event during the page load event.
Thoughts: AcroForms JS (Javascript for Acrobat) has a seriously broken event model. If you were to get the value of the combobox while using this even handler it would serve up a stale value. Not only does it take an obscure hack to make it work but there is little/no AcroForms JS community to provide answers to hard questions like these.

Detect document is in direct focus

In Javascript, how do you detect if the document is in direct focus. By direct focus, I mean you're on the document, but no form elements are focused.
What I'm trying to do here is opposite of Stackoverflow's WYSIWYG editor. Stackoverflow bolds the text when you hit CTRL+B while focus is on the textarea. I want to execute a command when the user is NOT filling out any form on the page. For example, SHIFT+N goes to the next step in my application, but still allows writing capital Ns on form textareas.
I use the Prototype framework, BTW.
There is no need to track focus, it is overcomplicating things and that doesn't pass the common sense smell test... something could go wrong if you missed just one event.
If you observe the root element of a page (document or document.body) then all events which aren't explicitly stopped will reach there and you'll be able to filter out those that started on a form element.
document.observe('keypress', function(event, element) {
if (event.findElement('input, select, textarea') == document) {
// No input was typed on.
}
});
This example doesn't filter out anchors but could do easily by adding a to the findElement call.
Why don't you use a global javascript variable as a flag ?
var isFocusedOnElement = false;
And assign an onfocus trigger to all text areas,input boxes which change it to true onfocus, and false on onBlur.
Then you can check this flag whenever you encounter they keystrokes.

Categories