Problem with giving focus to first element inside a container - javascript

I am just trying to cycle the focus between elements inside a particular element when the tab key is pressed. What I want to do is not to set focus to any element which is not a descendant of an element when tab is pressed from the last control inside the element. At that time the focus must be set to the first input element inside the container.
I have done a sample and it its not working, and I am unable to figure out the issue.
Sample can be found here
The complete code is
Script
$(function(){
$(":input:last","#div1").bind("keydown", function(e){
if ( e.keyCode === 9 )
{
var firstElem = $(":input:first","#div1");
firstElem.focus();
}
});
});
CSS
input.red { width: 200px; border: solid 1px red; }
input { width: 200px; }
HTML
<input type="text" class="red" />
<div id="div1">
<input type="text" id="txt1" />
<select id="sel1">
<option>1</option>
</select>
<input type="text" id="txt2" />
</div>
Any help would be appreciated.
Thanks
Edit
Thanks everyone. Problem solved. It was the lack of a return false; statement in the keydown event.

Try Keypress instead of Keydown
Also return false so that the keypress normal handling is cancelled.
What appears to be happening is that you are moving the focus then the tab happens, moving it to the select. You need to setfocus, then return false so that the regular tab is cancelled.
$(function(){
$(":input:last","#div1").bind("keydown", function(e){
if ( e.keyCode === 9 )
{
var firstElem = $(":input:first","#div1");
firstElem.focus();
return false;
}
});
});

Your example is not working because you are not stopping the keystroke, you set the focus on the first element, and then the tab key is sent, which causes the focus to be changed to the second element.
Try:
$(function(){
$(":input:last","#div1").bind("keydown", function(e){
if ( e.keyCode === 9 ) {
var firstElem = $(":input:first","#div1");
firstElem.focus();
e.preventDefault(); // or return false;
}
});
});
Check the above example here.

Can you not just use the tabindex attribute in the html?
If your page is dynamic it might be easier to set this attribute using JS rather than capturing the keypress etc.

Related

Why does preventDefault on parent element disable programmatically checking child checkbox on click?

A div element's click event has e.preventDefault() at the beginning. That makes manually clicking the checkbox input or it's associated label inside no longer works.
With the help of some more JavaScript code, manually clicking the label generates expected results because the checkbox is now programmatically checked/unchecked.
However, manually clicking the checkbox input still does not work despite the fact that similar JavaScript code for programmatically checking/unchecking has been implemented. Why?
document.querySelector('div').onclick = function (e)
{
e.preventDefault();
if (e.target.tagName.toUpperCase() == 'LABEL')
{
e.target.previousElementSibling.checked = !e.target.previousElementSibling.checked;
}
else if (e.target.tagName.toUpperCase() == 'INPUT')
{
e.target.checked = !e.target.checked;
}
}
<div>
<input id="check" type="checkbox">
<label for="check">Label Text</label>
</div>
Prevent default propagates often propagates down to the child. There is a way to stop that from happening by using using event.stopPropagation. Read here to learn more about other useful methods that might help your cause.
https://chunkybyte.medium.com/the-one-with-event-propagation-and-e-preventdefault-part-1-6d84f3c4220
Clicking the label sets the checked property as expected because there is no default action related to the label to be canceled. Clicking the input sets the property as expected, but due to the default action (toggling the checked property) being prevented it reverts to its previous state.
see: Why does preventDefault on checkbox click event returns true for the checked attribute? for more in depth discussion.
document.querySelector('div').onclick = function (e)
{
e.preventDefault();
if (e.target.tagName.toUpperCase() == 'LABEL')
{
e.target.previousElementSibling.checked = !e.target.previousElementSibling.checked;
}
else if (e.target.tagName.toUpperCase() == 'INPUT')
{
console.clear();
console.log(e.target.checked);
e.target.checked = !e.target.checked;
console.log(e.target.checked);
}
}
<div>
<input id="check" type="checkbox">
<label for="check">Label Text</label>
</div>
Edit
In response to your comment I think the cleanest solution would be to explicitly apply listeners to those elements that you want to control outside of the provided API methods calling stopPropagation() on them to avoid triggering the parent listeners.
You can then handle whatever logic you need without having to work around artifacts of the outside methods. If you need the parent to listener to run as well you can programmatically activate it after your control logic is finished.
// original API listener
document.querySelector('.container').addEventListener('click', function (e) {
e.preventDefault();
// add container specific code
console.log('clicked div');
});
// your isolated listener
document.querySelector('.checkbox-container').addEventListener('click', function (e) {
e.stopPropagation(); // stop the event from propagating to the parent listener
// add checkbox specific code
console.clear();
console.log('clicked checkbox container');
// even programmatically 'clicking' parent if you need to
e.currentTarget.parentElement.click();
});
.container {
width: 150px;
height: 60px;
background-color: lightgray;
}
.checkbox-container {
display: inline-block;
background-color: aquamarine;
}
<div class="container">
<div class="checkbox-container">
<input id="check" type="checkbox">
<label for="check" >Label Text</label>
</div>
</div>

iphone keyboard not hiding when tapping the screen

I have an input field with number type
<input type="number" pattern="[0-9]*"/>
In normal browsers, I'm typing some numbers and I'm tapping the screen, it hides iphone/ipad keyboard.
But this is not working if it is inside iframe. we need to click done button explicitly. This issue is only for iphone/ipad
This is an iframe issue. Any fix using Javascript/Jquery would be highly appreciated.
Updated
Tried
document.activeElement.blur();
and focusout when event triggered in javascript. none of them are working..
$(document).on('focusin', function(){
$('input').css("background-color", "green");
console.log('focusin!')
});
$(document).on('focusout', function(){
console.log('focusout!')
$('input').css("background-color", "yellow");
$('input').blur();
});
focusout is not calling inside iframe!
My question is **How to force close ipad/iphone keypad when input element is not focused using Javascript/Jquery?**
Answers will be rewarded as stated!
To remove the keyboard you need to lose the focus on your input.
document.activeElement.blur();
With this line you remove the focus and the keyboard disappear.
In your case, it's possible to add an event on your body, and stop this event if you click on an input.
$(document).ready(function () {
$('body').click(function () {
document.activeElement.blur();
console.log("blur");
});
$('input').click(function (event) {
event.stopPropagation();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text"/>
Update
I found this answer to get an active element into an iframe.
/**
* Return the active element in the main web or iframes
* #return HTMLElement
**/
function getActiveElement() {
var focused = false;
// Check if the active element is in the main web or no
if (document.body === document.activeElement ||
document.activeElement instanceof HTMLIFrameElement) {
// Search in iframes
$('iframe').each(function() {
var element = this.contentWindow.document.activeElement;
// If there is a active element
if (element !== this.contentWindow.document.body) {
focused = element;
return false; // Stop searching
}
});
} else focused = document.activeElement;
return focused; // Return element
}
With this function you can get the active element on the document or into an iframe.
After, you need to remove the focus on this element to hide the keyboard.
getActiveElement().blur();
html target <input> and <textarea>, iphone and ipad will not hide keyboard when taping on blank area ;but android will! we need to hide keyboard by hand -- it means to set the input blur;
here gose the code
$(function(){
var cacheInput = null;
var timer = null;
if(!isApple()){
return false;
}
$(document).on('focus','input',function(e){
cacheInput = e.target;
})
$(document).on('focus','textarea',function(e){
cacheInput = e.target;
})
$(document).on('touchend',function(e){
if(e.target.tagName!=='INPUT'&&e.target.tagName!=='TEXTAREA'){
if(cacheInput!==null){
timer = setTimeout(function(){
cacheInput.blur();
clearTimeout(timer);
},300)
}
}
})
function isApple(){
var ua = navigator.userAgent.toUpperCase();
var
ipad = ua.indexOf('IPAD')>-1,
ipod = ua.indexOf('IPOD')>-1,
iphone = ua.indexOf('IPHONE')>-1 ;
return ipad || ipod || iphone ;
}
})
github: https://github.com/wikieswan/iphone-input-blur
demo: http://wikieswan.github.io/iphone-input-blur
In an ionic application I used a directive on the body that intercepts the inputs.
MyApp.directive('dismissIosKeyboardOnClick', function () {
return function (scope, element, attrs) {
if (cordova.platformId=="ios") {
element.on("touchstart", function(e) {
var keyboardDoms = new Set(["INPUT","TEXTAREA","SELECT"]);
if( keyboardDoms.has(document.activeElement.nodeName) &&
!keyboardDoms.has(e.target.nodeName) )
document.activeElement.blur();
});
}
};
});
Index.html
<body ... dismiss-ios-keyboard-on-click></body>
Hope this'll solve your issue, it simply removes the focus on active element.
Using Javascript
document.activeElement.blur();
Using jQuery
$("#Clicked_button_id").click(function() {
$("#input_field_id").blur();
});
Try this.
This detects when you tab any element but the input and then blurs it.
$("html").children().not("#input_field_id").click(function(){
$("#input_field_id").blur();
});
I might possibly have a solution for your issue on iOS. My configuration is safari on iOS 8.3/5C.
From my experiments it seems to me that body element in Safari/iOS is not receptive to any click events. I am not able to explain why but it seems so.
So, what I have done is: put a wrapper div just inside body and allow it to receive the click.
Main.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>keyboard hide issue</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
//!SOLUTION
$('#body-wrapper').click(function(e) {
console.log('I got clicked');
});
});
</script>
<style>
/* ignore this. Its just styles. ... */
div#body-wrapper {
height: 200px;
width: 100%;
background-color: red;
}
input {
margin: 10px;
}
</style>
</head>
<body>
<div id="body-wrapper">
<input type="text" id="main-input1"/>
<input type="number" id="main-input2"/>
<input type="email" id="main-input3"/>
</div>
<iframe src="blur.html"></iframe>
</body>
</html>
blur.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Blur iFrame</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
//!SOLUTION
$('#wrapper').click(function(e) {
//do nothing
});
});
</script>
<style>
/* ignore this. Its just styles. ... */
div#wrapper {
height: 100px;
width: 100%;
background-color: yellow;
}
</style>
</head>
<body>
<div id="wrapper">
<input type="number" pattern="[0-9]*" id="main-input"/>
</div>
</body>
</html>
In both files I am able to hide the keyboard just fine. Again, I don't know the underlying reason but do let me know if you aren't able to replicate the solution.
I have not tried it on an iPad. Thanks ...
Well... You can give me that reward cause I just solved this problem using a very SIMPLE solution.
Step 1
:
Check if the input is currently in focus. I'll explain later why we need to add a delay on changing the value of inputFocused variable.
var inputFocused = false;
$('input').focus(function(){
setTimeout(function(){
inputFocused = true;
},100);
});
Step 2: Add an event listener if the screen or $(window) is tapped or clicked. If the window was tapped or clicked, check if the input is currently in focus. If true you must focus the window $(window).focus(), after focusing the window, the blur() function will now work! so you can now unfocus the input element then the keyboard will now hide automatically, then set the inputFocused variable to false again.
$(window).click(function(){
if(inputFocused == true){
$(window).focus();
var input = $('input');
input.blur();
inputFocused = false;
}
});`
SetTimeout explanation:
The $(window).click() event will trigger if the user tap or click anywhere on the screen (e.g. Button click, Input click, tap or click screen, etc). If you tap the input, at the same time setting the inputFocused to true, the $(window).click() event triggers then check if inputFocused is true then will run the code which hides the virtual keyboard. So it means that whenever you focus an input field the keyboard will hide and that'll be a problem.
That's why we're adding a delay so that the code inside if(inputFocused == true) will not run while we're focusing the input field and it will only run if the input field is currently on focus.
TRIED AND TESTED!

disable enable button on keypress

i want to enable button when there is some value in text box
this is working fine all most but for one value it will fail
like is enter 1 in text box
http://jsfiddle.net/akash4pj/YhQN4/
js
<script>
$(document).ready(function(){
$("#textbx").keypress(function(){
if ($("#textbx").val().length > 0) {
$("#btn").removeAttr('disabled');
}
});
$("#textbx").blur(function(){
if ($("#textbx").val().length ==0) {
$("#btn").attr('disabled','disabled');
}
});
});
</script>
html code
<input id="textbx" type="text" /><button id="btn" disabled="disabled">go</button>
Use keyup instead of keypress, like this:
$("#textbx").blur(function () {
if ($("#textbx").val().replace(/\s{1,}/g, "").length == 0) {
$("#btn").attr('disabled', 'disabled');
}
});
Also, I've added .replace(/\s{1,}/g, "") in the code as well. This ensures (indirectly) that if the user only types spaces, the button will still be disabled when the text input is blurred.
Fiddle.
The keypress event occurs before the browser processes the key, i.e. before the character is appended to the input value, so when the first key is pressed, the textbox is still empty when your functions checks the value length.
The keyup event occurs after the browser has appended the character to the input, so if you trigger on keyup instead of keypress your code should function the way you want.
I'd suggest:
$("#textbx").on('keyup blur', function() {
$("#btn").prop('disabled', $.trim(this.value).length === 0);
});
As mentioned in other answers you should use keyup, but you don't need to listen for blur as well:
$("#textbx").keyup(function(){
if ($("#textbx").val().trim().length > 0) {
$("#btn").removeAttr('disabled');
}
else
$("#btn").attr('disabled','disabled');
});
Fiddle

jquery focus first form element on tab of final

I am trying to get the cursor to jump to focus on the first element of the form. For some reason it keeps getting focus on the 2nd element instead of the first. I did just a simple form.
<form>
<input type="text">
<input type="text">
<input type="text">
<input type="submit" value="Submit">
</form>
$('form').children().keydown(function(e) {
if (e.keyCode == 9 || e.which == 9) {
if ($(this).is(':last-child')) {
$(this).parent().children().first().focus();
}
}
})
Problem
Fiddle
See console logs
when you press tab on last element it focus the 1st element and then perform tab operation so it goes to 2nd element .
Solution
Use event.preventdefault() or return false to stop tab operation .
Working Demo or Working Demo
if ($(this).is(':last-child')) {
$(this).parent().children().first().focus();
e.preventDefault(); // or return false;
}

Jquery - call function when blur+clicking certain element?

I want to call a function when a certain field gets blurred, but only if a certain element is clicked. I tried
$('form').click(function() {
$('.field').blur(function() {
//stuff
});
});
and
$('.field').blur(function() {
$('form').click(function() {
//stuff
});
});
But neither works, I reckon it's because the events happen simultaneously?
HTML
<form>
<input class="field" type="textarea" />
<input class="field" type="textarea" />
</form>
<div class="click-me-class" id="click-me">Click Me</div>
<div class="click-me-class">Click Me Class</div>
jQuery
$('.field').blur(function() {
$('#click-me').click(function(e) {
foo = $(this).data('events').click;
if(foo.length <= 1) {
// Place code here
console.log("Hello");
}
$(this).unbind(e);
});
});
You can test it out here: http://jsfiddle.net/WfPEW/7/
In most browsers, you can use document.activeElement to achieve this:
$('.field').blur(function(){
if ($(document.activeElement).closest('form').length) {
// an element in your form now has focus
}
});
I have edited my answer because we have to take into account that the event is asigned every time.
It is not 100% satisfactory, and I don't recommend this kind of complicated way of doing things, but it is the more approximate.
You have to use a global variable to take into account the fact that the field was blurred. In the window event, it is automatically reset to 0, but if the click on "click-me" is produced, it is verified before the window event, becase window event is bubbled later, it happens inmediately after the "click-me" click event
Working code
$(window).click(function(e)
{
$("#result").html($("#result").html()+" isBlurred=0<br/>");
isBlurred=0;
});
var isBlurred=0;
$('.field').blur(function() {
$("#result").html($("#result").html()+" isBlurred=1<br/>");
isBlurred=1;
});
$('#click-me').click(function(e) {
if(isBlurred==1)
{
$("#result").html($("#result").html()+" clicked<br/>");
}
});
".field" would be the input and "#click-me" would be the element clicked only just once.

Categories