4

Possible Duplicate:
Event handlers inside a Javascript loop - need a closure?

I am getting some json object through an API call.It is of the folowing format:-

{data:[{id:"1",name:"some1",url:"someurl1"},{id:"2",name:"some2",url:"someurl2"}...]}

I get it through a jsonp result and it is parsed as below:-

function(results){
   for(var i=0;i<10;i++){
    item=document.createElement("div");
    item.innerHTML=results.data[i].name;
    item.onclick=function(){
        console.log(results.data[i]);  //--->this is where i am stuck 
      }
    }
 }

How do i pass the particular object from the loop to the onclick event. I mean the first div created should have an onclick event with the data of the first object and the second div should have the data from the second object.. Please ask me if any more clarification is required

Edit:- If I do something like this:-

item.onclick=function(){
  console.log(results.data[1])
}

I get that particular object in the onclick event of all the items , but that is not what i want

Edit:- This is how i finally solved it. Thanks to the link pointed to by DCoder.

item.onclick =function(object){
           return function(){
           //do something with the object
           }

         }(obj);
Community
  • 1
  • 1
noname
  • 177
  • 1
  • 3
  • 12

6 Answers6

2

You could always jQuery's data function to store and retrieve the data object:

function(results){
  for(var i=0;i<10;i++){
    item=document.createElement("div");
    item.innerHTML=results.data[i].name;

    // Store object in data 
    $(item).data("results", results.data[i]);

    item.onclick=function(){
        // Retrieve the data needed
        var data = $(this).data("results");
        console.log(data);
      }
    }
 }
Craig MacGregor
  • 4,589
  • 1
  • 21
  • 13
2

Quick solution:

function(results){
    for(var i=0;i<10;i++){
        (function(index){ // create a closure, this makes a new scope
            item=document.createElement("div");
            item.innerHTML=results.data[index].name;
            item.onclick=function(){
                console.log(results.data[index]);  //--->this is where i am stuck 
            }
        })(i);  // pass in i
    }
}
Shmiddty
  • 13,847
  • 1
  • 35
  • 52
0

The onclick event is fired from jquery when someone clicks on 'item'. You cannot expect custom data to the event handler unless it is triggered using trigger function.

Sujith Kp
  • 1,075
  • 3
  • 14
  • 27
0

You're running into trouble with doing async calls inside of js. This is a common problem and it's describe here: http://dojo-toolkit.33424.n3.nabble.com/Advice-on-closures-and-retaining-variable-values-inside-async-handlers-e-g-xhrGet-td3227726.html

Basically the value of i is equal to 9 by the time your console.log is actually ran.

There are many ways to solve this problem in general, but your specific solution should probably be to restructure things immensely. Consider this alternative (requires jQuery), but we could do the same without it very easily.

$.each(results, function(data) {
  var $el = $("<div></div>").html(data.name).click(function() { console.log(data) });
})

But it would be even better to use jQuery.data() to store things and then use .on() or .delegate() to listen for the click events like this

$.each(results, function(data) {
  var $el = $("<div></div>").addClass("yourThing").html(data.name).data("data", data);
})

// replace window with a closer parent if one exists
$(window).on("click", ".yourThing", function() {
   console.log($(this).data("data")); // retrieve data from jquerys .data() store
});
Jamund Ferguson
  • 16,721
  • 3
  • 42
  • 50
0

Add a hidden field inside your div (created in loop), keep whatever you want in it. then on click of div. find hidden field inside it(div) and read its value.

Sujith Kp
  • 1,075
  • 3
  • 14
  • 27
0

I'd personally use $.map so the function callback creates a new execution context for each iteration.

As you've tagged the question with jQuery, your code can be as simple as

$($.map(data, function(v, i) {
    return $('<div>').html(data[i].name).click(function() {
        console.log(data[i]);
    });
})).appendTo('body'); //appending for demonstration purposes

Fiddle

Of course, you have to wrap it inside a function and pass the data array of objects as you were doing previously.

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166