focusout happening immediately after focus() - javascript

I am creating 'typeform like' form, that scrolls one input element at a time.
name -> email -> phone -> address -> note
(codepen here)
With the code below, I have the situation that after entering value for phone and pressing enter, address gets skipped. Flow directly reaches note.
The reason is that focusout event gets fired, immediately after target.find(".input-box").focus() on input#address.input-box.
I do not understand what is causing focusout to be fired.
Can anyone explain? (and how to stop it from happening).
The intent is to have phone element scroll after user enters the input on mobile. On iOS for example, there is no Enter key for phone entries, only 'Done'.
I use focusout since it the event fired on pressing 'Done'. But it is too broadly fired, to properly work with.
Is there a better way to achieve the expected behavior?
HTML:
<!-- ... -->
<div class="flex-container">
<form novalidate="">
<div class="input-block flex-item" id="input-block-name" style="display: inherit;">
<div class="label">name</div><input class="input-box" type="text" id="name">
</div>
<div class="input-block flex-item" id="input-block-email" style="display: none;">
<div class="label">email</div><input class="input-box" type="email" id="email">
</div>
<div class="input-block flex-item" id="input-block-phone" style="display: none;">
<div class="label">mobile</div><input class="input-box" type="tel" id="phone">
</div>
<div class="input-block flex-item" id="input-block-address" style="display: none;">
<div class="label">address</div><input class="input-box" type="text" id="address">
</div>
<div class="input-block flex-item" id="input-block-note" style="display: none;">
<div class="label">note</div><input class="input-box" type="text" id="note">
</div>
<!-- ... -->
</form>
<!-- ... -->
JS:
$(".input-box").first().focus();
$(".input-block")
.not($(document.activeElement.parentElement))
.css({ display: "none" });
$(window).on(
"keyup wheel focusout",
_.debounce((event) => {
var current = $(":visible").closest(".input-block");
// next
if (
event.key === "Enter" ||
event.originalEvent.deltaY > 0 ||
(event.type == "focusout" && event.target == $("#phone")[0])
) {
var target = $(":visible").closest(".input-block").next();
target.css({ display: "inherit" });
target.find(".input-box").focus();
current.css({ display: "none" });
}
// prev
if (event.originalEvent.deltaY < 0) {
var target = $(":visible").closest(".input-block").prev();
target.css({ display: "inherit" });
target.find(".input-box").focus();
current.css({ display: "none" });
}
}, 30)
);
EDIT: refined the question, after first response.

EDIT by OP: what 'solved' the issue, was to use blur event (see comments).
I believe your issue is with this line (in the if condition):
(event.type == "focusout" && event.target == $("#phone")[0])
With each scroll there will be a 'focusout' type from the previous input. When you scroll from phone to address, the phone input box has a type of 'focusout' and the above referenced code condition is true, hence why the result of the condition is happening twice.
Fully removing the above referenced line should resolve your issue.

Related

how to prevent doubling the input file if the user opened it and closed it without choosing a file

I want when the user chooses a file there is another input file is created but with my code when the user open it and close it without choosing a file then he opened it again and chose one there are 2 inputs are created if he opened and closed 3 times then chose one there are 4 inputs are created.
if he chose a file from the first time there is just 1 is created
<div class="gal-stf">
<input class="plus-n" type="file">
<p class="bt"></p>
</div>
<div class="ad-photo" style="display: none;">
<div class="gal-stf">
<input class="plus-n" type="file">
<p></p>
</div>
</div>
$(".gal").on("click", ".plus-n", function () {
var el = $(this).val();
$(this).change(function () {
$('.gal').append($('.ad-photo .gal-stf').last().clone(false));
$(this).prop('disabled' , 'disabled');
$(this).siblings('p').text(this.value);
});
});
Actually, it's happening because you are binding event handler on each click, so 3 click means 3 different handlers and each will fire when change event happened. Instead of listening click event directly listen to change event using event delegation.
$(".gal").on("change", ".plus-n", function() {
$('.gal').append($('.ad-photo .gal-stf').last().clone(false));
$(this).prop('disabled', 'disabled');
$(this).siblings('p').text(this.value);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="gal">
<div class="gal-stf">
<input class="plus-n" type="file">
<p class="bt"></p>
</div>
<div class="ad-photo" style="display: none;">
<div class="gal-stf">
<input class="plus-n" type="file">
<p></p>
</div>
</div>
</div>

Understand how element focus works with javascript

I'm trying understand how element focus works.
My questions is:-
Does Javascript focus have some limitations? I mean does it have same permissions when it runs from website code and from debug console?
also does focus depends on user action? Because I have code example which I can't understand why it runs like this:-
$('document').ready(function() {
$('#username').focus();
$("#username").focus(function() {
$('.placeholder').hide();
});
$('#ss').click(function() {
$('#username').focus();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="placeholder_input">
<input type="text" id="username" maxlength="100" />
<div class="placeholder_container">
<div class="placeholder">username</div>
<div id='ss'> damc</div>
</div>
</div>
Example On JSFiddle
When code starts run it must focus input field and hide text but it not doing this can't understand why? But when I'm making click on text then it makes focus on input field and hides text. Why it can't hide in beginning? Is it some kind of limitation?
You are focusing the element before you bind the event listener. Change the order and it works as planned:
$('document').ready(function() {
$("#username").focus(function() {
$('.placeholder').hide();
});
$('#ss').click(function() {
$('#username').focus();
});
$('#username').focus(); // focus here after your events are bound
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="placeholder_input">
<input type="text" id="username" maxlength="100" />
<div class="placeholder_container">
<div class="placeholder">username</div>
<div id='ss'> damc</div>
</div>
</div>

Submitting textarea on enter keydown without refresh

I am trying to submit a textarea when the user presses the enter key, saving the text in a var, then replacing the form with the text and appending a new form to the end, all without refreshing. I was able to do this with an input just fine, but I needed the textarea and can't get it working.
HTML:
<div class="col-md-6 col-md-offset-6 col-centered terminal-header">
<div class="close text-center">x</div>
<p id="header-text">guest#sethrait:~</p>
<div class="row">
<div id="terminal-window" class="col-md-10 col-md-offset-2 col-centered">
<div class="form_wrapper">
<form class="terminal-text">
<p id="p_term" class="terminal-text">guest#sethrait:~ $ </p>
<textarea class="form_input" name="terminal" placeholder="Currently under construction, please come back later"></textarea>
</form>
</div>
</div>
</div>
</div>
JS:
$( document ).ready(function() {
$(".form_input").keydown(function(){
if(event.keyCode==13){
$(".terminal-window").on("submit", "form", function (e) { //when form is submitted
submitCommand(e);
});
}
});
});
//triggered when user submits a command to the console
function submitCommand(e){
e.preventDefault();
var usrCommand=$('.form_input').val();
processCommand(usrCommand);
$(".form_wrapper").replaceWith("<p class='new-terminal-text' style='margin-left: -12px'>"+loc+usrCommand+"</p>"+"<br>");
$("#terminal-window").append("<div class='form_wrapper'><form class='terminal-text'><p class='terminal-text'>guest#sethrait:~ $</p> <textarea class='form_input' name='terminal' placeholder='echo Currently under construction, please come back later'></textarea></form></div>");
}
Note, not certain what processCommand , loc are , not appear defined at js at Question ?
Try substituting $("#terminal-window") for $(".terminal-window") as .terminal-window class not appear at html ; attaching keydown event to document , delegating event to .form_input as original .form_input element appear to be replaced at $(".form_wrapper").replaceWith
$(document).ready(function() {
$(document).on("keydown", ".form_input", function(event) {
// console.log(event)
if (event.keyCode == 13) {
$("#terminal-window form").on("submit", function(e) { //when form is submitted
event.preventDefault();
submitCommand(event);
}).submit();
}
});
//triggered when user submits a command to the console
function submitCommand(e) {
e.preventDefault();
var usrCommand = $('.form_input').val();
// processCommand(usrCommand);
$(".form_wrapper").replaceWith("<p class='new-terminal-text' style='margin-left: -12px'>" + usrCommand + "</p><br>");
$("#terminal-window").append("<div class='form_wrapper'><form class='terminal-text'><p class='terminal-text'>guest#sethrait:~ $</p> <textarea class='form_input' name='terminal' placeholder='echo Currently under construction, please come back later'></textarea></form></div>");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div class="col-md-6 col-md-offset-6 col-centered terminal-header">
<div class="close text-center">x</div>
<p id="header-text">guest#sethrait:~</p>
<div class="row">
<div id="terminal-window" class="col-md-10 col-md-offset-2 col-centered">
<div class="form_wrapper">
<form class="terminal-text">
<p id="p_term" class="terminal-text">guest#sethrait:~ $</p>
<textarea class="form_input" name="terminal" placeholder="Currently under construction, please come back later"></textarea>
</form>
</div>
</div>
</div>
</div>

Javascript/jQuery watch for CSS Changes

I have a simple dropdown that opens up a search field when you click it. Even though I have the text field of this search set to autofocus, it's not working for all browsers.
What method of Javascript/jQuery would I use to check if the containing UL css display is set to block, so that I can force the focus to be on the field using .focus().
HTML:
Quick Search
<ul class="dropdown-menu" role="menu">
<li id="li-quicksearch">
<form id="mainSearch" class="form-search">
<p>
<input type="text" id="inputSearch" class="form-control" placeholder="Quick Search" required="" autofocus autocomplete="off">
<button type="submit">SUBMIT</button>
</p>
</form>
</li>
</ul>
EDIT: There is no css change event so you'll have to approach the problem in 1 of 2 ways.
check the dom element in set intervals to see if its css has changed
trigger an event when the css of the dom element is changed by user interaction/your code.
the first way will look something like this:
var element = $(".dropdown-menu");
function checkForChanges()
{
if (element.css('display') == 'block')
{
// do your .focus() stuff here
}
setTimeout(checkForChanges, 500); // does this every half second.
}
or the second way:
$('.toggle').on('click', function() {
$('.dropdown-menu').toggle();
$('.dropdown-menu').trigger('change');
});
$('.dropdown-menu').on('change', function(){
if($(this).css(.css('display') == 'block')
{
// do your .focus() stuff here
}
});
You can check the display value of the ul using pure JavaScript with this:
JS:
var display = document.getElementById('dropdown-menu')[0].style.display;
if (display === 'block') {
//do what you want.
}
Or using jQuery:
if ($('.dropdown-menu').css('display') === 'block') {
//do what you want.
}
It looks like you are using bootstrap to create the dropdown. If that is the case you can use the "shown" event. However you need to attach the event on a container element.
Html
<div class="quickSearchContainer">
Quick Search
<ul class="dropdown-menu" role="menu">
<li id="li-quicksearch">
<form id="mainSearch" class="form-search">
<p>
<input type="text" id="inputSearch" class="form-control" placeholder="Quick Search" required="" autofocus autocomplete="off">
<button type="submit">SUBMIT</button>
</p>
</form>
</li>
</ul>
</div>
Javascript
$('#quickSearchContainer').on('show.bs.dropdown', function () {
$('#inputSearch').focus();
});
I want to thank everyone for their input, but the working solution that I found was to modify the bootstrap JS to allow for an autofocus on toggleClass of the OPEN for the dropdowns. Everyone gets kudos!

How to trigger onclick by pressing enter using inline javascript?

[FYI: i am not allowed to change how it was marked up. div will be clicked.. not a button or anchor]
i have a menu(that should pass on accessibility standards) that will open its submenu when clicked.
this is the onclick function, and i need to do the same function when pressing enter key,
// parent menu (this will repeat)
<div onclick="javascript:ToggleMenu('Calendar');" class="menu-item" style="cursor: hand;" tabindex="2">
<p>Calendar</p>
</div>
//submenu (this will repeat)
<div id="Calendar" class="menu-subitem" style="display: none;" tabindex="2">
<a onclick="Audit(this)" tabindex="2" href="Calendar/CalendarAssignment.aspx" id="TM_C1">Calendar Assignment</a>
<a onclick="Audit(this)" tabindex="2" href="Calendar/ShiftAssignment.aspx" id="TM_C2">Shift Assignment</a>
</div>
thanks!
i tried my best to be clear whew!
Here's the accessible solution while keeping a div:
<div id="foo" role="button" tabindex="0">Toggle menu</div>
<script>
$('#foo').click(function() {
ToggleMenu('<%# Container.DataItem.FuncID %>');
}).keydown(function(e) {
if (e.which === 32 || e.which === 13) {
this.click();
}
});
</script>
But honestly you should just use a button:
<button id="foo">Toggle menu</button>
<script>
$('#foo').click(function() {
ToggleMenu('<%# Container.DataItem.FuncID %>');
});
</script>
This will do it when they hit the enter key anywhere on the page
<div onclick="javascript:ToggleMenu('<%# Container.DataItem.FuncID %>');">
<script>
document.addEventListener("keypress", function (evt)
{
if (evt.keyCode === 13) {
//they pressed enter
//now get the divevent
var div = document.querySelector('div[onclick*="ToggleMenu"]');
//trigger the event
div.onclick.apply(div);
}
}
);
</script>
I can see you have an error in your code
onclick"javascript:xxxx"
is not correct,
"javascript:xxx"
should using on "a" tag "href" attribute, just remove the "javascript:" in your onclick attribute and you may get what you want.

Categories