0

I'm misunderstanding setInterval() and values that I expect to be around when it goes to execute are not, so it fails.

function setPairAnimations() {
    if (pairs.length > 0) {
        if (pairCount < pairs.length) {
                intervalNames.push(setInterval(function (pairCount) {
                    if (topMarker == true) {
                        pairs[pairCount].pMarker1.setZIndex(201);
                        pairs[pairCount].pMarker2.setZIndex(200);
                        topMarker = false;
                    }
                    else {
                        pairs[pairCount].pMarker1.setZIndex(200);
                        pairs[pairCount].pMarker2.setZIndex(201);
                        topMarker = true;
                    }
                }, 1000));
            ++pairCount;
            setPairAnimations();            
        }       
    }    
}
function swapMarkers() {
    //first, stop all existing running marker animations
    clearIntervals();

    if (pairs.length > 0) {
       setPairAnimations();
    }
    if (clusters.length > 0) {
        setClusterAnimations();
    }
}

The 6th line down bombs: "pairs[pairCount].pMarker1.setZIndex(201);" because pairs[pairCount] is undefined. pairs is a global array of literal objects, each object contains two properties or keys within it. Example.

pairs.push({ pMarker1: markerToggles[0].tMarker1, pMarker2: markerToggles[0].tMarker2 });

pairCount is a global count variable

Pairs is being populated correctly as I expect as per debugger. In this case, it's length is 1, so there should only be one animation started between two marker objects (in some cases it could be more marker sets that get animated, depending on how many were found in the pairs array).

I "believe" the problem is that by the time that setInterval function executes, the pairCount value is no longer what I expect (I assume outside of the bounds of the pairs array). In this call:

intervalNames.push(setInterval(function (pairCount) {

pairCount is undefined, and that's why the line I mentioned above fails. But I'm not sure what to do about it. Is it that I can't pass a global variable into the anonymous function call? I'm not a very experienced programmer, so I hope I explained this correctly and can give more code if needed, but I really think it's just a musunderstanding of how setInterval works in loops and I am simply misusing it. thx.

user192632
  • 266
  • 1
  • 17
  • This is confusing, why would you have to wait to push something to an array ? – adeneo Apr 29 '16 at 18:45
  • I don't see where I'm waiting to push something on the array, The pairs array gets set well before the code I displayed and it's populated correctly I am resetting the zindexes of two markers in the first position of the pairs array to make them toggle visiblity – user192632 Apr 29 '16 at 18:49
  • Oh, I see. All i am doing is to push the setinterval call on to an array so that the array can store it's handle if I need to stop all animations later. – user192632 Apr 29 '16 at 18:51
  • You wouldn't even hit your setInterval unless your array length was greater then your counter. Could you figure out what pairCount is before you encounter your issue? – Dresden Apr 29 '16 at 18:51
  • Yes, I realize you're pushing the reference to the interval, still seems weird – adeneo Apr 29 '16 at 18:52
  • It might be weird, this is a new problem for me. – user192632 Apr 29 '16 at 18:53
  • The error message is "Uncaught TypeError: Cannot read property 'pMarker1' of undefined" – user192632 Apr 29 '16 at 18:53
  • You're sure the issue isn't something related to the infamous loop issue, where you use `pairs[pairCount]` inside an async method, and update `pairCount` outside it? It's not really clear how and when this function is called, or where the variables are coming from ? – adeneo Apr 29 '16 at 18:54
  • 1
    http://stackoverflow.com/questions/457826/pass-parameters-in-setinterval-function – jonhopkins Apr 29 '16 at 18:54
  • I'll update code to show where function is called. thx – user192632 Apr 29 '16 at 18:55
  • And as noted above, why does the setInterval function have a `pairCount` argument, that overwrites the variable in the outer scope ? – adeneo Apr 29 '16 at 19:00
  • pairs is a global array of objects that each contain two marker objects. pairCount is a global variable used to walk through the loop in setPairAnimations() – user192632 Apr 29 '16 at 19:00
  • It's not a global anymore, it's overwritten by the local argument in the function with the same name – adeneo Apr 29 '16 at 19:01
  • it's supposed to keep track of which iteration of the pairs array it is dealing with. – user192632 Apr 29 '16 at 19:01
  • That could be true, and I pointed out in my explanation that using a global variable could be a problem when used as an arg for an anonymous function. I just don't know what to do about it. – user192632 Apr 29 '16 at 19:02
  • How do i tell it which set of markers to animate in setPairAnimations() if there are more than one object of object markers inside of pairs or more than one position on the pairs array? – user192632 Apr 29 '16 at 19:04
  • Just remove the argument in the `setInterval` callback, it shouldn't be there if you're trying to access the global – adeneo Apr 29 '16 at 19:05
  • I think you may have too much going on and there may be a simpler way to do it. I examined your code in my editor and noticed if (pairs.length > 0) { if (pairCount < pairs.length) { could be: if (pairs.length > 0 && pairCount < pairs.length) {. Being you know the length of your object array, could you somehow use it as a guide for the value of pairCount or could you omit it entirely and use the value of intervalNames.length instead? I would have to see the rest of the code to be certain. – iuppiter Apr 29 '16 at 20:50

1 Answers1

1

As you have noticed, pairCount is undefined within the function called by the interval. This is because you are creating a parameter, which never has a value passed into it by the interval, and it is shadowing the global pairCount. One way to get around this is to call the function yourself, using the global pairCount variable for the parameter. By passing the variable as a parameter, you can be sure that its value at the time the setPairAnimations() function is called is the value that will be used. If the value never changes, then you don't need a parameter at all.

intervalNames.push(setInterval(function() {
    // call the function, here pairCount is the global variable
    intervalAnimation(pairCount);
} , 1000));

// extracted from the setInterval into its own function
function intervalAnimation(pairCount) {
    if (topMarker == true) {
        pairs[pairCount].pMarker1.setZIndex(201);
        pairs[pairCount].pMarker2.setZIndex(200);
        topMarker = false;
    }
    else {
        pairs[pairCount].pMarker1.setZIndex(200);
        pairs[pairCount].pMarker2.setZIndex(201);
        topMarker = true;
    }
}

To loop through and make sure every pair in the list gets an animation, you don't have to do it recursively; you can use a loop, like so:

function setPairAnimations() {
    // don't need to check length, loop won't run if length is 0
    for (pairCount = 0; pairCount < pairs.length; pairCount++) {
        intervalNames.push(setInterval(function() {
            intervalAnimation(pairCount);
        }, 1000));
    }
}
jonhopkins
  • 3,844
  • 3
  • 27
  • 39
  • BINGO!!! could you just add pairCount++; right after the closing of the else so that I can mark it as accepted and everyone gets the most accurate answer? Thanks a bunch. – user192632 Apr 29 '16 at 19:11
  • Is that what you intended for it to do in your original code? Because in the question you have that outside of the setInterval. I was under the impression that you were calling `setPairAnimations` multiple times so that each pair gets its own animation – jonhopkins Apr 29 '16 at 19:13
  • pairCount needs to be incremented so that it will check all array positions of pairs array.There could be more than one setInterval call, if pairs has more than one set of markers or a length greater than 1 – user192632 Apr 29 '16 at 19:16
  • As it is now in your question, you have `if (pairs.length > 0) { if (pairCount < pairs.length) { setInterval(...); ++pairCount; setPairAnimations(); } }` `pairCount` is already being incremented, and the recursive calling to `setPairAnimations()` should already be handling calling `setInterval` again. – jonhopkins Apr 29 '16 at 19:18
  • Updated answer to show a way to get an animation interval for all the array positions – jonhopkins Apr 29 '16 at 19:28