4

I am getting familiar with jQuery and making a little application where a red box moves around the screen and the user has to try and click on it and when the user does an alert() box pops up but the problem is that the alert() keeps popping up even after 'ok' is pressed. The only way I can stop it is to repeatedly click 'ok' and eventually it goes away.

Here is the code that displays the alert box:

function Animate() {
    var _newPosition = GetNewPosition();
    // Sets new position of div
    div.animate({
        top: _newPosition[0],
        left: _newPosition[1]
    }, function () {
        div.on('click', function () {
            alert('You clicked the box!');
        });
        Animate();
    });
}

Here is my JSFiddle that reproduces the problem

I originally thought that I could solve it by returning false after the call to the alert() for example:

div.on('click', function () {
    alert('You clicked the box!');
    return false;
});

But that didn't work either.

I know this should be a simple thing to figure out but I cant quite seem to get my thumb on it.

Tushar
  • 85,780
  • 21
  • 159
  • 179
AnonDCX
  • 2,501
  • 2
  • 17
  • 25

2 Answers2

6

The click handler is recursively called in the animation complete callback which is binding the click event on the element multiple times. So, when the element is clicked the handler is being called multiple times.

To solve the issue, bind the event only once.

function Animate() {
    var _newPosition = GetNewPosition();
    // Sets new position of div
    div.animate({
        top: _newPosition[0],
        left: _newPosition[1]
    }, Animate);
}

And in ready()

$(document).ready(function () {
    Animate();

    div.on('click', function() {
        // Code here
        alert('clicked');
    });
});

Using Animate as reference to the animation complete callback is same as

function() {
    Animate();
}

The function reference will be passed to the animate and it'll be called when the animation is completed.


Suggestions:

  1. Use mousedown event to track the click on moving object
  2. Use random duration for animate.

FIddle

var div = $('#box');
$(document).ready(function() {
  Animate();

  div.on('mousedown', function() {
    // Code here
    console.log('clicked');
  });
});

function GetNewPosition() {
  // Get dimentions of the window and remove the div area
  var h = $(window).height() - 50;
  var w = $(window).width() - 50;
  // New height and width is auto generated
  var nh = Math.floor(Math.random() * h);
  var nw = Math.floor(Math.random() * w);
  return [nh, nw];
}

function Animate() {
  var _newPosition = GetNewPosition();
  // Sets new position of div
  div.animate({
    top: _newPosition[0],
    left: _newPosition[1]
  }, (Math.floor(Math.random() * 5000) + 1), Animate);
}
#box {
  width: 50px;
  height: 50px;
  background-color: red;
  position: fixed;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3 id="success"></h3>
<div id="box"></div>
Tushar
  • 85,780
  • 21
  • 159
  • 179
  • Thanks Tushar, but what does Animate do instead of Animate()? – AnonDCX Nov 24 '15 at 04:12
  • I'd also suggest to use `mousedown`, a `click` is almost impossible on faster movements making the *game* unfair. Also to decrease the speed: `}, 5000, Animate);` or even [a random](http://stackoverflow.com/questions/4959975/generate-random-value-between-two-numbers-in-javascript) instead of 5000. – Roko C. Buljan Nov 24 '15 at 04:13
  • @DecompileCodex `Animate` is a callback reference, `Animate()` is an immediate execution. – Roko C. Buljan Nov 24 '15 at 04:15
  • Right thanks, I thought that $(document).ready(function(){...code...}) was only called once when the page was loaded and thats it – AnonDCX Nov 24 '15 at 04:29
  • @DecompileCodex and it is. But in your code, every time Animate ends (triggers again the callback Animate) > inside your re-called function you're again asserting another click event to the same element. – Roko C. Buljan Nov 24 '15 at 04:35
  • Ohk thanks, so is the callback (animate) like a delegate? – AnonDCX Nov 24 '15 at 04:36
  • I get it, every time the box is clicked, the page is reloaded hence why document.ready is loaded every time. Thanks guys :) – AnonDCX Nov 24 '15 at 04:38
  • @DecompileCodex The `ready` will be called only once when page is loaded and adding the code to bind click event in it means binding the event only once – Tushar Nov 24 '15 at 04:39
1

Event is getting bound multiple times as it is in animate function. Instead binding click event in animate bind it in $(document).ready(function () {}); so that it will only get bound once.

Please find updated jsfiddle

Suraj Ahirrao
  • 182
  • 10