Javascript: Reset the selected focus on an element that is being rerendered - javascript

I'm using dust.js in order to render Javascript templates to HTML. Using dust.js, I've basically broken my page into template components, that are rerendered in response to certain events. One such component/template conceptually looks as follow:
[Label] [Input1] [Input2] [Input3]
All 3 inputs in this component have an onBlur event which is used to recalculate the value of the other inputs and which in turn causes the template to rerender. So for instance, if the user modified the value of Input1, both Input2 and Input3's values will be adjusted and rerendered.
The reason I rerender the template instead of just setting the values is that the template contains additional logic and elements that are rendered depending on the values (so for instance, certain values would result in an error message being rendered or an additional field being displayed).
So far so good, but this causes a focus problem. Take for example if the user modifies Input1 and then clicks on Input2. The onBlur will trigger, I'll update the values of Input2 and Input3 and then rerender the template. This in turn will cause the user's focus to be discarded, and they'll have to click on Input2 again.
I need a way to know that the user clicked on Input2 so that I can set the focus to it after the rerendering has been completed. As the onBlur event triggers before onFocus, I can't think of any way to do this.
Is there any solution other than bypassing the template rendering?

I had a similar problem. I solved it by delaying the "blur" event listener function with about 100ms, to allow the focus event on another input to fire before the blur handler starts rendering.

Related

How to respond immediately to a change in a number input element in Javascript

I am a beginner at HTML/CCS/Javascript, and I am designing a website which looks like this :
I would like to ensure that the table displayed below is always in sync with the number input element.
I have an input number element like this:
<label for="loansize">Loan Size (USD) (between 500 and 3000):</label>
<input type="number" id="loansize" name="loansize" value="3000" min="500" max="3000">
Currently the table does refresh when the user clicks elsewhere on the page, because I have added code like this :
'<div onChange="processPage();">' ... Render the HTML ... '</div>';
But this does not catch the user being in the process of changing the input number, so I get in a situation like this:
The bottom table remains unchanged from the above picture, even though the number input has changed. It takes a click elsewhere on the page for the table to be back in sync.
How can I ensure the table is re-rendered (i.e. remains in sync) in such a situation ?
Instead of using inline onChange which is considered as a bad practice. You can modify the element using DOM. Here is the simple way to fire the processPage() function every time the value in the loan input is changed.
const loanSize = document.getElementById('loansize');
loanSize.addEventListener('input', processPage);
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event
You can try using the onInput listener.
From MDN:
The input event is fired every time the value of the element changes. This is unlike the change event, which only fires when the value is committed, such as by pressing the enter key, selecting a value from a list of options, and the like.

How to stop reactjs component rerender on state change

I have a form with some input fields (some of them hidden until a checkbox is checked. When I check/uncheck the checkbox a specific state is set (this.state.isChecked = true/false).
On render method, i have a div (containing some input fields) with some classes and this condition for "show" class: <div className={'extra-fields ' + (this.state.isChecked? ' show' : '')}>...</div>
Expected behavior is that on state change, only the "show" class is putted or deleted from div
Current behavior: the entire form is rendered again and all data written in the input fields are lost.
How it should be done this?
If the value of the input fields is important (which they apparently are), and if they can change (which the obviously can), then React should be aware of them, typically in state.
The 'standard' (on only) react way to maintain the contents of the input fields is:
put the content of the input fields in state as well,
include something like value={this.state.foo} and onChange={this._onChange()} to the render of each input field
include the _onChange() function to the form to handle input changes
That way, whenever the form is re-rendered (after each setState()), the input values are also preserved.
PS: The question title "stop reactjs component from rerender on state change" does not really cover the question from text: you are asking for a partial re-render: do re-render the show/hide extra fields based on checkbox, but do not re-render input fields.
The short answer is that you can prevent a component from rendering/updating with the shouldUpdateComponent life-cycle event: https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate
However, I agree with the previous answer, that for the sake of doing what sounds like a partial re-render, and to follow best practices in general, you should be storing the state of your input fields somewhere in a component so that they persist beyond a render call.

How to initialize form additions for jquery methods?

I've got a form where I'm trying to do the sort of thing you often see with tags: there's a textfield for the first tag, and, if you put something into it, a new and similar textfield appears to receive another tag. And so on. I've gotten the basics of this working by setting up a jQuery .blur() handler for the textfield: after the value is entered and the user leaves the field, the handler runs and inserts the new field into the form. The handler is pretty vanilla, something like:
$('input.the_field_class').blur(function () { ... });
where .the_field_class identifies the input field(s) that collect the values.
My problem is that, while the new textfield is happily added to the form after the user enters the first value, the blur handler doesn't fire when the user enters something into the newly-added field and then leaves it. The first field continues to work properly, but the second one never works. FWIW, I've watched for and avoided any id and name clashes between the initial and added fields. I had thought that jQuery would pick up the added textfield, which has the same class markings as the first one, and handle it like the original one, but maybe I'm wrong -- do I need to poke the page or some part of it with some sort of jQuery initialization thing? Thanks!
Without seeing your code in more of its context, it's hard to know for sure, but my best guess is that you're attaching a handler to the first field, but there is no code that gets called to attach it to the new field. If that's the case, you have a few options, two of which are:
1) In your blur() handler, include code to attach the blur handler to the newly created field.
2) Use jQuery's event delegation to attach a handler to the field container, and listen for blur events on any field in the container:
<div class="tag-container">
<input class="the_field_class" /> <!-- initial tag field -->
</div>
<script>
var $tagContainer = $('.tag-container');
var createNewField = function() {
$tagContainer.append($('<input class="the_field_class" />');
};
$tagContainer.on('blur', 'input.the_field_class', createNewField());
</script>
Which is better will depend on your use case, but I'd guess that the 2nd option will be better for you, since you're unlikely to be dealing with tons of blur events coming from the container.

angular.js: select textearea's content upon modification

I want to know if it's possible to select a textarea's content when it gets modified. In jQuery, I'd do the following:
$("texarea").on("change", function (e) {
$(this).select(); // the content gets selected for copy/cut operations
});
I know it's a bad practice to directly manipulate DOM elements from within an angular controller, so if you know how I can do this cleanly, I'd be happy to learn how!
I think you can do the following, attach an event handler to your textfield element using onblur and onfocus attributes. Write two functions for each as follows:
onfocus get the initial content of the textfield
onblur get the final content and compare to the initial content if there is a difference the run the select function
If you want it to be in real time your could also use onkeyup and onkeydown

Is it possible to set the pre-change value of an input element

I have an input element with an onchange event. The onchange event alerts the user if the value is not accepted, and returns focus back to the input element.
However, if the user then clicks out of the element, the onchange event doesn't fire - which is understandable since the user hasn't made a further change, but it introduces the problem of only validating once.
I explored a possible solution to reset the value back to what it was before it was changed, but I'd like to avoid that if at all possible for the sake of allowing the user to correct the value they entered without having to type the whole thing again.
Another possibility was to put the validation into the blur event but this would introduce other problems such as events on other elements firing if they are focused.
So my question is, if the user changes the input value from 'X' to 'Y', can I return focus to the element, leaving the value as 'Y' but make it treat 'X' as the pre-change value, thus behaving so if the user changes it back to 'X' the change event will not subsequently fire, but if they leave it as 'Y' and lose focus again, the change event fires again as if changing from 'X' to 'Y'?
Why not just mark the field as invalid (using CSS or jQuery to add markup) instead of using an alert? The field remains invalid until the user changes the value to a valid one, and the validation script removes the invalid marking.
Is the input type text? In these circumstances I prefer to use onkeyup instead of onchange for the very reason you're describing.
Sometimes even that doesn't work: This will not capture the change when text is pasted into the text box using a mouse since a key isn't pressed (but shift+insert or ctrl+v are). You might want to add the same event to both onchange and onkeyup to cover all bases.

Categories

Resources