1

I'm trying to grab the title of the youtube video and print it on a page, under the thumbnail of this video.

Everything works fine, I got the API key, and the titles are printing to the console. But It's done with Ajax so I have to make everything wait for the title to come. And that's where I'm stuck.

So how do I make the code/loop wait for Ajax to finish it's doing?

My simplified code. I tried posting it on code pen but no luck with making js work. https://codepen.io/anon/pen/JyYzwM

Link to a live page with it. It works there and you can see the console returns the titles. http://boiling-everglades-49375.herokuapp.com/video.php

$('.category-shape').on('click', function () {
   var documentary = ["siAPGGuvPxA", 'i6Hgldw1yS0', 'Omg1gMNtVpY', 'MfWHPnxrDI4', 'aT0HduxW8KY'];
   showVideos(documentary);
}


function showVideos(channel) {
if (!isFirstPass) {
    $('#addedContent').remove();
}
$('#dropdownVideoPicker').append('<div id="addedContent"></div>');
console.log(" ");
for (var i = 0; i < channel.length; i++) {
    var title = getTitle(channel[i]);
    $.when(getTitle(channel[i])).done( function () {
        var pageCode = generatePageCode(channel[i], title);
        console.log(getTitle(channel[i]));
        $('#addedContent').append(pageCode);
    });
}
$('#addedContent').hide();
$('#addedContent').slideDown();
isFirstPass = false;
$("html, body").animate({scrollTop: ($('.category-shape:nth-of-type(6)').offset().top)}, 1000);
grabYtId();
}


function grabYtId() {
    $('.videoThumbnail').on('click', function () {
      var $ytId = $(this).attr('src').slice(27, -6);
      showModalWindow($ytId);
    });
}


function showModalWindow(Id) {
var $theModal = $("#videoModal"),
    iframe = $("#iframe")[0],
    videoSRC = 'https://www.youtube.com/embed/' + Id,
    videoSRCauto = videoSRC + "?autoplay=1&rel=0&controls=1&showinfo=0";
$(iframe).attr('src', videoSRCauto);
$('button.close').click(function () {
    $(iframe).attr('src', videoSRC);
});
$theModal.on("hidden.bs.modal", function () {
    $(iframe).attr('src', videoSRC);
});
}

And that's the function that grabs the titles

function getTitle(videoId) {
$.ajax({
    url: "https://www.googleapis.com/youtube/v3/videos?id=" + videoId + "&key=" + "AIzaSyCDyE576FU2QRbkHivxHfrjbEjPwartzKo" + "&fields=items(snippet(title))&part=snippet",
    dataType: "jsonp",
    success: function (data) {
        var title = data.items[0].snippet.title;
        console.debug("function: " + title);
        var titleLoaded = new CustomEvent('titleLoaded', {
            detail: {
                loaded: true
            }
        });
        $('body')[0].dispatchEvent(titleLoaded);
        return title;
    },
    error: function (jqXHR, textStatus, errorThrown) {
        alert(textStatus, +' | ' + errorThrown);
    }
});
}

And yes, I know that giving an API key to the public is a bad idea but I'll change it add a website restriction in google.

Alex Ironside
  • 4,658
  • 11
  • 59
  • 119
  • So what is your question? If you have the titles returning and know you have to wait for the ajax call to complete then I don't understand what your question is? You can't remove the waiting time as the call has to complete for you to get the results.... Please update your question and be more specific with your problem/question. Thank you. – NewToJS Jul 28 '17 at 19:25
  • Edited to clarify – Alex Ironside Jul 28 '17 at 19:37

1 Answers1

2

You can push the ajax deffered objects in an array and call $.when.apply($,arr) to wait for all the call to be processed:

function showVideos(channel) {

  if (!isFirstPass) {
    $('#addedContent').remove();
  }
  $('#dropdownVideoPicker').append('<div id="addedContent"></div>');

  var arr = $.map(channel, function(data) {
    getTitle(data);
  });

  $.when.apply($, arr).then(function() {
    $('#addedContent').hide();
    $('#addedContent').slideDown();
    isFirstPass = false;
    $("html, body").animate({
      scrollTop: ($('.category-shape:nth-of-type(6)').offset().top)
    }, 1000);
    grabYtId();
  });
}

function getTitle(videoId) {

  return $.ajax({
    url: "https://www.googleapis.com/youtube/v3/videos?id=" + videoId + "&key=" + "AIzaSyCDyE576FU2QRbkHivxHfrjbEjPwartzKo" + "&fields=items(snippet(title))&part=snippet",
    dataType: "json",
    success: function(data, status, jqxr) {
      var title = data.items[0].snippet.title;
      var titleLoaded = new CustomEvent('titleLoaded', {
        detail: {
          loaded: true
        }
      });
      $('body')[0].dispatchEvent(titleLoaded);
      var pageCode = generatePageCode(videoId, title);
      console.log(title);
      $('#addedContent').append(pageCode);
    },
    error: function(jqXHR, textStatus, errorThrown) {
      alert(textStatus, +' | ' + errorThrown);
    }
  });
}

You can find a fiddle here

Bertrand Martel
  • 42,756
  • 16
  • 135
  • 159
  • I've read the docs but I'm still not sure how this works. var arr = $.map(channel, function(data) { getTitle(data); }); – Alex Ironside Jul 31 '17 at 14:42
  • From [this](http://api.jquery.com/jquery.map/) : `The $.map() method applies a function to each item in an array or object and maps the results into a new array`. But you can also declare `var arr = []` and `arr.push(getTitle(...));` in a for loop iterating channel item if you prefer – Bertrand Martel Jul 31 '17 at 14:48
  • So $.map() is just another way of building arrays? – Alex Ironside Aug 01 '17 at 15:03
  • And what is the $ in this context? The whole jquery object? `$.when.apply($, arr)` – Alex Ironside Aug 01 '17 at 15:04
  • Yes, the `this` value is set to jquery `$`, see [this](https://stackoverflow.com/a/14777167/2614364) – Bertrand Martel Aug 01 '17 at 15:15