-4

I tried to iterate over an array using a for-loop. In the loop there is a ajax call which is asynchronous. I need it to use the current value of the for loop iteration and not the changed value when the ajax call is finally retrieved. I searched for a solution and stumbled upon closure with a function. Oddly, it doesn't seem to work in this case. Anyone who can help? Thanks!

Edit:
The last key value of the iteration is used for the titles of every feed. So he fetches the correct feed (feeds[key]) but in the success part, he just pushes last_key + title for every feed. I don't get any errors, the ajax call works correctly.

for (var key in feeds) {
  (function(k) {
    console.log('function: ' + k); // gives the correct keys, e.g. first time 'Reddit', second time 'Tweakers'
    $.feedToJson({
      feed: feeds[k],
      success: function(data) {
        console.log('succes: ' + k); // always gives the last key, e.g. always 'Tweakers'
        for (var i in data.item) {
          var item = data.item[i];
          if (typeof item.title == 'object') {
            news.push(k + ': ' + item.title[0]);
          } else {
            news.push(k + ': ' + item.title);
          }
        }
      }
    });
  })(key);
}

var feeds = {
Reddit: 'https://www.reddit.com/r/leagueoflegends/.rss?sort=new',
Tweakers:'http://www.tweakers.com/feeds/nieuws.xml'

}

(function fetchNews() {
    news = [];
    for (var key in feeds) {
        (function (k) {
            console.log('function: ' + k); // gives the correct keys, e.g. first time 'Reddit', second time 'Tweakers'
            $.feedToJson({
            feed: feeds[k],
            success: function(data){
                        console.log('succes: ' + k); // always gives the last key, e.g. always 'Tweakers'
                        for (var i in data.item) {
                            var item = data.item[i];
                            if (typeof item.title == 'object') {
                                news.push(k + ': ' + item.title[0]);
                            } else {
                                news.push(k + ': ' + item.title);
                            }       
                        }
                    }
            });
        })(key);
    }

    setTimeout(function() {
        fetchNews();
    }, 60000);
})();

(function($) {

$.extend({
    feedToJson: function(options, callback) {
        if ($.isFunction(options)) {
          callback = options;
          options = null;
        }
        options = $.extend($.feedToJson.defaults,options);
        var url = options.yqlURL + options.yqlQS + "'" + encodeURIComponent(options.feed) + "'" + "&_nocache=" + options.cacheBuster;
        return $.getJSON(url, function(data){  
                //console.log(data.query.results);
                data = data.query.results;
                $.isFunction(callback) && callback(data); //allows the callback function to be the only option
                $.isFunction(options.success) && options.success(data);
            }); 
    }
});

})(jQuery);

Hans
  • 127
  • 1
  • 9
  • 1
    "it doesn't seem to work" Why? What outcome are you seeing? – JLRishe Nov 08 '15 at 16:11
  • Please provide more information. 'it doesn't seem to work in this case' - what do you get? an error? what's in 'feeds' array and resulting 'news' array? are the ajax calls done correctly? – shershen Nov 08 '15 at 16:12
  • The last key value of the iteration is used for the titles of every feed. So he fetches the correct feed (feeds[key]) but in the succes part, he just pushes last_key + title for every feed – Hans Nov 08 '15 at 16:13
  • 1
    It's very confusing to have a separate key variable both inside the function and outside. Try changing the one inside the function to k. I wouldn't expect that to make a difference, but at least that way you will be 100% sure that you are using the right variable. – JLRishe Nov 08 '15 at 16:17
  • But `console.log('succes: ' + key);` show the correct key in the console? If not then you maybe look at the wrong part of you code. – t.niese Nov 08 '15 at 16:20
  • Changed the parameter of the function to k and put some additional info about the console logs, see edit. – Hans Nov 08 '15 at 16:21
  • 1
    The code you posted won't result in the behavior you are observing. Something in your actual application must be different. – Felix Kling Nov 08 '15 at 16:23
  • 3
    Your report of what happens does not match how the code would actually work as you have shown it to us. So, I suspect that either something is wrong in your analysis of the problem or you aren't showing us enough of the real code and something is different in the actual code you are running than what you are showing us. – jfriend00 Nov 08 '15 at 16:23
  • I don't get it either... It should work but I can obviously check the logs and I print the news to my page. All feeds of reddit are marked 'Tweakers'. Here you can see all of the necessary code. – Hans Nov 08 '15 at 16:39

1 Answers1

0

You can create a simpler and more readable closure using $.each .

$.each(feeds, function (key, feed) {
    $.feedToJson({
        feed: feed,
        success: function (data) {
            console.log('succes: ' + key); // always gives the last key, e.g. always 'Tweakers'
            $.each(data.item, function (_, item) {
                if (typeof item.title == 'object') {
                    news.push(key + ': ' + item.title[0]);
                } else {
                    news.push(key + ': ' + item.title);
                }
            })
        }
    });    
});

Based on code shown your current closure however should be working fine

charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • Note that the solution to the "closure-loop" problem is *not* introducing another closure. It's creating scope. And yes, that's exactly what `$.each` gives you: scope per iteration. – Felix Kling Nov 08 '15 at 16:34