onmouseover-triggered function keeps triggering on mouse over - javascript

I have a function, which is triggered when the mouse goes over a div.
The div contains a link, which is 100% height and width of the containing div. The link contains an image, which the function moves when onmouseover the grandparent (the div).
The function moves the image to the right and then back to the middle.
When I move the mouse over the div the function is triggered but moves the image by only 5px (one loop of the function) and keeps moving it 5px when I move the mouse around - the function is not looping and just loops once on every onmouseover.
<div onmouseover="jotArrow(this);" class="latest-entry latest-entry-third" id="news-link-home">
<a class="home-square-link" href="hello.php">Reviews<br/><img src="<?php echo $config['file_path']; ?>/images/squares-arrow.png" width="60px"/></a>
</div>
JS:
var arrowPos = 0;
var Arrow;
function jotArrow(arrow)
{
Arrow = arrow.getElementsByTagName('img')[0];
if (arrowPos < 50) {
arrowPos = arrowPos + 5;
Arrow.style.left = arrowPos + 'px';
setTimeout(jotArrow, 10);
} else {
jotArrowBack(arrow)
}
}
function jotArrowBack(arrow)
{
if (arrowPos > 0) {
arrowPos = arrowPos - 5;
Arrow.style.left = arrowPos + 'px';
setTimeout(jotArrowBack, 10);
}
}
To make sure the code is correct, I modified it a little (from that above) so that it makes an image in a different div move (onmouseover of div1 causes div2 image to move). And it worked fine.
So I am guessing it has something to do with the image being inside the div and the mouse goes over more than one element. But really I don't see why this would be an issue as the function does not care about onmouseout it should just perform it's whole task on the first onmouseover.
I have tried putting the onmouseover attribute on all three elements (the div, the a and the img) separately and all at the same time - same problem.

Your code appears to have two problems. As you mentioned, you get multiple mouseover events which confuse the code, but the other problem is that jotArrow fetches the Arrow element every time, and the second time it can't find it because your setTimeout call doesn't pass the parameter. When you switch the code to move another element I assume you just write something like document.getElementById('blah') which picks up the same element each time.
One approach would be to use a helper function initArrow, something like this:
function initArrow(arrow)
{
if (arrowPos == 0) {
Arrow = arrow.getElementsByTagName('img')[0];
jotArrow();
}
}

Related

Why my div shake after Javascript events are executed?

This is supposed to happen:
I mouseover my box, the box moves 50px to the right, and when I mouseleave the box, the box returns to its original position.
This happens:
The box moves to the right when mouseover, and moves to its original position when I mouseleave. But if I do this a few times, the box starts shaking. The more times I do it, the more it shakes.
How do I keep it from shaking after I mouseover/mouseleave several times?
I assume I need some sort of removeEventListener inside the functions, and addEventListeners, but I am farely new to this stuff.
const box1 = document.getElementById("divContainer");
let box1Left = parseInt(box1.style.marginLeft = 0 + "px");
function moveBox1Right() {
let id = null;
clearInterval(id);
id = setInterval(x, 5);
function x() {
if (box1Left == 50) {
clearInterval(id);
} else {
box1Left++;
box1.style.marginLeft = box1Left + "px";
}
}
}
box1.addEventListener("mouseover", moveBox1Right)
function moveBox1Left() {
let id = null;
clearInterval(id);
id = setInterval(y, 5);
function y() {
if (box1Left >= 1) {
box1Left--;
box1.style.marginLeft = box1Left + "px";
} else {
clearInterval(id);
}
}
}
box1.addEventListener("mouseleave", moveBox1Left);
#divContainer {
height: 100px;
width: 100px;
background-color: #c5c5c5;
}
<div id="divContainer">
</div>
If you mouse in/out during the "animation" both intervals can theoretically be active at the same time, causing the shake. The intervals are only cancelled when it reaches it's end condition, not when another interval is started, the mouse enters/leaves, or the direction is presumably intended to change.
You may want to share id between the two functions as your clearInterval(id) at the start of each function does nothing (id = null in the line before always means you're clearing null).
Better, you may want to consider using CSS animate which can solve this issue fairly elegantly.
Move the timeout reference (let id) outside the functions.
It is pointless to clear the id if you set it to null and you need to share it and use the reference when you clear it
let id;
function moveBox1Right() {
clearInterval(id);
...
function moveBox1Left() {
clearInterval(id);

How can I increase a CSS property's value repeatedly on click?

I want to add (in this case, decrease, technically) the value of an element each time a different element is clicked. What I have so far:
$("#trigger_heritage").click(function () {
$(".heritage_content ul").css("margin-left", + -880);
// So each time clicking shall move the .heritage_content ul-element 880px further left
});
It gets 880px far left, but only once. What I want is that this value gets increased each time the other element gets clicked.
How would I do that?
You can provide a string in the format -=[value] to the css() method which you can use to amend the current value. Try this:
$("#trigger_heritage").click(function () {
$(".heritage_content ul").css("margin-left", '-=880');
});
Working example
Here is a simple example:
$(document).ready(function() {
var move = 0;
$(".left").click(function () {
move -= 25;
$(".move").css("margin-left", move + "px");
});
$(".right").click(function () {
move += 25;
$(".move").css("margin-left", move + "px");
});
})
Fiddle: https://jsfiddle.net/gjfjahjo/
Set a variable, say $marginLeft, and increment this each time the function is called, then set the margin-left:$marginLeft....

Get divs within viewport inside a wrapper div

Is there a way to get elements which is:
Inside a div with overflow: scroll
Is in viewport
Just like the following picture, where active div (5,6,7,8,9) is orange, and the others is green (1-4 and >10) :
I just want the mousewheel event to add "active" class to div 5,6,7,8,9 (currently in viewport). View my JSFiddle
$('.wrapper').bind('mousewheel', function (e) {
//addClass 'active' here
});
You could do something like this. I would have re-factored it, but only to show the concept.
Firstly I would attach this to scroll event and not mousewheel. There are those among us that likes to use keyboard for scrolling, and you also have the case of dragging the scrollbar. ;) You also have the case of touch devices.
Note that with this I have set overflow:auto; on wrapper, thus no bottom scroll-bar.
With bottom scrollbar you would either have to live with it becoming tagged as in-view a tad to early, or tumble into the world of doing a cross-browser calculating of IE's clientHeight. But the code should hopefully be OK as a starter.
»»Fiddle««
function isView(wrp, elm)
{
var wrpH = $(wrp).height(),
elmH = $(elm).height(),
elmT = $(elm).offset().top;
return elmT >= 0 &&
elmT + elmH < wrpH;
}
$('.wrapper').bind('scroll', function (e) {
$('div.box').each(function(i, e) {
if (isView(".wrapper", this)) {
$(this).addClass('active');
} else {
$(this).removeClass('active');
}
});
});
Note that you should likely refactor in such a way that .wrapper height is only retrieved once per invocation, or if it is static, at page load etc.
Update; a modified version of isView(). Taking position of container into account. This time looking at dolphins in the pool.
»»Fiddle««
function isView(pool, dolphin) {
var poolT = pool.offset().top,
poolH = pool.height(),
dolpH = dolphin.height(),
dolpT = dolphin.offset().top - poolT;
return dolpT >= 0 && dolpT + dolpH <= poolH;
}

For Statement and Img Problem

I am using the following logic in a for statement
The problem I am having is that it seems that when you hover over the first image - it hides 'all the images'. I want to try and preserve the [i] for each image but it seems it doesn't do this ?
function myHandler(elem, img) {
var curImg = img;
var curImgId = curImg.find('img');
$(curImgId).live('click', function() {
$(this).hide();
});
//Other stuff requiring preservation of [i]
}
When you hover over the first image, that image hides. This is normal.
However, your problem is the second image moves into the space previously filled by the first image, and the second image gets a mouse event, which causes that image to hide. This happens continuously until the rest of the images all disappear.
You can test this by hovering over the second image - all the images to the right disappear.
EDIT: I would second #Digital Planes answer,
the second image comes in place of first one due to first one being hidden and triggers an event.
Here is a working code : http://jsfiddle.net/njPdQ/8/
The change is :
function myHandler(elem, img) {
console.log(elem);
var curImg = img;
var curImgId = curImg.find('img');
console.log(img);
$(curImgId).live('mouseenter', function() {
console.log("Event handler: Hiding " + elem);
// $(this).hide();
$(this).css("visibility", "hidden"); //this will keep the images in place
});
}

JavaScript/jQuery onmouseover problem

I want that when mouse is over an image, an event should be triggered ONCE, and it should be triggered again only after mouse is out of that image and back again, and also at least 2 seconds passed.
My current function is called continuously (refreshcash) if I leave the mouse over my image
<img src="images/reficon.png" onmouseover="refreshcash()" onmouseout="normalimg()" id="cashrefresh"/>
function refreshcash() {
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
}
function normalimg() {
$("#cashrefresh").attr("src","images/reficon.png");
}
code update
This code seems to have a bug,but the algorithm is kinda logical
<script type="text/javascript">
var canhover = 1;
var timeok = 1;
function redotimeok() {
timeok = 1;
}
//
function onmenter()
{
if (canhover == 1 && timeok == 1)
{
enter();
canhover = 0;
}
}
//
function onmleave()
{
leave();
canhover = 1;
setTimeout(redotimeok(), 2000);
leave();
}
//
$('#cashrefresh').hover(onmenter(),onmleave());
function enter(){
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
}
function leave(){
$("#cashrefresh").attr("src","images/reficon.png");
}
</script>
Try the hover:
$('#cashrefresh').hover(function(){
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
}, function(){
$("#cashrefresh").attr("src","images/reficon.png");
});
And your image should look like:
<img src="images/reficon.png" id="cashrefresh"/>
Update:
Modify your code like this:
var e = null;
var l = null;
$('#cashrefresh').hover(function(){
e = setTimeout(enter, 2000)
}, function(){
l = setTimeout(leave, 2000)
});
function enter(){
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
clearTimeout(e);
}
function leave(){
$("#cashrefresh").attr("src","images/reficon.png");
clearTimeout(l);
}
Do you have the images cached in some way? If you replace them by their src attribute without specifying width/height elsewhere (best would be CSS) or having them readily available then the hovered box (img element) will collapse into a smaller (or no) box until the image has been loaded far enough for the browser to know the correct dimensions of the image to resize the box (which may affect other elements being adjusted to the image). The exact effect depends on the browser but you may lose the hover state causing the call of your mouseout function.
I assume that both images are the same size, so if you didn't already, you could try adding the dimensions to your CSS for #cashrefresh and see if that fixes the problem.
For the delay I would recommend using the jQuery timers plugin (or a similar one) which eases handling of timers compared to doing it on your own. You would probably want to give your timers names and try to stop older ones before you add the next one.

Categories