3

The variable value is not correctly set inside getJSON function. The variable $videoId displays 396 and 397 as expected in the first Alert.

But in the second alert, the value 397 is displayed twice.

Am I missing anything here? I could not find any other post here discussing this kind of issue. If so please point me over there.

Below is the jQuery code.

 $( "div .ow_video_list_item").each(function(){         
     $videoId = $(this).children("a").attr("href").split("/")[5];
     alert($videoId);    ==> First Alert

     $.getJSON("video/get-embed/" + $videoId + "/", function (data)   
     {                        
         $.each(data, function (key, code) {                                  
             alert($videoId);   ==> Second Alert
         });       
     });  

  });

Below is the HTML code:

<div class="ow_video_list_item ow_small">
    <a href="http://site.com/video/396">Video 1</a>
</div>

<div class="ow_video_list_item ow_small">
    <a href="http://site.com/video/397">Video 2</a>
</div>
Purus
  • 5,701
  • 9
  • 50
  • 89

4 Answers4

1

Assuming $videoLink is in fact $videoId as pointed out by comments :

It is because the getJSON method is asynchronous and you are dealing with javascript closures. When you execute the getJSON callback :

function (data)   
     {                        
         $.each(data, function (key, code) {                                  
             alert($videoId);   ==> Second Alert
         }); 

you have looped on your first each loop and the $videoId have taken the last value hence the display of 397 two times.

Have a look at how javascript closures work here : How do JavaScript closures work?

Community
  • 1
  • 1
benzonico
  • 10,635
  • 5
  • 42
  • 50
  • I really got confused learning about clousers. Seems to be complex to me.. Thanks for pointing me to this link. – Purus Feb 28 '13 at 14:25
1

When you do getJson method, you use async code. In that case, the last value you give to $videoID is 397 so on both callbacks that's the alerted value. There's a few ways to get through this. You could for example return the videoID value in the "data" retrieved from the getJson action and the use it alert(data.videoID). Or, instead of having a simple integer variable, you could have an array of values with appropriate keys. It Could, for example, be the index (the i in : $().each(function(i,e) {})). You need to find a way to make it work like that. I do think that data.id would be the easiest way of doing it! Hope it help.

Pete
  • 57,112
  • 28
  • 117
  • 166
Bene
  • 11
  • 1
1

The other comments about the asynchronous nature of getJson are right. But mostly, the problem is that you use a global variable $videoId. If you replace:

$videoId = $(this).children("a").attr("href").split("/")[5];

by

var $videoId = $(this).children("a").attr("href").split("/")[5];

You will be fine, even when using async methods.

Greg
  • 3,370
  • 3
  • 18
  • 20
1

A couple things.

  • In your code nowhere is $videoId defined, I'm assuming that $videoLink is really supposed to be $videoId. For future reference if might be easier to do something like these to access that data point

<a href="http://site.com/video/396" data-video-id="396">Video 1</a>

That way you can access that video id easily with $(element).data('videoId'). There are other strategies for this, like using classes.

  • If $videoLink is NOT supposed to be $videoId in your code sample, then $videoId is defined somewhere outside of the scope of that function. There are lots of resources out there about scope/closures in JS. If you are doing a decent amount of JS dev work I would suggest Javascript: The good parts.

  • Going back to assuming $videoLink is actually $videoId in your code sample. You are assigning it's value inside of that .each loop BUT that variable itself isn't "closed" inside of that function. It's either global, or defined somewhere else outside the scope of that each loop. throw a var in front of the $videoLink = statement to keep that var contained.

  • Another potential issue is that you are calling an async call to the server, but depending on a variable outside of the scope of that async call. Most of the time these calls will be milliseconds, but a good way to understand what is going on is to mentally step through the code and pretend that each server call will take 1 minute. In your example the outer loop runs through once, gets the id of 396 then fires off an AJAX request, then loops again and does the same thing for id 397. The server hasn't responded in the time it took for the 2nd ajax request to fire off. So you have 2 ajax requests hanging out now. A minute later they come back and oh look, your $variableLink variable has the value of 397 because it was defined outside of the ajax callback function. Solutions to this? There are a few. You can use some data you get back from the server for what you need or you can keep an array/hash of potential videos being accessed from the server.

There are other ways to do it, but without knowing the exact use-case of what you are trying to do beyond tracking that variable it's hard to say. But this should give you a good starting point for it.

Nathan Hess
  • 741
  • 1
  • 8
  • 18
  • Thanks for the detailed response. These really helped me to understand many things about jquery scope. – Purus Feb 28 '13 at 14:25