Trigger jQuery mousemove event only once - javascript

I'm trying to make an exit popup and I could do that using the following code.
Whenever the user's mouse move out of the browser area, this gives a popup. But it is quite annoying when the popup comes everytime. I want to limit it to just a single time.
Can somebody help me with this?
jQuery(document).ready(function () {
jQuery(document).mousemove(function(e) {
jQuery('#exitpopup').css('left', (window.innerWidth/2 - jQuery('#exitpopup').width()/2));
jQuery('#exitpopup').css('top', (window.innerHeight/2 - jQuery('#exitpopup').height()/2));
if(e.pageY <= 5)
{
// Show the exit popup
jQuery('#exitpopup_bg').fadeIn();
jQuery('#exitpopup').fadeIn();
}
});
});

Use jQuery's one() function: http://api.jquery.com/one/
jQuery(document).ready(function () {
jQuery(document).one('mousemove', function(e) {
jQuery('#exitpopup').css('left', (window.innerWidth/2 - jQuery('#exitpopup').width()/2));
jQuery('#exitpopup').css('top', (window.innerHeight/2 - jQuery('#exitpopup').height()/2));
if(e.pageY <= 5)
{
// Show the exit popup
jQuery('#exitpopup_bg').fadeIn();
jQuery('#exitpopup').fadeIn();
}
});
});

Insert this:
e.stopPropagation();
just at the first list of the mousemouve function.
....
jQuery(document).mousemove(function(e) {
e.stopPropagation();
jQuery('#exitpopup').css('left', (window.innerWidth/2 - jQuery('#exitpopup').width()/2));
...

(function($) {
$(document).ready(function () {
var leftPage = false;
$(document).mousemove(function(e) {
if(e.pageY <= 5)
{
if (!leftPage) {
var exitPopup = $('#exitpopup');
exitPopup.css('left', (window.innerWidth/2 - exitPopup.width()/2));
exitPopup.css('top', (window.innerHeight/2 - exitPopup.height()/2));
$('#exitpopup_bg').fadeIn();
exitPopup.fadeIn();
}
leftPage = true;
} else {
leftPage = false;
}
});
});
})(jQuery);
"If the user leaves the page AND they have not already left THEN set popup. Next mark that they have left the page (leftPage = true)"
"Do not try and set the popup again until they are back in the page"
Couple of extras:
Instead of calling jQuery all the time we wrap the whole thing in a function wrapper so you can use $.
Instead of doing this everytime $('#exitpopup'); we CACHE it to a variable exitPopup so it doesn't have to do the lookup every time (inefficient)

A few things here. First, for form's sake, you should move your CSS alterations inside the if block, because you really don't need those to run every time the user moves their mouse, just right before you show the popup:
if(e.pageY <= 5)
{
// Alter CSS as appropriate
jQuery('#exitpopup').css('left', (window.innerWidth/2 - jQuery('#exitpopup').width()/2));
jQuery('#exitpopup').css('top', (window.innerHeight/2 - jQuery('#exitpopup').height()/2));
// Show the exit popup
jQuery('#exitpopup_bg').fadeIn();
jQuery('#exitpopup').fadeIn();
}
Second, you'll probably want to avoid showing it a second time by detaching the event handler. I'd recommend you use the jQuery .on() and .off() syntax instead of the shorthand .mousemove() because it'll be easier to read and maintain. I also recommend you use namespaces on your events so you can ensure that you're not detaching events that might have been set in other scripts.
jQuery(document).on('mousemove.yourNamespace', function (e) {
if(e.pageY <= 5)
{
// Alter CSS as appropriate
jQuery('#exitpopup').css('left', (window.innerWidth/2 - jQuery('#exitpopup').width()/2));
jQuery('#exitpopup').css('top', (window.innerHeight/2 - jQuery('#exitpopup').height()/2));
// Show the exit popup
jQuery('#exitpopup_bg').fadeIn();
jQuery('#exitpopup').fadeIn();
// now detach the event handler so it won't fire again
jQuery(document).off('mousemove.yourNamespace');
}
}
Lastly, if you wrap all of this code in an IIFE, you won't have to write out jQuery every time, and you still won't have to worry about possible conflicts with $ in the global namespace.
(function ($) {
$(document).on('mousemove.yourNamespace', function (e) {
if(e.pageY <= 5)
{
// Alter CSS as appropriate
$('#exitpopup').css('left', (window.innerWidth/2 - $('#exitpopup').width()/2));
$('#exitpopup').css('top', (window.innerHeight/2 - $('#exitpopup').height()/2));
// Show the exit popup
$('#exitpopup_bg').fadeIn();
$('#exitpopup').fadeIn();
// now detach the event handler so it won't fire again
$(document).off('mousemove.yourNamespace');
}
}
})(jQuery);
jQuery docs for .on(), .off(), and event.namespace for reference.

Related

How to use jquery resize run funtion one time?

I want to use run 2 functions jquery when resize window. But I just want to do they one time. code can be like:
jQuery(document).ready(function () {
var screenwidth=jQuery(window).width();
if(screenwidth>991){
dofunction1();
}
else{
dofunction2();
}
});
I want when screenwidth>991 do dofunction1() 1 time, and when screenwidth<=991 do dofunction2() 1 time. Hope your help!!
You can use .one() to bind resize event
Attach a handler to an event for the elements. The handler is executed at most once per element per event type.
$(window).one('resize', function () {
var screenwidth = jQuery(window).width();
if (screenwidth > 991) {
dofunction1();
} else {
dofunction2();
}
});

Execute javascript only above certain width with resize

I'm currently developing a website which has a sticky menu function. I've got the normal javascript to work good, which adds some classes once the client scrolls past 150px.
I now face the problem that I don't want the classes to be added once people view the website below 725px, so I added a rule that it only executes the script above 725px but the problem is this:
If I resize the window back to full the function won't work anymore, so I created another rule with the javascript resize function but I can't get it to work..
Here is my script:
$(document).ready(function(){
var mainbottom = 150;
if($(window).innerWidth() > 725) {
$(window).on('scroll',function(){
stop = Math.round($(window).scrollTop());
if (stop > mainbottom) {
$('.header').addClass('sticky-nav');
$('.logo').addClass('sticky-logo');
$('.navigation').addClass('sticky-menu');
} else {
$('.header').removeClass('sticky-nav');
$('.logo').removeClass('sticky-logo');
$('.navigation').removeClass('sticky-menu');
}
});
}
});
$(window).resize(function() {
var mainbottom = 150;
if($(window).innerWidth() > 725) {
$(window).on('scroll',function(){
stop = Math.round($(window).scrollTop());
if (stop > mainbottom) {
$('.header').addClass('sticky-nav');
$('.logo').addClass('sticky-logo');
$('.navigation').addClass('sticky-menu');
} else {
$('.header').removeClass('sticky-nav');
$('.logo').removeClass('sticky-logo');
$('.navigation').removeClass('sticky-menu');
}
});
}
});
I'll hope somebody can help me with this problem.
First off, you should keep your code DRY. So preferably never copy paste any code around, bacause you will have to edit all the copies when you have to alter the behaviour or fix bugs.
You have not but your second $(window).resize() handler in the onready handler, so maybe that is why it is not triggered.
This should work:
$(document).ready(function(){
var mainbottom = 150;
function onScroll () {
stop = Math.round($(window).scrollTop());
if (stop > mainbottom) {
$('.header').addClass('sticky-nav');
$('.logo').addClass('sticky-logo');
$('.navigation').addClass('sticky-menu');
} else {
$('.header').removeClass('sticky-nav');
$('.logo').removeClass('sticky-logo');
$('.navigation').removeClass('sticky-menu');
}
}
var widthExceeded = false;
$(window).resize(function() {
$(window).innerWidth() > 725) {
if (!widthExceeded) {
$(window).on('scroll', onScroll);
}
widthExceeded = true;
} else {
if (widthExceeded) {
$(window).off('scroll', onScroll);
}
widthExceeded = false;
}
}).resize();
});
You are defining a scroll event listener inside a resize event listener, so basically you're declaring the scroll listener on every resive event (so the scroll listener is defined many many times if the user resize its browser). You need to correct this.
You could declare a flag (boolean) to indicate wether the viewport is below 725px or not. It should be initialized on $(document).ready(...) by testing the viewport dimensions.
Create a resize event listener which updates this flag by testing the viewport width, so you always know if you need to manage your classes or not.
At this point, console.log(your_flag) in your resize event listener to check if it works fine.
Then declare a scroll event listener, and in this listener the first thing you want to do is test the flag value. If viewport > 725, then manage the classes, otherwise do nothing.

How do I remove function added to clicked element, when I click outside of it?

I have a funcition that adds mousewheel horizontal scrolling to selected div.
I want to add this function to the element when I click on it, and remove it when I click outside of it. Not sure how to do it though, adding functionality works fine, but I can't figure out how to remove this function if I click outside the div (so even if mouse is within the div, horizontal scrolling won't take place).
Here's my jquery:
$mainDiv.on('click', function() {
$(this).find($scrollableContainer).horizontal();
});
Function responsive for horizontal scroll (mousewheel plugin):
$.fn.horizontal = function() {
$(this).mousewheel(function(e, delta) {
this.scrollLeft -= (delta * 40);
e.preventDefault();
});
};
In other words, what I'm trying to achieve is: if user clicks on $mainDiv - add horizontal() function to $scrollableContainer, but if user then clicks outside $mainDiv, remove horizontal() function from $scrollableContainer. I did try clicking on the body but that didn't work:
$('body').on('click', function() {
$(this).find($scrollableContainer).off();
});
Anyone can help please?
First modify the plugin
$.fn.horizontal = function(didgeridoo) {
this[didgeridoo]('mousewheel', fn);
function fn(e, delta) {
this.scrollLeft -= (delta * 40);
e.preventDefault();
}
};
then to activate
$mainDiv.on('click', function() {
$(this).find($scrollableContainer).horizontal('on');
});
and deactivate
$(document).on('click', function() {
$(this).find($scrollableContainer).horizontal('off');
});
It is rather strange to use a variable in find, unless that variable holds a selector as a string ?
Note that there is no delta as a second argument, and that the mousewheel event is non-standard, and according to MDN shouldn't be used? Are you using another plugin to provide non-standard functionality ?
There are however deltaX and deltaY properties of the event in Chrome and IE, they can be accessed like this
function fn(e) {
e.preventDefault();
var delta = e.originalEvent.deltaX;
this.scrollLeft -= (delta * 40);
}
And MDN has a polyfill that should work cross-browser.

javascript / jquery - avoid repeating evaluation of a conditional

I currently have a conditional running in jquery's scroll event, which doesn't seem to make a lot of sense since it will only execute once. I was wondering if there is any way to ensure that the conditional will only be evaluated once.
here's my code:
$window.scroll(function() {
if (s1_doAnimate == true){
s1_doAnimate = false;
}
})
Use $.one
$(window).one('scroll', function(){
...
});
You can unbind the handler once the condition has been met;
$window.scroll(function foo /* give the function a name */ () {
if (s1_doAnimate == true){
s1_doAnimate = false;
// Unbind the handler referenced by the name...
$window.off(foo);
}
})

Differentiate between focus event triggered by keyboard/mouse

I'm using jquery ui autocomplete and want to decipher between focus events triggered by keyboard interaction and mouse interaction. How would I go about this?
$('input').autocomplete({
source: function(request, response) {
...
},
focus: function(event, ui) {
// If focus triggered by keyboard interaction
alert('do something');
// If focus event triggered by mouse interaction
alert('do something else');
}
});
Thanks
The only way I can think of doing this is to have a handler listen in on the keypress and click events, and toggle a boolean flag on/off. Then on the focus handler of your input, you can just check what the value of your flag is, and go from there.
Probably something like
var isClick;
$(document).bind('click', function() { isClick = true; })
.bind('keypress', function() { isClick = false; })
;
var focusHandler = function () {
if (isClick) {
// clicky!
} else {
// tabby!
}
}
$('input').focus(function() {
// we set a small timeout to let the click / keypress event to trigger
// and update our boolean
setTimeout(focusHandler,100);
});
Whipped up a small working prototype on jsFiddle (don't you just love this site?). Check it out if you want.
Of course, this is all running off a focus event on an <input>, but the focus handler on the autocomplete works in the same way.
The setTimeout will introduce a bit of lag, but at 100ms, it might be negligible, based on your needs.
You should actually be able to determine this from the event-Object that is passed into the focus-event. Depending on your code structure this might be different, but there is usually a property called originalEvent in there, which might be nested to some depth. Examine the event-object more closely to determine the correct syntax. Then test on mousenter or keydown via regular expression. Something like this:
focus: function(event, ui){
if(/^key/.test(event.originalEvent.originalEvent.type)){
//code for keydown
}else{
//code for mouseenter and any other event
}
}
The easiest and most elegant way I've found of achieving this is to use the "What Input?" library. It's tiny (~2K minified), and gives you access to the event type both in scripts:
if (whatInput.ask() === 'mouse') {
// do something
}
...and also (via a single data attribute that it adds to the document body) styles:
[data-whatinput="mouse"] :focus,
[data-whatinput="touch"] :focus {
// focus styles for mouse and touch only
}
I particularly like the fact that where you just want a different visual behaviour for mouse / keyboard it makes it possible to do that in the stylesheet (where it really belongs) rather than via some hacky bit of event-checking Javascript (though of course if you do need to do something that's not just purely visual, the former approach lets you handle it in Javascript instead).
The first thing that comes to mind is that you can find the position of the mouse and check to see if its within the position of the element
Use this to store the position of the element:
var input = $('#your_autocompleted_element_id'),
offset = input.offset(),
input_x = offset.top,
input_y = offset.left,
input_w = input.outerWidth(),
input_h = input.outerHeight();
Then use this to find absolute position of the mouse within the window:
var cur_mx, cur_my;
$(document).mousemove(function(e){
cur_mx = e.pageX;
cur_my = e.pageY;
});
Then in your autcomplete setup:
focus: function(event, ui) {
// mouse is doing the focus when...
// mouse x is greater than input x and less than input x + input width
// and y is greater than input y and less than input y + input height
if (cur_mx >= input_x && cur_mx <= input_x + input_w && cur_my >= input_y && cur_my <= input_y + input_h) {
// do your silly mouse focus witchcraft here
} else {
// keyboard time!
}
}
This can be handled using mousedown event, see my example below.
this.focusFrom = 'keyboard' =>
onFocus = () => {
if (this.focusFrom === 'keyboard') {
// do something when focus from keyboard
}
}
handleMouseDown = () => {
this.focusFrom = 'mouse';
}
handleOnClick = () => {
this.focusFrom = 'keyboard';
}

Categories

Resources