Jake
Jake

Reputation: 4374

Dynamic listeners based on array

I'm playing with mobile app creation with jQuery and an api I built using Slim.

My overall goal is to create a list of buttons that when clicked will call a function with the appropriate parameters.

I am successfully sending my request to slim, getting a list of users and storing the results in a global array of User objects.

Next I am iterating through the array appending html to the document to show the buttons. At the same time I am adding a click listener. The listener gets added, but not like I expect.

Users is an array of user objects with global scope. A user object can be boiled down to [{"name":"User's name"}].

Also relevant might be the fact that I'm doing this in a call back.

$.getJSON(url, function(data){
    for(i=0;i<data.length;i++)
    {
         var u = new User();
         u.name = data[i]['name'];
    }
})
//The success handler DOES get called.
.success(function() {
    for(var i=0; i<users.length; i++)
    {
        //this part works.  users[i] is accessed as expected.
        var html_string = '<li>'+users[i].name+'</li>';

        $("#myUL").append(html_string);
        $("#myUL li:last").click(function(){
            //logs undefined
            console.log(users[i].name);

            //Handle the event
            eventHandleFunction()
        });
    }
})

I'm well enough versed in programming in general to know that what I'm doing does not fall into best practices, but I am so illiterate in javascript that I don't know the right way to fix it. In addition to the howto answer I'd really appreciate anyone who took some time to point me to useful resources.

Update: After reading an answer about using delegate to assign handlers I have updated my code a bit. Now it looks like this. Note: I've only not updated the code above in order to get an answer to the 'why' part of the original question.

$("#myUL").delegate("li","click",function(){
            //sets the attribute name of the global var user
    user.name = $(this).text();
            //lets see what user.name is now.  Oh, look.  It's what i expect
    alert(user.name);
    //do whatever else i want to do here.
});

//This json request is now (i believe) entirely unnecessary to answer the question.
$.getJSON(url, function(data){
    for(i=0;i<data.length;i++)
    {
         var u = new User();
         u.name = data[i]['name'];
    }
})
//The success handler DOES get called.
.success(function() {
   //No longer relevant
})

Upvotes: 0

Views: 284

Answers (2)

adeneo
adeneo

Reputation: 318302

for(var i=0; i<users.length; i++) {
    var numb = i,
        html_string = '<li>'+users[numb].name+'</li>';

    $("#myUL").append(html_string);

    $("#myUL li:last").click(function(){
        console.log(users[numb].name);

        eventHandleFunction()
    });
}

Upvotes: 0

Rafay
Rafay

Reputation: 31043

you can use delegate

$("#myUL").delegate("li:last","click",function(){

//event handler code here
});

this way you dont have to explicitly attach click event handler to every dynamically added li in the DOM

if you are using jquery version 1.7+ then you can use .on method like

$("#myUL").on("click","li:last",function(){

//event handler code here
});

the why part

the reason i see is the scope

 for(var i=0; i<users.length; i++)
    {     

        var html_string = '<li>'+users[i].name+'</li>';

        $("#myUL").append(html_string);

        $("#myUL li:last").click(function(){
            //logs undefined BECAUSE i is undefined inside the click handler
            console.log(users[i].name);
            //Handle the event
            eventHandleFunction()
        });
    }

Upvotes: 1

Related Questions