0

I start with one item in the stack ar.

What I intended the code to do is: If user clicks the correct link (the one computer has randomly selected), we proceed to the next "level" where we add one more element to the stack.

In the next level user has to select 2 correct links in the order in which they're in the stack. Once user does that, he should proceed to the next level and so on. It's similar to Simon says game and I am just trying to imitate the bare logic of the game with this.

HTML:

<a href="javascript:void(0);" id="l1">Link 1</a>
<a href="javascript:void(0);" id="l2">Link 2</a>
<a href="javascript:void(0);" id="l3">Link 3</a>
<a href="javascript:void(0);" id="l4">Link 4</a>
<div id="log"></div>

Javascript

function check() {
  var index = 0;
  $('body').click(function(event) {
    var log = $('#log');
    alert(index);

    if ($(event.target).is(ar[index])) {
      log.html(index + ' ' + event.target.id + ' was clicked.');
      index++;

      if (index === ar.length) {
        //if all clicked elements corresponded to correct 
        //order in array and reached end of array
        level +=1;
        console.log("Passing to next level. ", level);
        randomId();
        console.log(ar);
        log.html(ar);
        check();
      }
    } 
    else {
      log.html(index + ' ' + event.target.id + ' was clicked. Is wrong');  
      index = 0;
    }
  });
}

var ar = [];  
divIds = ["#l1", "#l2", "#l3", "#l4"];
level = 1;
randomId();
check();

function randomId() {
  var min = 0;
  var max = 3;
  var id = Math.floor(Math.random() * (max-min+1)) + min;
  var selectedId = divIds[id];

  ar.push(selectedId);
  alert(ar);
}

However when I am calling check() function a second time (when we move to level 2 where there are 2 elements in stack) the value of index is not 0 despite the fact that var index = 0 is the first line of the check() function.

I am using console.log and alert to capture the value of index but their sheer number is confusing me. And by looking at the number of alert pop-ups, my check function seems to be acting like a loop. Why aren't we getting a clean slate when we're calling the function a second time?

Daniel Beck
  • 20,653
  • 5
  • 38
  • 53
Joan
  • 3
  • 2
  • 3
    Every time you call `check()` you are adding an **additional** event handler to ``. The handlers from the previous `check()` call do not magically disappear. I.e. after having called `check()` twice, clicking `` will execute two event handlers. If that's the issue, remove existing event handlers before you bind the new one. – Felix Kling Jul 19 '16 at 13:35
  • Why attach the click handler over and over again? – Asons Jul 19 '16 at 13:41

2 Answers2

0

Updated - removed the index parameter as it wasn't needed

If I understood your code sample correct, you could do like this

  • add index and level as a parameter to the check function
  • pass a start value to the index/level when call the check() (self invoked)
  • replace remove the inner check() with index = 0;

This way, the check functions parameter, index and level, will work like a non global static variable, which is most likely what you need.

I also recommend an app object for your variables etc., rather than having global variables.

Side note: I couldn't get the actual code to work how it appeared it should work. After dropping the usage of the index and a few adjustments, it started to though. Is this how you intended it to work, or what's the purpose for the `index´ variable

var MyApp = {};
MyApp.ar = [];
MyApp.divIds = ["#l1", "#l2", "#l3", "#l4"];

(function check(level) {
  randomId();
  $('body').click(function(event) {
    var log = $('#log');
    if ($(event.target).is(MyApp.ar[level-1])) {
      log.html(event.target.id + ' was clicked.');
      if (level === MyApp.ar.length) {
        //if all clicked elements corresponded to correct 
        //order in array and reached end of array
        level++;
        console.log("Passing to next level. ", level);
        randomId();
        console.log(MyApp.ar);
      }
    } else {
      log.html(event.target.id + ' was clicked. Is wrong');
    }
  });
})(1);

function randomId() {
  MyApp.ar.push(MyApp.divIds[Math.floor(Math.random() * MyApp.divIds.length)]);  
  alert(MyApp.ar);
}
a {
  padding: 0 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="javascript:void(0);" id="l1">Link 1</a>
<a href="javascript:void(0);" id="l2">Link 2</a>
<a href="javascript:void(0);" id="l3">Link 3</a>
<a href="javascript:void(0);" id="l4">Link 4</a>
<div id="log"></div>
Asons
  • 84,923
  • 12
  • 110
  • 165
  • Yes, thank you, that is exactly what I wanted the code to do. I was calling check() again thinking it was doing a fresh start to the function, resetting the variables and everything. But as all of you have mentioned, it is re-attaching the event handler and messing things up. As a side note, will closures help me understand why there seemed to be multiple values of index in my code or was it just because of multiple event handlers? – Joan Jul 19 '16 at 17:02
  • @Joan What you mean when you say _will closures help you understand..._? – Asons Jul 19 '16 at 17:07
  • what I meant was that at my level (where I didn't realize I was attaching event handlers again and again and that was causing the erratic behavior) will trying to understand closures help me understand JS better or just confuse me even more (I've tried reading it before and didn't understand it all that well)? Closures keep coming up in javascript related forums and when I am trying to understand something that's not working I tend to think it's because of some of the advanced concepts I've heard about and don't understand. – Joan Jul 19 '16 at 18:56
  • @Joan Then I recommend to focus on learn JS basics, as without them, closures will be so much difficult to understand, if not impossible. I've been doing this a while and I still have a lot to learn :) – Asons Jul 19 '16 at 19:38
  • @Joan Still, have a look at this page, it might explain it in a simpler way than what your read before: https://developer.mozilla.org/en/docs/Web/JavaScript/Closures – Asons Jul 19 '16 at 19:40
-1

What you are running into here is called Closures. Basically, you are binding a function defined within the scope of another function to your click event. All the clicks refer to the same outer index of their scope and modify it.

Read more here

If after reading that you still are not able to understand what the issue is here, comment here and I will do my best to help, I just do not want to repeat what others have said.

Edit: As others have pointed you have another issue here, which is, you are binding the click event multiple times. You have to remove the previous bind (or even better) just change the values, do not bind multiple events.

$('body').click(function(event){})

This line of code is what makes your click work. You do not need to run check() multiple times because once you have "attached" the event handler once, you only need to check the values not rebind it over and over.

In other words, make your check() only run once, and place your index within the bound click function instead of outside if you want it to reset every time it is clicked. If you want it to reset only after certain amount of clicks you need to keep it outside of the function's closure like so:

function check(){
  index = 0;
  $('body').click(function(event){
    //NO INDEX HERE
  })
}

But in this case (which is what you have now) you need to manually reset it under some condition, from within the function which you bound to your click. For example if(ar > neededNumber){index =0;}

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Dellirium
  • 1,362
  • 16
  • 30
  • 1
    It's actually worse than that since *new* click handlers are being created on each call to `check()` and each has its own enclosed `index`. – Dave Newton Jul 19 '16 at 13:41
  • But he does run check() only once and after that it is the clicks that are being ran. If he was to do a check() every time his value would reset, though, he'd end up with multiple functions bound, which does make it worse, but he only calls check() once, judging by his code. It is a fair point though. – Dellirium Jul 19 '16 at 13:44
  • No, he run the check over and over ... take a good look and you'll find it – Asons Jul 19 '16 at 13:46
  • Oh god, I didn't even notice that part of the code running it again, either way, these are 2 separate issues, both need fixing. – Dellirium Jul 19 '16 at 13:48
  • (I know you already saw it, but in addition to the code reading, the question explicitly states it's called again: "However when I am calling check() function a second time [...]") – Dave Newton Jul 19 '16 at 15:07
  • I saw the second call at a later point, missed it on the initial look. I thought he misinterpreted the binded function as the check. Edited the answer to reflect it as per suggestions. – Dellirium Jul 19 '16 at 15:11