0

So I'm creating the a FB app that uses the FB SDK. In the code below, I am getting a list of movies I like and their FB page ids in 'data'. Then, I'm iterating through it to get the get the names of the movies and using the page ids, i get their page links and src of their page profile pictures. Then I use the details to create the following HTML block:

<article>
<figure>
    <img src="source">
</figure>
<div>
    <a href="link"/>
</div>
</article>

So, I dynamically create each article block and then append them to the below HTML code:

<body>

 <header></header>

 <section>
     <article></article>
 </section>

 <footer></footer>

 <script src = *source of my .js file*></script>

</body>

This is my js code:

// data has a list of FB movie pages, each containing the name of the movie and page id
function print(data)
{
//iterates through the object passed to print movie names in console.  

var target = document.querySelector('article');
var docFrag = document.createDocumentFragment();
for (var i = 0; i < data.length; i++)
    {
        var temp = data[i];
        var linkElement = document.createElement('a');
        var linkText = document.createTextNode(temp["name"]);
        linkElement.appendChild(linkText);

        //getting the link to the movie's FB page
        getLink(function(response){linkElement.href = response;},temp["id"]);

        var imgElement = document.createElement('img');

        //getting the src of the picture of the movie's page
        getPic(function(response){imgElement.setAttribute("src", response);},temp["id"]);

        imgElement.setAttribute("width", "304");
        imgElement.setAttribute("height", "228");
        imgElement.setAttribute("alt", temp["name"]);

        var article = document.createElement("article"),
            figure = document.createElement("figure"),
            div = document.createElement("div");

        div.appendChild(linkElement);
        figure.appendChild(imgElement);
        article.appendChild(figure);
        article.appendChild(div);
        console.log(article);
        docFrag.appendChild(article);
    }
    target.appendChild(docFrag);
}

function getLink(callback,id)
{
   FB.api('/'+id+'?fields=link', function(response)
   {
       callback(response.link);
   });
}
function getPic(callback,id)
{
   FB.api('/'+id+'?fields=cover{source}', function(response)
       {
      callback(response.cover.source);
  });
}

My problem is that when I print the output, all the article blocks except the last one lose the href's and the src's for the 'img' blocks. When I print the articles in the console, the href and the src are empty except the last one. I think maybe it's got something to do with async calls to the FB SDK, but I'm not sure. Can anyone help?

1 Answers1

0

var has function scope, not block scope, and is hoisted. Use const or let instead, especially in for loops, especially in asynchronous for loops:

for (let i = 0; i < data.length; i++) {
  const temp = data[i];
  const linkElement = document.createElement('a');

To the interpreter, what you're currently doing looks something like this:

function print(data) {
var target;
var docFrag; 
var temp;
var linkElement;
// etc
for (i = 0; i < data.length; i++) {
  temp = data[i];
  linkElement = document.createElement('a');
  // etc

So after the end of the loop, once the responses come back, each callback is referencing the same imgElement, the last one the for loop reassigned.

You can also use forEach, which is significantly better than for loops in most respects. (no manual iteration, automatic abstraction, accepts functions as arguments)

data.forEach((temp) => {
  const linkElement = document.createElement('a');
  // ...
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320