Changing browser tabs undesirably fires the focus event, especially in Google Chrome - javascript

I've got a little issue with the focus event that I just became aware of. Apparently, focus fires when switching to another browser tab and then back again. I'd rather not have that happen; is it possible?
I was never aware of this until today. Here's a little demo: http://jsfiddle.net/MJ6qb/1/
var times = 0;
$('input').on('focus', function() {
times ++;
$(this).after('<br>Focused '+times+' times');
});
To reproduce: Focus on the input, then switch browser tabs, then switch back. All browsers seem to fire the focus event when you switch back to the tab, and Google Chrome 19 is firing it twice!
Ideally, the function should not run when switching browser tabs at all but only on user click or Tab, but now that I'm aware of the Chrome issue I'm a bit more concerned about that because it's resulting in extra unwanted back-to-back AJAX requests in my real app (it's for fetching results for an autocomplete that needs to be up to date, but not so much that I want to use the keyup event).
It doesn't seem jQuery related (I did test with vanilla javascript) but I can using jQuery for a solution. Is there anything I can do about this? I know I can use jQuery's one() but I do want the function to run more than once.

Try this
var times = 0;
var prevActiveElement;
$( window ).on( "blur", function(e){
prevActiveElement = document.activeElement;
});
$('input').on('focus', function() {
if (document.activeElement === prevActiveElement) {
return;
}
prevActiveElement = document.activeElement;
times++;
$(this).after('<br>Focused ' + times + ' times');
}).on( "blur", function(){
prevActiveElement = null;
});​

Try this to get around the problem:
var times = 0, foc=true;
$(window).on('focus', function() {
foc = false;
setTimeout(function() {foc=true}, 200);
});
$('input').on('focus', function() {
if (foc || times===0) {
times ++;
$(this).after('<br>Focused '+times+' times');
}
});
​
FIDDLE
​

Related

Popstate event not firing on back button

Script
window.addEventListener('popstate', function (event) {
console.log(core.current.queryString.k);
if (!core.current.queryString.k || core.current.queryString.k == "") {
$(".container").removeClass("some-class");
$(".container-class").css("height", "");
$(".container-class").css("bottom", "50px");
isSearchBarInputted = false;
}
});
The popstate event is skipped upon hitting the back browser button. It works fine before but I guess the recent updates on Chrome affected this. Are there any ways to remediate this? I'm just starting to get familiar with javascript.
Thanks in advance!

removing eventlistener for beforeunload

I'm trying to implement a popup (bootstrap modal style) that would be triggered as web visitor leaves my site.
I tried different alternatives of:
$(window).bind('beforeunload', function(){
$("#sModal").modal('show');
return 'Take our survey before you leave.';
});
However, it didn't work in FF while worked fine in IE. I had another problem also, that the "Do you want to leave or stay" alert was being displayed on any link click on my website itself, across all browser types, as the whole page was being loaded.
I got around this by looping through all my anchor tags and adding a click listener to remove the beforeunload listener using:
window.onload = function () {
var allLinks = document.getElementsByTagName('a');
for (var i = 0; i < allLinks.length; i++) {
allLinks[i].addEventListener("click", removeBeforeUnload, false);
}
};
The removeBeforeUnload function just used the
$(window).unbind('beforeunload');
Getting back to actually make the popoup/modal appear on all browsers, i used the code from this stackoverflow answer after my document completes loading:
window.onbeforeunload and window.onunload is not working in Firefox , Safari , Opera?
This solution works great across all browsers, however now I cannot unbind this event on any of my local clicked links! I tried everything
window.removeEventlistener('beforeunload',null,false);
window.removeEventlistener('onbeforeunload',null,false);
window.removeBeforeUnload();
window.onbeforeunload = null;
I hope you can point me in the right direction and explain why I cannot unbind this event, that I used from stackoverflow answer.Thanks!
One thought is use a global variable flag and don't do anything in the unload event handler when flag isn't truthy. Set this flag to null or false in link click handlers
Then you don't really need to remove the listener
var doUnload = true;
$('a').click(function(){
doUnload = false;
});
function unloadhandler(){
if(doUnload){
// show modal , return message etc
}else{
// do nothing , don't return anything
}
}
Probably jQuery is adding a 2nd beforeunload event listener, which you can't remove via the DOM API the same way as the one added to the Window by default.
What should work for you is:
var allLinks = $('a');
for (var i = 0; i < allLinks.length; i++) {
$(allLinks[i]).on('click', () => {
$(window).off('beforeunload');
// now add any custom code you want for handling this event
$("#sModal").modal('show');
)};
}

How can I bind to the change event of a textarea in jQuery?

I want to capture if any changes happened to <textarea>. Like typing any characters (deleting,backspace) or mouse click and paste or cut. Is there a jQuery event that can trigger for all those events?
I tried change event, but it triggers the callback only after tabbing out from the component.
Use: I want to enable a button if a <textarea> contains any text.
Try this actually:
$('#textareaID').bind('input propertychange', function() {
$("#yourBtnID").hide();
if(this.value.length){
$("#yourBtnID").show();
}
});
DEMO
That works for any changes you make, typing, cutting, pasting.
bind is deprecated. Use on:
$("#textarea").on('change keyup paste', function() {
// your code here
});
Note: The code above will fire multiple times, once for each matching trigger-type. To handle that, do something like this:
var oldVal = "";
$("#textarea").on("change keyup paste", function() {
var currentVal = $(this).val();
if(currentVal == oldVal) {
return; //check to prevent multiple simultaneous triggers
}
oldVal = currentVal;
//action to be performed on textarea changed
alert("changed!");
});
jsFiddle Demo
Use an input event.
var button = $("#buttonId");
$("#textareaID").on('input',function(e){
if(e.target.value === ''){
// Textarea has no value
button.hide();
} else {
// Textarea has a value
button.show();
}
});
This question needed a more up-to-date answer, with sources. This is what actually works (though you don't have to take my word for it):
// Storing this jQuery object outside of the event callback
// prevents jQuery from having to search the DOM for it again
// every time an event is fired.
var $myButton = $("#buttonID")
// input :: for all modern browsers [1]
// selectionchange :: for IE9 [2]
// propertychange :: for <IE9 [3]
$('#textareaID').on('input selectionchange propertychange', function() {
// This is the correct way to enable/disabled a button in jQuery [4]
$myButton.prop('disabled', this.value.length === 0)
}
1: https://developer.mozilla.org/en-US/docs/Web/Events/input#Browser_compatibility
2: oninput in IE9 doesn't fire when we hit BACKSPACE / DEL / do CUT
3: https://msdn.microsoft.com/en-us/library/ms536956(v=vs.85).aspx
4: http://api.jquery.com/prop/#prop-propertyName-function
BUT, for a more global solution that you can use throughout your project, I recommend using the textchange jQuery plugin to gain a new, cross-browser compatible textchange event. It was developed by the same person who implemented the equivalent onChange event for Facebook's ReactJS, which they use for nearly their entire website. And I think it's safe to say, if it's a robust enough solution for Facebook, it's probably robust enough for you. :-)
UPDATE: If you happen to need features like drag and drop support in Internet Explorer, you may instead want to check out pandell's more recently updated fork of jquery-splendid-textchange.
2018, without JQUERY
The question is with JQuery, it's just FYI.
JS
let textareaID = document.getElementById('textareaID');
let yourBtnID = document.getElementById('yourBtnID');
textareaID.addEventListener('input', function() {
yourBtnID.style.display = 'none';
if (textareaID.value.length) {
yourBtnID.style.display = 'inline-block';
}
});
HTML
<textarea id="textareaID"></textarea>
<button id="yourBtnID" style="display: none;">click me</div>
Here's another (modern) but slightly different version than the ones mentioned before. Tested with IE9:
$('#textareaID').on('input change keyup', function () {
if (this.value.length) {
// textarea has content
} else {
// textarea is empty
}
});
For outdated browsers you might also add selectionchange and propertychange (as mentioned in other answers). But selectionchange didn't work for me in IE9. That's why I added keyup.
try this ...
$("#txtAreaID").bind("keyup", function(event, ui) {
// Write your code here
});
Try to do it with focusout
$("textarea").focusout(function() {
alert('textarea focusout');
});
.delegate is the only one that is working to me with jQuery JavaScript Library v2.1.1
$(document).delegate('#textareaID','change', function() {
console.log("change!");
});
After some experimentation I came up with this implementation:
$('.detect-change')
.on('change cut paste', function(e) {
console.log("Change detected.");
contentModified = true;
})
.keypress(function(e) {
if (e.which !== 0 && e.altKey == false && e.ctrlKey == false && e.metaKey == false) {
console.log("Change detected.");
contentModified = true;
}
});
Handles changes to any kind of input and select as well as textareas ignoring arrow keys and things like ctrl, cmd, function keys, etc.
Note: I've only tried this in FF since it's for a FF add-on.
Try this
$('textarea').trigger('change');
$("textarea").bind('cut paste', function(e) { });

JavaScript on iOS: preventDefault on touchstart without disabling scrolling

I am working with JavaScript and jQuery in an UIWevView on iOS.
I'v added some javascript event handler that allow me to capture a touch-and-hold event to show a message when someone taps an img for some time:
$(document).ready(function() {
var timeoutId = 0;
var messageAppeared = false;
$('img').on('touchstart', function(event) {
event.preventDefault();
timeoutId = setTimeout(function() {
/* Show message ... */
messageAppeared = true;
}, 1000);
}).on('touchend touchcancel', function(event) {
if (messageAppeared) {
event.preventDefault();
} else {
clearTimeout(timeoutId);
}
messageAppeared = false;
});
});
This works well to show the message. I added the two "event.preventDefault();" lines to stop imgs inside links to trigger the link.
The problem is: This also seems to prevent drag events to scroll the page from happen normally, so that the user wouldn't be able to scroll when his swipe happens to begin on an img.
How could I disable the default link action without interfering with scrolling?
You put me on the right track Stefan, having me think the other way around. For anyone still scratching their head over this, here's my solution.
I was trying to allow visitors to scroll through images horizontally, without breaking vertical scrolling. But I was executing custom functionality and waiting for a vertical scroll to happen. Instead, we should allow regular behavior first and wait for a specific gesture to happen like Stefan did.
For example:
$("img").on("touchstart", function(e) {
var touchStart = touchEnd = e.originalEvent.touches[0].pageX;
var touchExceeded = false;
$(this).on("touchmove", function(e) {
touchEnd = e.originalEvent.touches[0].pageX;
if(touchExceeded || touchStart - touchEnd > 50 || touchEnd - touchStart > 50) {
e.preventDefault();
touchExceeded = true;
// Execute your custom function.
}
});
$(this).on("touchend", function(e) {
$(this).off("touchmove touchend");
});
});
So basically we allow default behavior until the horizontal movement exceeds 50 pixels.
The touchExceeded variable makes sure our function still runs if we re-enter the initial < 50 pixel area.
(Note this is example code, e.originalEvent.touches[0].pageX is NOT cross browser compatible.)
Sometimes you have to ask a question on stack overflow to find the answer yourself. There is indeed a solution to my problem, and it's as follows:
$(document).ready(function() {
var timeoutId = 0;
$('img').on('touchstart', function(event) {
var imgElement = this;
timeoutId = setTimeout(function() {
$(imgElement).one('click', function(event) {
event.preventDefault();
});
/* Show message ... */
}, 1000);
}).on('touchend touchcancel', function(event) {
clearTimeout(timeoutId);
});
});
Explanation
No preventDefault() in the touch event handlers. This brings back scrolling behavior (of course).
Handle a normal click event once if the message appeared, and prevent it's default action.
You could look at a gesture library like hammer.js which covers all of the main gesture events across devices.

how to identify onbeforeunload was caused by clicking close button

How do I determine if onbeforeunload was caused by clicking the close button or a page refresh or generally what event caused onbeforeunload?
here is a snippet:
window.onbeforeunload = function( e ){
if( !e ) e = window.event;
// insert code to determine which is the source of the event
}
Please help me.
Referring to various articles and doing some trial and errors, finally developed this idea which works perfectly for me just the way i wanted it to happen. The logic was quiet simpler it implement as well The idea was to detect the unload event that is triggered by closing the browser. In that case, the mouse will be out of the window, pointing out at the Close('X') button.
$(window).on('mouseover', (function () {
window.onbeforeunload = null;
}));
$(window).on('mouseout', (function () {
window.onbeforeunload = ConfirmLeave;
}));
function ConfirmLeave() {
return "";
}
The ConfirmLeave function will give the pop up default message, it case there is any need to customize the message, return the text to be displayed instead of empty string
See if this helps, :)
As far as I know, there is no way of determining what caused the onbeforeunload. The event is triggered when window is about to close whether closing the browser or some other way.
If the close button was pressed the value of e.clientY is negative. For the other possible sources i doubt there is a solution.
window.onbeforeunload = function() {
var e = window.event;
alert(e.clientX + " / " + e.clientY);
}
I searched for something similar but ended up empty handed.
So I tried doing the opposit
We can identify all the events but browser events.
Refer below (Untested) snippet.
var target = $( e.target );
if(!target.is("a, :button, :submit, :input, .btn, .bulkFormButton")){
//Your code for browser events)
}
$("form").submit(function () {
//Your code for browser events)
});
This worked for me but there are still some events that are not handled.
I am in search of those.
If anyone have idea about them please share.

Categories

Resources