0

i write some function, and i called abApi.general.getUserById function, but when i print output to $("#friend-requests-block") my name variable is empty. i know this is javascript and i try with $("#friend-requests-block") in getUserById callback, but then i haven't type. How can i fix this?

                for (var index in requests) {

                        var name = "";
                        var type = "";

                        if(requests[index].FriendRequestTypeId == 1) {
                            type = "private";
                        }
                        else {
                            type = "business";  
                        }

                        abApi.general.getUserById(abEnvironment.sessionToken, requests[index].FromUserId, function(response2){
                            name = response2.Name;  
                        });

                        $("#friend-requests-blocks").html($("#friend-requests-blocks").html() + "<div class=\"log-block\" id=\"friend-requests-log-"+requests[index].Id+"\"><a href=\"#\"><h2>"+ name + "("+ type +")</h2></a> <div class=\"friend-requests-buttons\" style=\"margin-top: 15px;\"> <a href=\"javascript:void(0)\" data-role=\"button\" style=\"margin: 0px 5px 0px 5px;\" onClick=\"abAction.approveFriendRequest("+requests[index].Id+", 1,"+requests[index].FromUserId+");\">Accept</a><a href=\"javascript:void(0)\"data-role=\"button\" style=\"margin: 0px 5px 0px 5px;\" onClick=\"abAction.approveFriendRequest("+requests[index].Id+", 0,"+requests[index].FromUserId+");\">Reject</a> <a class=\"button3\" href=\"javascript:void(0)\"data-role=\"button\" style=\"margin: 0px 5px 0px 5px;\" onClick=\"abAction.approveFriendRequest("+requests[index].Id+", 2,"+requests[index].FromUserId+");\">Later</a></div></div>");    

                }   
6
  • getUserById probably uses AJAX. name is set, but after your other code has finished running. Move your $('#friend-request-blocks') chunk into the same callback function as name is in and it should work.
    – Blender
    Commented Oct 5, 2012 at 7:16
  • In order to help you'll have to give more background information. What is abApi? Have you tried to inspect the response2 variable, does it contain any data? You can try to log it or create a breakpoint at that line. Commented Oct 5, 2012 at 7:18
  • i'm not using ajax. abApi is my "class" where i have some functions. response2.Name give me name because i log it and it's not empty. Commented Oct 5, 2012 at 7:23
  • @Blender: the type var will be reassigned, too, and he uses it to set the html in $('#friend-request-blocks'). That's another issue that the OP needs to take into account Commented Oct 5, 2012 at 7:27
  • @TomaszSzulc: You say you're not using ajax, but where does the response2 come from? what does getUserById do? I'd say it either executes a query or requests data from the server-side in some way. In either case: the function that takes response2 as an argument is async Commented Oct 5, 2012 at 7:29

1 Answer 1

1

It's not just a scope issue you're dealing with, but the fact that getUserById is async, too (even more than the scope). the variable name won't be set until your script receives a response. Having said that, since you're using a loop, moving the $('#friend-request-blocks').html() bit to the success callback won't cut it: the variables name and type will be reassigned on every loop iteration. To get around this, you'll have to use a closure:

abApi.general.getUserById(abEnvironment.sessionToken,requests[index].FromUserId,
(function(type)
{//pass the current type as an argument to closure
    return function(response2)
    {
        var name = response2.Name;//declare local variable name, or use response2.Name
        $('#friend-request-blocks').html('html goes here with correct type: '+type+' and name: '+name);
    };
}(type)));

Also, I get the impression you're looping through an array, not an object, though I could be wrong. If requests is an array, it's best not to use a for...in loop, but a regular for(var i;i<requests.length;i++) loop. Google will give you a huge list of reasons as to why for...in on arrays isn't the best of ideas.

5
  • ok thank you i'll check it later. i haven't time so i did it on "rigid". Commented Oct 5, 2012 at 7:30
  • it's working perfectly, but i don't know what is (type) after function. Could you explain this? Commented Oct 5, 2012 at 8:01
  • type is a variable that you reassign in the loop. Because you set the html in an async function, type might (probably will) have changed between the time the request was sent and the callback being executed. The solution is an IIFE: a function has its own scope, so you wrap your callback in a function that takes type as an argument, and call it immediately, passing the current value of type to it, hence (function(type){<-- type is argument name}(type))<-- current value of type passed as argument. this function returns another function that accesses to the arguments of its parent Commented Oct 5, 2012 at 8:17
  • In this case, when the returned function references the variable type it references the argument that was passed to its parent IIFE (Immediately Invoked Function Expression), not the variable that keeps changing in the loop. The result is that each callback function has its own type value, that value is equal to the value type had when it was passed to that particular callback function. Perhaps this is a better explanation Commented Oct 5, 2012 at 8:20
  • 1
    @TomaszSzulc: forget the previous link, it's tedious: here's a nice explanation complete with diagrams that clarify a lot. this link, perhaps this could prove worth something. At first glance this and this pretty dry contain some useful info Commented Oct 5, 2012 at 8:27

Not the answer you're looking for? Browse other questions tagged or ask your own question.