How to make element not lose focus when button is pressed? - javascript

I have a textarea in which I am inserting content at the location of the caret (thanks to Tim Down's answer). It inserts the content when the user presses a button. But it seems that when the button is pressed, the focus on the textarea is lost. How do I keep the focus there, providing the location of the caret is also the same? I was thinking along the lines of using evt.preventDefault() with .focusout(). If that helps.

Handle the mousedown-event instead of the click-event.
The mousedown event will be handled before the focus of another element is lost.
In your mousedown eventhandler, you need to to prevent event default behavior.
e.preventDefault(); // in your mousedown eventhandler
JS-Fiddle demo

You can't stop the focus from moving to a focusable element and still allow the mouse click to have its normal behavior (such as click the button). If you click on an element that supports focus such as a button, it will get the keyboard focus.
It is possible to programmatically put focus back on an element if done properly. If done poorly, it can ruin the usability of a page.
Demo: JSFiddle

You have to renew focus when button is pressed.
HTML code:
<input id="messageBox" autofocus />
<input type="button" id="messageSend" onclick="setFocusToMessageBox()" value="Send" />
Javascript code:
<script>
function setFocusToMessageBox(){
document.getElementById("messageBox").focus();
}
</script>

You can easily do this by applying focus back to the text area programmatically as the button click function is over. This way you can regain the focus along with the click event each time.

Try using tabindex="-1" on button, maybe that'll work.
<input type="text" name="body" id="body" Placeholder="message..">
<input type="submit" value="send" id="sendButton" tabindex="-1">

Related

Enter key fires both click event and keypress when multiple events are attached to button

I have two events attached to a button and when I press a key while the button is on focus both keypress and click events are fired. However, if I click the button only the click event is fired. By adding e.preventDefault() seems to fix the issue but I want to understand why it's behaving that way in the first place.
Apologies if this is a duplicate but I couldn't find a relevant answer apart from this one but the explanation isn't clear enough there.
Many thanks.
$('.btn').on('click keypress',function(e){
console.log(e.type);
});
<button type="button" class="btn" >click me</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
On button focus
if you pressed any key except (space and enter) only the keypress event will fire
But
if you focus the button and press space or enter this will fire both the events because this is a browser default behavior also for this same reason e.preventDefault() solved the problem for you.

jquery keyup and mouse click

My code:
<input class="quantity" type="text" value="33000">
<script>
$(document).ready(
$('.quantity').keyup(function (event) {
alert('up');
MyVeryImportantValidate($(this), event.key)
});
..
</script>
My problem, if introduced into the Input still holding the keys and mouse make click on any other element in page... event keyup does not work.
I think the documentation in jquery states it clearly, it is going to the item that has focus.
http://api.jquery.com/keyup/
The keyup event is sent to an element when the user releases a key on
the keyboard. It can be attached to any element, but the event is only
sent to the element that has the focus. Focusable elements can vary
between browsers, but form elements can always get focus so are
reasonable candidates for this event type.
In fact the focus is lost even on holding a key down in this input text area. If I hold down the a letter key it repeats until I click outside it changing the focus.

onClick event doesn't fire if you move mouse

I have a simple button like this:
<a class="button" href="javascript:void(0);" onclick="submitActivity();">Add</a>
I also tried with:
<a class="button" href="javascript:submitActivity();">Add</a>
In both cases, it doesn't register the click if the mouse has moved a certain amount of pixels between mousedown and mouseup. This can lead users to believe they have submitted the info when they didn't
This is happening in Chrome. Haven't tested other browsers.
I want the event to fire regardless of where in the button you click and release.
Edit: The same thing is happening in Firefox, but visually it looks like I'm dragging the link. This way it at least makes sense to the user that it doesn't submit, but in Chrome there are no such visual indicator of what is happening.
A click is defined as "holding down the mouse button, and then letting go of the mouse button." It is a combination of a mouse down and mouse up event executed on the same element. If the user moves away from the element, they are no longer executing a click, simply a mousedown (and also a mouseout, and then a mouseup on a different element).
This is standard, intuitive behavior. Users don't expect their click to "matter" unless they let go of the mouse without moving.
If for your application it is really important than ANY click result in this submit happening for you, then don't go with an onclick, go with onmousedown.
<a class="button" href="javascript:void(0);" onmousedown="submitActivity();">Add</a>
EDIT: Misunderstood your problem. Perhaps this syntax that I am used to will work for you will work for you:
<INPUT type="button" value="Add" name="add_button" onClick="submitActivity()">
Solution was to do a preventDefault() on onmousedown.
$(".button").mousedown(function(event){
event.preventDefault();
return false;
});
Demo fiddle
<a class="button" href="javascript:void(0);" onMouseDown="submitActivity();">Add</a>
I stumbled upon the same problem but in another context. I created custom buttons using divs with onclick="..." and placing child divs into them for the button text and icon. When moving the cursor even one pixel over a child div between mousedown and mouseup, the parent div generated a mouseout event which prevented the click event to be fired. I could not find a way to disable the mouseout event, but found a simple CSS-solution to this problem. Just disable pointer-events for all children:
.buttondiv * {
pointer-events: none; /* prevent click problems in buttons containing child divs */
}

How do you avoid losing focus on a contenteditable element when a user clicks outside that element?

I want to prevent a contentEditable area from losing focus if a click is made outside that area. Some sample HTML looks like this:
<div id="content">
<p>Hello</p>
</div>
<div id="clickThis">
<p>If you click on this or anywhere for that matter after focusing on Hello, you lose your focus on Hello</p>
</div>
Sample Javascript looks as follows:
$(document).ready(function()
{
$('#content')[0].contentEditable=true;
$('#clickThis').bind('click',function(e)
{
console.log(window.getSelection().getRangeAt(0).startContainer);
e.preventDefault();
});
});
When you click on the #clickThis div or anywhere outside the #content div, you lose focus on the #content div even if you call the click event's preventDefault function.
In addition, the range changes the moment the click event is fired, so I can't just return to the previous range after the click has occurred. Is there a way to maintain the cursor position and focus after a click occurs?
jsFiddle: http://jsfiddle.net/VivekVish/FKDhe/4/
Putting Juan's question into an answer, instead of using the click event, you have to use the mousedown event as follows:
$(document).ready(function()
{
$('#content')[0].contentEditable=true;
$('#clickThis').bind('mousedown',function(e)
{
console.log(window.getSelection().getRangeAt(0).startContainer);
e.preventDefault();
});
});
You can see it working here:
http://jsfiddle.net/FKDhe/7/
The answer is to add event.preventDefault() to the mouseDown event.
const button = document.getElementById('boldFormat')
button.addEventListener('mousedown', (event) => {
event.preventDefault() // prevent loss of focus
document.execCommand('bold', false)
})
The problem occurred because the you are listening to the click event which causes the contentEditable element to lose focus; regardless of whether you run preventDefault or not.
try adding $('#content').focus(); after e.preventDefault();
it's not a perfect solution, since it jumps to the beginning, but give it a try.
anyway, are you sure it's a good idea to force the user back to this area? :)

onfocus is not called when using the autofocus attribute on an input tag

In the following example, I get only one alert box. I read that the focus is put before the JavaScript code is executed. Is there a way to get this to work on?
<input id="i" type="text" autofocus onfocus="alert(1)">
<script type="text/javascript">
document.getElementById('i').addEventListener('focus', function() {
alert(2);
}, false);
</script>
(I have only tested this in Safari)
Edit:
I can obviously do it this way (Prototypejs selector):
var autofocusElement = $$('input[autofocus]')[0];
callListener(autofocusElement);
But it looks ugly compared to only add an event listener.
Edit:
Do not worry over a lack of browser support for the autofocus attribute. It solved easily as I have done in I fiddle links to below. There is also the best solution to the problem as I can see. My question is if I can do it in a less ugly than having to call the listener manually.
http://jsfiddle.net/tellnes/7TMBJ/3/
It works fine in Firefox 3.6 since Firefox does not support autofocus. But in Safari, which supports autofocus, are not the event called.
From the HTML5 working draft:
There must not be more than one
element in the document with the
autofocus attribute specified.
So you're asking for undefined behavior anyway.
With only one autofocus element, under Firefox 3.6, neither of the handlers get called on page load. Manually giving the focus to the element calls both handlers (then proceeds into an infinite loop, due to the alert boxes giving the focus back to the element when closing).
The HTML5 draft does say that autofocus should perform the focusing steps on page load, including raising the focus event, but chances are that browsers are not currently implementing that feature in a complete or consistent manner.
You might want to explicitly call your focus event handler during page load until the HTML5 spec is finished and browsers start aiming for complete support.
The following code from your current example:
<input id="i" type="text" autofocus onfocus="alert(1)">
<script type="text/javascript">
document.getElementById('i').addEventListener('focus', function() {
alert(2);
}, false);
</script>
Is going to cause an infinite loop of alerts going from 1 to 2
[eidt]
because: (this happens only in broswers that support autofocus )
input gets autofocus, fires event which fires an alert, alert grabs focus, click ok, input grabs focus, focus event fires new event triggering now two different alerts (DOM fully loaded now so new event is added with another alert), both alerts grab focus, click ok, click ok, input grabs focus fires new event triggering now two different alerts, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events...
Textual description of an infinite process FTW!....? :P
[/edit]
In your previous examples with two auto-focuses applied it seems that the last one will be executed as in the example I have attached at the bottom. I also added a way of adding a focus event to each input based on a class name... Not sure if you're looking for that but though it might be of some help.
JSFiddle Example of onfocus event
You need to give a value to autofocus.
<input id="i" type="text" onfocus="alert(1)" autofocus="">
Give autofoucs="autofocus" attribute after all events has been given to the input field.
You can also use addEventListener in .js file at the top.
It might be that the autofocus onfocus event fires before addEventListener adds the event listener.
I replaced autofocus with class="autofocus" on my input element, and set the focus like this near my addEventListener call:
if(searchInput.classList.contains('autofocus')) {
searchInput.focus();
}
If you need to execute a piece of javascript code, onfocus for either input, you could use jQuery: http://api.jquery.com/focus/

Categories