alert() function is looping when called in focus() event - javascript

I Want an Alert pop-up when focusing on input. It pops up correctly but when I click on 'OK' or 'x' i.e cancel, it Loops infinitely and never closes.
$('input').focus(function () {
alert('hello');
});

This is because the input is assuming the focus again when the alert is closed (which is the new focus when it appears - notice the outline around the button in the dialogue?)
If you only want to make the alert show once, you could perhaps write something a resembling this:
let hasShownAlert = false
$('input').focus(function () {
if (!hasShownAlert) {
hasShownAlert = true
alert('hello')
}
})
Of course you could improve this with state containers or something, but this is the simplest way you could achieve it. (Note: the hasShownAlert variable has to be defined outside of the onfocus handler, otherwise it'll be cleared up by the garbage collector.)
Updated: So if you don't want it to only show once, there are a couple of things you could do. The first, the simpler, would be listening for the click event, rather than focus. The second way could be setting a didShowAlert variable -- inverting the value each time the handler is fired. E.g...
let didShowAlert = false
$('input').on('focus', (ev) => {
if (didShowAlert) {
didShowAlert = false
} else {
didShowAlert = true
alert('hello')
}
})

You could try a hack like
$(document).on("focus", 'input:not(.unFocus)', function() {
alert('hello');
$('input').addClass('unFocus');
setTimeout(function() {
$('input').removeClass('unFocus');
}, 10);
});
It may not be the ideal way to do it, but it works :)

Related

Using jQuery to recall a function window onblur+ onfocus

hI got a problem to use jQuery to recall afunction if window is on focus.
And when window is not on focus (onblur) so pause that function until window is on focus again.
Here is my code:
function functiondosomething (user_id) {
var myInterval;
var time_delay = 1000;
$(window).focus(function () {
setTimeout(function() { functiondosomething (user_id); }, time_delay);
}).blur(function () {
clearTimeout(myInterval); // Clearing interval on window blur
});
setTimeout(function() { functiondosomething (user_id); }, time_delay);// ## problem here
}
My problem is :
When I remove that line (which I marked problem here above.) the
function will not work at first time until I click out of window to
make it onblur and come back on focus again, so it starting to work.
If I let that line (which I marked problem here above.) be there,
the function could not pause, even I click out of window to make it
be onblur.
When I click onfocus it start working and stop. I have to click out
of window and focus the window again again and again. Something like it need to be activate by clicking out of window and clicking back to window again.
What should I do ?
I see a few problems here:
You're not setting myInterval so when you call clearTimeout(myInterval) it's not clearing anything.
You're using the same function to set up your listeners and call setTimeout recursively. This means your handlers are being set every time you recur, and the recursion means it will run whether the handlers run or not.
I think you need to separate things a bit:
function functiondosomething(user_id) {
// Do stuff...
}
function setupHandlers(user_id) {
var myInterval;
var time_delay = 1000;
function doSomethingWrapper() {
functiondosomething(user_id);
myInterval = setTimeout(doSomethingWrapper, time_delay);
}
$(window).focus(function () {
doSomethingWrapper();
}).blur(function () {
clearTimeout(myInterval); // Clearing interval on window blur
});
doSomethingWrapper();
};

jQuery bind to keyup only, not focus

This seems like a simple thing but google hasn't turned up anything for me:
How can I bind to a text / value change event only, excluding an input gaining focus? Ie, given the following:
$(function(){
$('input#target').on('keyup', function(){
alert('Typed something in the input.');
});
});
...the alert would be triggered when the user tabs in and out of an element, whether they actually input text or not. How can you allow a user to keyboard navigate through the form without triggering the event unless they input/change the text in the text field?
Note: I'm showing a simplified version of a script, the reason for not using the change event is that in my real code I have a delay timer so that the event happens after the user stops typing for a second, without them having to change focus to trigger the event.
Store the value, and on any key event check if it's changed, like so:
$(function(){
$('input#target').on('keyup', function(){
if ($(this).data('val')!=this.value) {
alert('Typed something in the input.');
}
$(this).data('val', this.value);
});
});​
FIDDLE
Simply use the .change event.
Update: If you want live change notifications then do you have to go through the keyup event, which means that you need to program your handler to ignore those keys that will not result in the value being modified.
You can implement this with a whitelist of key codes that are ignored, but it could get ugly: pressing Del results in the value being changed, unless the cursor is positioned at the end of the input in which case it does not, unless there happens to be a selected range in the input in which case it does.
Another way which I personally find more sane if not as "pure" is to program your handler to remember the old value of the element and only react if it has changed.
$(function() {
// for each input element we are interested in
$("input").each(function () {
// set a property on the element to remember the old value,
// which is initially unknown
this.oldValue = null;
}).focus(function() {
// this condition is true just once, at the time we
// initialize oldValue to start tracking changes
if (this.oldValue === null) {
this.oldValue = this.value;
}
}).keyup(function() {
// if no change, nothing to do
if (this.oldValue == this.value) {
return;
}
// update the cached old value and do your stuff
this.oldValue = this.value;
alert("value changed on " + this.className);
});
});​
If you do not want to set properties directly on the DOM element (really, there's nothing wrong with it) then you could substitute $(this).data("oldValue") for this.oldValue whenever it appears. This will technically have the drawback of making the code slower, but I don't believe anyone will notice.
See it in action.
This will do it, set a custom attribute and check against that:
$('input').focus(function(){
$(this).attr('originalvalue',$(this).val());
});
$('input').on('keyup',function(){
if($(this).val()===$(this).attr('originalvalue')) return;
alert('he must\'ve typed something.');
});
Be wary of events firing multiple times.
Here is another version that plainly tests if the input field is empty.
If the input is empty then the action is not performed.
$(function(){
$(selector).on('keyup', function(){
if ($(this).val()!='') {
alert('char was entered');
}
})
});

if statement around onclick

What is the best way to ignore running code when a button is clicked? I am trying the following but I currently get not reaction how I want it done.
if (!document.getElementById('btn_Cancel').getAttribute('onclick')) {
// code not to be ran when button is clicked
By default code gets ran when a textbox goes onblur so do not want that code ran when button gets clicked
}
You're going to want to make a reference to that element, so you don't end up looking it up each time it's clicked and you'll need a variable to keep track of whether it's been clicked or not:
var cancelButton = document.getElementById('btn_Cancel'),
clicked = false;
cancelButton.addEventListener('click', function() { clicked = !clicked; }, false);
// assuming this is in a loop or something:
if(!clicked) {
// running code
}
else {
// clicked, do nothing
}

passing a keydown to another element

I want to pass a keydown event to another element. Along the way I found that :
$('input').keydown(function(e) {
$('textarea').keydown()[0].focus();
});
works and that:
$('input').keydown(function(e) {
setTimeout(function() { $('textarea').keydown()[0].focus(); }, 0);
});​
doesn't work. At least in Chrome.
Anyway I want to do this with the second method as I want it to first be able to do a ctrl+c or ctrl+x on an input that has text selected and then jump to the textarea.
Here's a DEMO to see what I mean.
Why doesn't the second way work? Also is there any way to accomplish this?
Works as expected. First of all, half of your code is irrelevant. :p
$('inout').keydown(function(e) {
$('textarea').keydown()[0].focus();
});
is equivalent to
$('inout').keydown(function(e) {
$('textarea').keydown(); // doesn't do anything sensible
$('textarea')[0].focus();
});
and it transfers the focus to the textarea before the keyhandler resolves. The key ends up in the textarea. and the input doesn't even see it. (assume the code says input and not inout).
The second example:
$('input').keydown(function(e) {
setTimeout(function() { $('textarea').keydown()[0].focus(); }, 0);
});​
is equivalent to:
$('input').keydown(function(e) {
setTimeout(function() {
$('textarea').keydown(); // doesn't do anything sensible
$('textarea')[0].focus();
}, 0);
});​
so, because of the timeout, first the keydown event completes, the key is accepted as input to the input, and then the delayed function gets invoked and changes focus. Nothing further happens.
I don't know how to "repeat" or "rethrow" a keyboard event, in case you want to get the same keypress in both input and textarea (if that's what you wanted; I am not 100% sure what you wanted).
EDIT: Okay: if it's just Ctrl/Shift/another modifier key, return true so the default handler picks it up. If it's Ctrl-C (i.e. C key with ctrlKey set (metaKey on Mac), do the timeout thing (so the input catches it before the focus); if not, move focus immediately (so the textarea catches it). Not trivial, and I can't think of a better method at the moment.
Pass enough time for the setTimeout delay
$('input').keydown(function(e) {
setTimeout(function() { $('textarea').keydown()[0].focus(); }, 700); // 0.7 seconds
});
the keydown event on the textarea has no sense, and can be removed;
$('input').keydown(function(e) {
setTimeout(function() { $('textarea').focus(); }, 700); // 0.7 seconds
});

Looking for a better workaround to Chrome select on focus bug

I have the same problem as the user in this question, which is due to this bug in Webkit. However, the workaround provided will not work for my app. Let me re-state the problem so that you don't have to go read another question:
I am trying to select all the text in a textarea when it gets focus. The following jQuery code works in IE/FF/Opera:
$('#out').focus(function(){
$('#out').select();
});
However, in Chrome/Safari the text is selected--very briefly--but then the mouseUp event is fired and the text is deselected. The following workaround is offered in the above links:
$('#out').mouseup(function(e){
e.preventDefault();
});
However, this workaround is no good for me. I want to select all text only when the user gives the textarea focus. He must then be able to select only part of the text if he chooses. Can anyone think of a workaround that still meets this requirement?
How about this?
$('#out').focus(function () {
$('#out').select().mouseup(function (e) {
e.preventDefault();
$(this).unbind("mouseup");
});
});
The accepted answer (and basically every other solution I found so far) does not work with keyboard focus, i. e. pressing tab, at least not in my Chromium 21. I use the following snippet instead:
$('#out').focus(function () {
$(this).select().one('mouseup', function (e) {
$(this).off('keyup');
e.preventDefault();
}).one('keyup', function () {
$(this).select().off('mouseup');
});
});
e.preventDefault() in the keyup or focus handler does not help, so the unselecting after a keyboard focus seems to not happen in their default handlers, but rather somewhere between the focus and keyup events.
As suggested by #BarelyFitz, it might be better to work with namespaced events in order to not accidentally unbind other event handlers. Replace 'keyup' with 'keyup.selectText' and 'mouseup' with 'mouseup.selectText' for that.
Why not simply:
$('#out').focus(function(){
$(this).one('mouseup', function() {
$(this).select();
});
});
Seems to work in all major browsers...
A very slightly different approach would be to separate the focus event from the mouse sequence. This works really nicely for me - no state variables, no leaked handlers, no inadvertent removal of handlers, and it works with click, tab, or programmatic focus. Code and jsFiddle below -
$('#out').focus(function() {
$(this).select();
});
$('#out').on('mousedown.selectOnFocus', function() {
if (!($(this).is(':focus'))) {
$(this).focus();
$(this).one('mouseup.selectOnFocus', function(up) {
up.preventDefault();
});
}
});
https://jsfiddle.net/tpankake/eob9eb26/27/
Make a bool. Set it to true after a focus event and reset it after a mouse up event. During the mouse up, if it's true, you know the user just selected the text field; therefore you know you must prevent the mouse up from happening. Otherwise, you must let it pass.
var textFieldGotFocus = false;
$('#out').focus(function()
{
$('#out').select();
textFieldGotFocus = true;
});
$('#out').mouseup(function(e)
{
if (textFieldGotFocus)
e.preventDefault();
});
$(document).mouseup(function() { textFieldGotFocus = false; });
It's important that you put the mouseup listener that resets the variable on document, since it's not guaranteed that the user will release the mouse button over the text field.
onclick="var self = this;setTimeout(function() {self.select();}, 0);"
Select the text before putting the focus on the input box.
$('#out').select().focus();
digitalfresh's solution is mostly there, but has a bug in that if you manually trigger .focus() using JS (so not using a click), or if you tab to the field, then you get an unwanted mouseup event bound - this causes the first click that should deselect the text to be ignored.
To solve:
var out = $('#out');
var mouseCurrentlyDown = false;
out.focus(function () {
out.select();
if (mouseCurrentlyDown) {
out.one('mouseup', function (e) {
e.preventDefault();
});
}
}).mousedown(function() {
mouseCurrentlyDown = true;
});
$('body').mouseup(function() {
mouseCurrentlyDown = false;
});
Note: The mouseup event should be on body and not the input as we want to account for the user mousedown-ing within the input, moving the mouse out of the input, and then mouseup-ing.
tpankake's answer converted to a reusable jQuery function..
(If you upvote this, please also upvote his answer)
Load the following AFTER loading the jQuery library:
$.fn.focusSelect = function () {
return this.each(function () {
var me = $(this);
me.focus(function () {
$(this).select();
});
me.on('mousedown.selectOnFocus', function () {
var me2 = $(this);
if (me2.is(':focus') === false) {
me2.focus();
me2.one('mouseup.selectOnFocus', function (up) {
up.preventDefault();
});
}
});
});
};
Use it like this:
$(document).ready(function () {
// apply to all inputs on the page:
$('input[type=text]').focusSelect();
// apply only to one input
$('#out').focusSelect();
});

Categories