Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy load content of slides inside carousel (content is oEmbeds/iframes)

I am loading in ajax a modal/popin with a Bootstrap carousel in which each slide is (not an image as in many question about lazy loading) but an iframe from oEmbed from various social networks (facebook, instagram, twitter, ...).

The issue is that when I click the button that laods the modal, ALL the slides content get loaded, that is to say 15 to 20 oembeds(each of them loading content text, image and javascript...).

I would like to be clever about it and only "lazy load" slide by slide or even smarter 3 slides by 3 slides.

I am just also mentioning for the sake of information that I am using scrollMonitor and Hubspot Messenger. But i'd rather use Bootstrap slide events to trigger the apparition/load of each slide or any suggestion you would have.

I'm using ruby on rails as back end language

The url of the oEmbed programmatically change as they are inputed from a Admin Backoffice and change on each Article/page but you'll find below an example :

Page.html

//button to click to make modal appear
<a class="btn btn-primary" onclick="loadModal()" id="socialStoryModal">
      load modal
</a>

Load Modal with Hubspot Messenger in page.js

function loadModal() {  
      var msg;
      msg = Messenger().post({
        message:  'modal.html.erb',/see below the carousel
        showCloseButton: true,
        hideAfter: false
      }); 
    }

modal.html.erb = Modal with the carousel and the social embeds (here can be up to 50 of them)

<div id="embeds-carousel" class="carousel slide" data-ride="carousel" data-interval="false">

    <div class="carousel-inner" role="listbox">    

         <div class="item active" id="item1" >
    <script>
var url = « https://api.instagram.com/oembed?url=https://www.instagram.com/p/5456544654565/";
embed_request = {
      url: url,
      dataType: "jsonp",
      cache: false,
      success: function (data) {
        try {
          var embed_html = data.html;
          $( "div#item1").html(embed_html);
        } catch (err) {
          console.log(err);
        }
      }
    }; 
$.ajax(embed_request);
</script>
</div>

  <div class="item" id="item2" >
    <script>
var url = "https://publish.twitter.com/oembed?url=https://twitter.com/coca/status/546664465342324"; 

embed_request = {
      url: url,
      dataType: "jsonp",
      cache: false,
      success: function (data) {
        try {
           var embed_html = data.html;
          $( "div#item2").html(embed_html);
        } catch (err) {
          console.log(err);
        }
      }
    };  
$.ajax(embed_request);
</script>
</div>

<div class="item" id="item3" >
    <script>
var url = "https://publish.twitter.com/oembed?url=https://twitter.com/muse/status/65353453F"; 

embed_request = {
      url: url,
      dataType: "jsonp",
      cache: false,
      success: function (data) {
        try {
           var embed_html = data.html;
          $( "div#item3").html(embed_html);
        } catch (err) {
          console.log(err);
        }
      }
    }; 
$.ajax(embed_request);
</script>
</div>


<div class="item" id="item4" >
    <script>
var url = « https://api.instagram.com/oembed?url=https://www.instagram.com/p/cftzezeker5/";
embed_request = {
      url: url,
      dataType: "jsonp",
      cache: false,
      success: function (data) {
        try {
          var embed_html = data.html;
          $( "div#item4").html(embed_html);
        } catch (err) {
          console.log(err);
        }
      }
    };  
 $.ajax(embed_request);
 </script>
</div>

<div class="item" id="item5" >
    <script>
var url = « var url = "https://www.facebook.com/plugins/post/oembed.json/?url=https://www.facebook.com/cocacola/posts/fdgyez556Yds";
";
embed_request = {
      url: url,
      dataType: "jsonp",
      cache: false,
      success: function (data) {
        try {
          var embed_html = data.html;
          $( "div#item5").html(embed_html);
        } catch (err) {
          console.log(err);
        }
      }
    };  
 $.ajax(embed_request);
</script>
</div>

and so on…
 </div>
  <!-- Controls -->
  <a class="left carousel-control" href="#embeds-carousel" role="button" data-slide="prev">
    <i class="fa chevron fa-chevron-left "></i>
    <span class="sr-only">Previous</span>
  </a>
  <a class="right carousel-control" href="#embeds-carousel" role="button" data-slide="next">
    <i class="fa chevron fa-chevron-right "></i>
    <span class="sr-only">Next</span>
  </a>


</div>

I've seen tons of libraries to lazy load images and even sometimes scripts/iframes but they all need to have directly add certain classes I n the block, which is of no help for me as I use oembed above and I have nowhere to put these lazy classes.

I need to make it work with these oEmbeds iframes.

like image 786
Mathieu Avatar asked Feb 10 '17 16:02

Mathieu


People also ask

Are iFrames lazy loaded?

Lazy-load your iFrames. Lazy-loading yields priority to other resources that your user may need first. It postpones loading of all other iFrames until they are about to come into browser's viewport. iFrames in general are great for security of your site.

Do iFrames slow down page load?

So, you should not use iframe excessively without monitoring what's going on, or you might end up harming your page performance. To avoid having your iframes slow down your pages, a good technique is to lazy load them (i.e., loading them only when they are required like when the user scrolls near them).

What is Lazyload?

The benefits of lazy loading include: Reduces initial load time – Lazy loading a webpage reduces page weight, allowing for a quicker page load time. Bandwidth conservation – Lazy loading conserves bandwidth by delivering content to users only if it's requested.


1 Answers

To lazy load the embeds you need to add them to an array rather than rendering them in the DOM, and once all of them have been loaded (successfully or not) then you can use that array to only render in the DOM the current slide.

Here's an example:

var oEmbedUrls = [
  'https://api.instagram.com/oembed?url=https://www.instagram.com/p/5456544654565/',
  'https://publish.twitter.com/oembed?url=https://twitter.com/coca/status/546664465342324',
  'https://publish.twitter.com/oembed?url=https://twitter.com/muse/status/65353453F',
  'https://api.instagram.com/oembed?url=https://www.instagram.com/p/cftzezeker5/',
  'https://www.facebook.com/plugins/post/oembed.json/?url=https://www.facebook.com/cocacola/posts/fdgyez556Yds'
];

var oEmbedsHtml = [];
var doneCount = 0;
var currentSlideIndex;

$.each(oEmbedUrls, function(i, url){
    $.ajax({
      url: url,
      dataType: "jsonp",
      cache: false,
      success: function (data) {
        var itemIndex = oEmbedsHtml.length;
        oEmbedsHtml.push(data.html);
        $('#embeds-carousel .carousel-inner').append('<div class="item" id="item' + itemIndex + '"></div>');
        oEmbedUrlResponded();
      },
      error: function(){
        console.warn('oEmbed URL could not be loaded: ', url);
        oEmbedUrlResponded();
      }
    }
});

function renderEmbedSlide(index){
  currentSlideIndex = index;
  $('#item' + index).html(oEmbedsHtml[index]);
}

function oEmbedUrlResponded(){
  doneCount ++;

  // Check if all the URLs have been loaded (successfully or not) when we can now render the carousel and the first slide as well
  if(doneCount == urls.length){
    renderEmbedSlide(0); // Render the first embed
    /*** CALL HERE THE CODE TO ACTIVATE THE CAROUSEL COMPONENT ***/
  }
}

Finally, you'lll need to add a hook to your carousel component so that renderEmbedSlide(index) is called whenever the slide is changed by the carousel, being sure that the index (zero-based) of the new slide is passed as a parameter to the function.

You may also need to add a default min-width and min-height to the .carousel-inner .item CSS class to allow the carousel component know the dimensions beforehand, as the slides (embeds) will be lazy loaded thereafter.

like image 198
ablopez Avatar answered Nov 10 '22 13:11

ablopez