1

How can i reference an array item with the same index as the the array used in my for loop?

animations[i] current returns as undefined:

var icons = ["#know","#run","#think","#done","#measure","#plan","#resolve"]
var animations = [knowTl,runTl,thinkTl,doneTl,measureTL,planTl,resolveTl]

for(var i=0;i<icons.length;i++) {
$(icons[i]).hover(
  function() {
  animations[i].restart()
  },
  function() {}
 );
}
3
  • do you mean animations[i].restart() ?? Commented Mar 9, 2017 at 12:44
  • sorry, corrected Commented Mar 9, 2017 at 12:45
  • ahh okay i see.. you need to create closure in your bindings. like (function(){})() Commented Mar 9, 2017 at 12:47

3 Answers 3

1

do this

for(var i=0;i<icons.length;i++) {
(function(i){
  $(icons[i]).hover(
    function() {
      animations[i].restart()
    },
    function() {}
   );
})(i)
}
Sign up to request clarification or add additional context in comments.

9 Comments

This code will work, but theres plenty of ways to do it better.
Sorry man but Your answer provides no explanation why and how it works. If if suits the author than well... Not my code, not my problem.
@grzesiekgs This code will work, but theres plenty of ways to do it better you should add these solutions to your anwser?
i actually explained it to him at the comment section of his question. to create a closure. :)
@smarber I've explained exactly where he has made a mistake, and I've also provided the shortest answer which I've got in my mind at the time. What else do You need? :)
|
1

You misunderstood how JS scope works. Function which You are passing to hover, is executed when hover event occurs. But at the time when it happens, Your i variable has value of icons.length because Your for loop already stopped iterating.

What You need, is to get Your animation function reference, when hover event occurs.

Theres sample code written in ES6

const animationsSet = [{
  element: '#know',
  animation: knowTl
}, {
  element: '#run',
  animation: runTl
}]

animationsSet.forEach(({ element, animation }) =>
  $(element).hover(() => animation.restart())
)

Comments

1

You may avoid the closure.

In order to attach the hover event to all icons elements you can use:

$(icons.toString()).hover(

In this way you will avoid the for loop at all.

Now the problem: how get the index i?

This step can be solved looking for the index:

var i = icons.indexOf('#' + this.id);

As per comment reported by grzesiekgs you may add a new attribute to each element. So, the previous selector can be chained with:

.attr('idx', (idx, attr) => {return idx;})

And inside the handler you can use directly the new attribute.

And so the snippet:

var icons = ["#know", "#run", "#think", "#done", "#measure", "#plan", "#resolve"];
var animations = ['knowTl', 'runTl', 'thinkTl', 'doneTl', 'measureTL', 'planTl', 'resolveTl'];

$(icons.toString())
           .attr('idx', (idx, attr) => {return idx;})
           .hover(
           function () {
            var i = icons.indexOf('#' + this.id);
            
            var idxAttr = this.getAttribute('idx');

           
            console.log('IN (idxAttr =' + idxAttr + '): animations[' + i + ']=' + animations[i]);
            //animations[i].restart()
        },
        function () {
            // var i = icons.indexOf('#' + this.id);
            // console.log('OUT: animations[' + i + ']=' + animations[i]);
        }
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


<p id="know">know</p>
<p id="run">run</p>
<p id="think">think</p>
<p id="done">done</p>
<p id="measure">measure</p>
<p id="plan">plan</p>
<p id="resolve">resolve</p>

4 Comments

If You want to go this way, it would be way better to just add custom attribute on element, which will hold name of the function, and just hold the functions in one map, and access them by key. But I don't get whats the point of avoiding ONE closure, when You are using jQuery anyway.
@grzesiekgs Thanks for sharing. Yes, you are right. Adding an attribute is the best. Why avoid closure? First: the problem I see is how to use selectors in jQuery. The second is: a closure create a new context..... What's your idea?
Well modern JS compilers can handle creation of new closures quite well. Even with IE11 it's not so painful to create a closure. So IMO theres no point in avoiding it, especially when it makes Your code more readable. Write code for humans, not for machine. premature optimization is the root of all evil
@grzesiekgs Well answer. Thanks again for sharing. It's always a pleasure using this site for sharing ideas, even if my idea is different. See the updated answer. +1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.