0

I have few links in a page and I want to add a function to each link. I've done that with a loop.

Now, I got an array of objects. I want to pass objects values to function that I assigned to links. So I want to match links array with my object array.

html

<a href="#">link1</a>
<a href="#">link2</a>
<a href="#">link3</a>

js

var myArray = [
    obj1 = {property: "value1"},
    obj2 = {property: "value2"},
    obj3 = {property: "value3"}
];

var pageLinks = document.getElementsByTagName("a");

for (i = 0, len = pageLinks.length; i < len; i++){
    pageLinks[i].attachEvent("onclick", function(i){
        alert(myArray[i].property);
    }, false);
}

I tried doing this but I think I'm missing something. If I use array index instead of i in alert() it works fine. But there's no matching. I'm stuck with just one obj. How can I pass loop's i not just to page links but also to my function.

fiddle

EDIT: I guess I should have mentioned that I'm NEW to JS. I don't even know what closure means in JS. Same goes for bind... Instead of telling me what to do/use you could have just show me how to fix my current problem and link a demo maybe? Since I'm new to JS (don't know all these term) it's kinda hard to get the logic in someone else's code. Anyway. I have an answer now. Thanks.

akinuri
  • 10,690
  • 10
  • 65
  • 102
  • 2
    One more case of bitten by closure. – Jon Jun 25 '13 at 18:43
  • It's not the issue, but the `obj1 = ` bit is unneeded in creating your array. You are simply creating a global variable named `obj1` which does not seem to be your intent. – James Montagne Jun 25 '13 at 18:49
  • You realize that `.attachEvent()` is IE only, and the `, false` argument does nothing? –  Jun 25 '13 at 18:52
  • @CrazyTrain see EDIT. And I know. I'm using IE. HTA to be specific. That's not really an issue. – akinuri Jun 25 '13 at 19:15

2 Answers2

1

Updated Demo

Try adding a closure, to store the value of i for each iteration:

var myArray = [
    {property: "value1"},
    {property: "value2"},
    {property: "value3"}
];

var pageLinks = document.getElementsByTagName("a");

for (i = 0, len = pageLinks.length; i < len; i++){

    // This closure allows the value of "i" to be used
    // when the event handler is fired.
    (function(i){

        pageLinks[i].addEventListener("click", function(){
            alert(myArray[i].property);
        }, false);

    })(i);
}
Matt Coughlin
  • 18,666
  • 3
  • 46
  • 59
  • Still doesn't work. `Cannot access property "property" of undefined (myArray["[object Event]"])` :-) – Bergi Jun 25 '13 at 18:48
  • @Bergi: Do you still see any issues with this [updated demo](http://jsfiddle.net/Matt_Coughlin/TwSAN/1/)? It tested fine in Firefox and Chrome (from what I could tell). – Matt Coughlin Jun 25 '13 at 19:00
  • +1 to Matt for getting there first. Closures still own me. On another note, can I suggest using `for(var in pageLinks){ ... }` for cleaner code? Unless some teabag has a reason for bad practise? – shennan Jun 25 '13 at 19:10
  • @shennan: It is a bad practice on Arrays. Please learn the basics before engaging in preemptive name calling. –  Jun 25 '13 at 19:23
0

You can pass in the current index using bind

Like so:

for (i = 0, len = pageLinks.length; i < len; i++){
  pageLinks[i].addEventListener("click", function(ind){
    alert(myArray[ind].property);
  }.bind(this,i), false);
}

This issue is with scoping and closures.

Function.bind : Bind First argument is the scope for this all other arguments are passed in when the function is called in the order specified.

JasonM
  • 751
  • 6
  • 9