0

I have an ajax function which loads thumbnails which is called by another ajax function and gets the parameter from there in the loop.

I have tried waiting for the ajax call to be finished by using .done and .ajaxComplete but the function still seems to fire while the ajax is still calling.

But it seems that the array is undefined until the last call is made by the Ajax.

Here is a codePen - https://codepen.io/anon/pen/oermYj

//POPULATE IFRAMES FUNCTION
var counter = 0,
mainTitle,
iframeLink,
slideIndex,
iframeID,
iframeCount,
iframeTotal,
iframeTitles,
iframeThumbnail;
var iframeTitleArray = [];

function getIframeInfo(uniqueID){
  $.ajax({
    url: 'http://query.yahooapis.com/v1/public/yql',
        data: {
            q: "select * from json where url ='https://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=" + uniqueID + "&format=json'",
            format: "json"
        },
        dataType: "jsonp",
    success: function (data) {
        iframeTitles = data.query.results.json.title;
    },
    error: function (result) {
        alert("Sorry no data found.");
    }
}).done(function pushTitles(){
  iframeTitleArray.push(iframeTitles);
});
}
console.log(iframeTitleArray);

function populateCars(carId){
  $.ajax({
    type : 'GET',
    url : 'json/data2.json',
    data : {
      get_param: 'value'
    },
    dataType : 'json',
    success : function(data){
      //DEFAULT DATA PLACEMENT
      $('.gallery-slider').empty();
      $('.gallery-sub-slider').empty();
      $('.grid-center-wrap').empty();

      //LOOP THROUGH JSON AND POPULATE
      $.each(data.iframeImages, function(i){
        iframeThumbnail = data.iframeImages[i].iframeThumb;
        iframeLink = data.iframeImages[i].iframeLink;
        iframeID = data.iframeImages[i].iframeID;
        iframeCount = i + 1;
        $('.gallery-slider').append('<iframe width="590" height="950" src="' + iframeLink + '" frameborder="0" allowfullscreen></iframe>');
        $('.grid-center-wrap').append('<div class="grid-block"><img class="grid-img" src="//img.youtube.com/vi/' + iframeThumbnail + '/0.jpg"><div class="grid-overlay" data-slick-index="' + i + '"></div><div class="grid-number">' + (iframeCount + ' / ' + data.iframeImages.length) + '</div></div>');
        $('.gallery-mobile-slider').append('<div><img src="//img.youtube.com/vi/' + iframeThumbnail + '/0.jpg" class="mobile-gallery-img" data-slick-index="' + i + '"></div>');
        getIframeInfo(iframeThumbnail);
      });

      //DEFAULT IMAGE COUNTER VALUE
      $('.slider-count').html('1' + ' / ' + iframeCount);

      //WORKING OUT SUB-GALLERY DIV AMOUNT, POPULATE
      var divCount = Math.ceil(data.iframeImages.length);

      for (var i = 0; i < divCount; i=i+2) {
        if(data.iframeImages[i+1] == undefined){
          console.log('not here');
          $('.gallery-sub-slider').append(`<div class="sub-gallery-item" data-slick-index="${i}"><img src="//img.youtube.com/vi/${data.iframeImages[i].iframeThumb}/0.jpg" class="sub-gallery-img" data-slick-index="${i}"></div>`);
          return;
        }
        else{
          $('.gallery-sub-slider').append(`<div class="sub-gallery-item" data-slick-index="${i}">
          <img src="//img.youtube.com/vi/${data.iframeImages[i].iframeThumb}/0.jpg" class="sub-gallery-img" data-slick-index="${i}">
          <img src="//img.youtube.com/vi/${data.iframeImages[i + 1].iframeThumb}/0.jpg" class="sub-gallery-img" data-slick-index="${i + 1}">
          </div>`);
        }
      }
      
    }
  }).done(function(){
    //INITIALIZE SLIDERS
    createSlider();
  });
}
populateCars();

3 Answers3

0

Try using a callback

   var something= FunctionWithCallback(data.property, function 
      callback(data) { do something, append to array })

     function FunctionWithCallback(passin, callback) {                    
                $.ajax({
                    url: "/controller/action",
                    type: "POST",
                    dataType: "json",
                    data: { passin: passin },
                    success: function(data) {
                        callback(data);
                    },

                });
            }
Patrick Goode
  • 1,412
  • 5
  • 20
  • 35
  • I will try, just not sure how my top thumbnail function will apply to that though.. Seems like a completely different structure –  Sep 08 '17 at 13:33
0

Your main problem is how you're specifying dataType in your ajax calls:

dataType: "jsonp",

change that to

dataType: "json",

As an aside, log the object from the callback, not simply text like "it didn't work". You'll save yourself a lot of time by lining in diagnostics.

Here's a plnkr with the script working.

RamblinRose
  • 4,883
  • 2
  • 21
  • 33
  • Thanks for the help, but that was because I thought in the Stack editor it had to be JsonP for cross origin. The problem I have is accessing the iframeArray because it still has its content being loaded –  Sep 08 '17 at 13:45
  • I believe you're thinking "contentType" on the request - the returned data is specified with 'dataType', see this good [SO post](https://stackoverflow.com/questions/2722750/ajax-datatype#2722770) – RamblinRose Sep 08 '17 at 13:45
  • In any event, the plnkr displays a list of nice cars ;) – RamblinRose Sep 08 '17 at 13:54
0

Remember that AJAX is asynchronous by nature: so when populateCars() method is called and returns success, you will perform iteration using $.each(). All is good now, until you run into getIframeInfo(). At this point of time, you are making another AJAX call but not waiting for it to complete. An easier way to go about your problem is:

  1. Return the promise from getIframeInfo()
  2. When the promise from getIframeInfo(iframeThumbnail) is resolved in each iteration within populateCars(), you push whatever data you have retrieved into iframeTitleArray.

A refactored version of your code, with all the unnecessary code removed to keep it simple, will look like this:

function getIframeInfo(uniqueID) {
  // Return the promise
  return $.ajax({
    url: 'http://query.yahooapis.com/v1/public/yql',
    data: {
      q: "select * from json where url ='https://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=" + uniqueID + "&format=jsonp'",
      format: "jsonp"
    },
    dataType: "jsonp"
  })
}

function populateCars(carId) {
  $.ajax({
    type: 'GET',
    url: 'https://api.myjson.com/bins/i80y1',
    data: {
      get_param: 'value'
    },
    dataType: 'jsonp'
  }).done(function(data) {
    //DEFAULT DATA PLACEMENT
    // ...

    //LOOP THROUGH JSON AND POPULATE
    $.each(data.iframeImages, function(i) {

      // ITERATIVE LOGIC
      // ...

      // Wait for getIframeInfo() to resolve, then push data into array
      getIframeInfo(iframeThumbnail).done(function(data) {
        var iframeTitle = data.query.results.json.title;
        iframeTitleArray.push(iframeTitle);
      })
    });

    // DEFAULT IMAGE COUNTER VALUE
    // ...

    // WORKING OUT SUB-GALLERY DIV AMOUNT, POPULATE
    // ...
  });
}

However, based on your code I don't see you using the iframeTitleArray anywhere else. If you really want to get the full array back at some point, you will have to daisy chain your promises. Instead of $.each(), use $.map() so that you push each returned getIframeInfo promise into an array, and then wait for all promises in that array to resolve entirely:

// LOOP THROUGH JSON AND POPULATE
var iframeTitles = $.map(data.iframeImages, function(i) {

  // ITERATIVE LOGIC
  // ...

  // Push getIframeInfo() to array
  return getIframeInfo(iframeThumbnail);
});

// Wait for all iframeTitles to be resolved
$.when.apply($, iframeTitles).then(function() {
  var responses = arguments,
      titles = [];

  $.each(responses, function(idx, response) {
    var iframeTitle = response[0].query.results.json.title;
    titles.push(iframeTitle);
  });

  console.log(titles);
});
Terry
  • 63,248
  • 15
  • 96
  • 118
  • Man this is a godly answer. THANK YOU TERRY. Yet I keep getting a error. Check this codepen - https://codepen.io/anon/pen/oermYj –  Sep 08 '17 at 14:09
  • Keeps telling me response.data.query.results.json.title; is undefined –  Sep 08 '17 at 14:17
  • @Darian Can you try logging `iframeTitles` to your browser console? Do you see an array of promises? Anyway, looks like I made a mistaken in the parameters assigned to `$.each()`. Try `$.each(responses, function(idx, responses) {...})` and also, use `response[0].query.results.json.title` instead of `response.data.query.results.json.title;`. Updated my answer :) – Terry Sep 08 '17 at 14:25