javascriptinfinite-scrolljquery-masonryimagesloaded

How to run masonry only after all html5 videos are loaded with infinitescroll?


masonry infinite scroll append html5 videos overlapping

i am currently using imagesLoaded library which checks whether images are loaded then calls masonry.

But it was not working with html5 video tag, because of this videos gets overlapped on one another.

so i changed calling masonry from document.ready to window.load and removed call to imagesLoaded on initial loading i.e. from this

$(document).ready(function(){

    var $container = $('#media');
    // layout Masonry again after all images have loaded
    $container.imagesLoaded( function() {

      $container.masonry({
          "columnWidth": "." + "col-sm-2",
          itemSelector: '.item',
          gutter: 0,
        });
      $('.item').css('opacity', '1.0');
    });

});

to this

$(window).load(function(){
        var $container = $('#media');

          $container.masonry({
              "columnWidth": "." + "col-sm-2",
              itemSelector: '.item',
              gutter: 0,
            });
          $('.item').css('opacity', '1.0');
});

now html5 videos in masonry are not overlapping, and are rendering perfectly on page's first load i.e. initial load, but as i am also using infinite-scroll which adds more images/videos on scrolling page down, so when new videos are being added to container they are being overlapped , this behavior is caused by early running of masonry before all the video elements are being loaded as imagesloaded cant check the videos loaded.

this is the code.

$(document).ready(function(){
    var $container = $('#media');
    var no_more_media = "<?= Lang::get('lang.no_more_to_load') ?>";
    var loading_more_media = "<?= Lang::get('lang.loading_more_media') ?>";

    $container.imagesLoaded(function(){
            $container.masonry();
        });

$container.infinitescroll({
        loading: {
            finished: undefined,
            finishedMsg: "<p>" + no_more_media + "</p>",
            img: "data:image/gif;base64,R0lGODlhAQABAHAAACH5BAUAAAAALAAAAAABAAEAAAICRAEAOw==",
            msg: null,
            msgText: "<div class='loading'><i></i><i></i><i></i></div><p>" + loading_more_media + "</p>",
            selector: null,
            speed: 'fast',
            start: undefined,
        },
        navSelector  : "ul.pagination",            
                       // selector for the paged navigation (it will be hidden)
        nextSelector : "ul.pagination a:first",    
                       // selector for the NEXT link (to page 2)
        itemSelector : ".container #media .item",
        animate: false,
        bufferPx: 160,
      },

      function( newElements ) {
         // hide new items while they are loading
        //var $newElems = 
        $.each($(newElements), function(index, value){
            item_click_events($(value));
        });

            $( newElements ).css({ opacity: 0 });

            $(newElements).imagesLoaded(function(){
               var $newElems = $( newElements );
               $newElems.animate({ opacity: 1 });
               $container.masonry( 'appended', $newElems, true);
            }
            );

      });
});

i have tried changing document.ready to window.load in above code too, and removing running imagesloaded altogether, but its not working with infinitescroll.,

e.g. modified code

$(window).load(function(){
    var $container = $('#media');
    var no_more_media = "<?= Lang::get('lang.no_more_to_load') ?>";
    var loading_more_media = "<?= Lang::get('lang.loading_more_media') ?>";

            $container.masonry();

    $container.infinitescroll({
        loading: {
            finished: undefined,
            finishedMsg: "<p>" + no_more_media + "</p>",
            img: "data:image/gif;base64,R0lGODlhAQABAHAAACH5BAUAAAAALAAAAAABAAEAAAICRAEAOw==",
            msg: null,
            msgText: "<div class='loading'><i></i><i></i><i></i></div><p>" + loading_more_media + "</p>",
            selector: null,
            speed: 'fast',
            start: undefined,
        },
        navSelector  : "ul.pagination",            
                       // selector for the paged navigation (it will be hidden)
        nextSelector : "ul.pagination a:first",    
                       // selector for the NEXT link (to page 2)
        itemSelector : ".container #media .item",
        animate: false,
        bufferPx: 160,
      },

      function( newElements ) {
         // hide new items while they are loading
        //var $newElems = 
        $.each($(newElements), function(index, value){
            item_click_events($(value));
        });

            $( newElements ).css({ opacity: 0 });

               var $newElems = $( newElements );
               $newElems.animate({ opacity: 1 });
               $container.masonry( 'appended', $newElems, true);

      });
});

there is another way i can solve this overlapping issue, by specifying video width and height, but as its responsive design, specifying video width and height breaks the responsiveness.

so my question is , is there any js library simmilar to imagesloaded which makes sure all videos are loaded and then i can call to masonry ? or how can i make sure the videos wont get overlapped on infinitescroll ?


update 1 :

i have tried many techniques, for infinitescroll

$(newElements).load(function(){
   var $newElems = $( newElements );
   $newElems.animate({ opacity: 1 });
   $container.masonry( 'appended', $newElems, true);
});

doesnt loads new content after pagescroll.

$(window).load(function(){
   var $newElems = $( newElements );
   $newElems.animate({ opacity: 1 });
   $container.masonry( 'appended', $newElems, true);
});

doesnt loads new content after pagescroll.

   var $newElems = $( newElements );
   $newElems.animate({ opacity: 1 });
   $container.masonry( 'appended', $newElems, true);

overlaps video content

so i have came up with calling infinite-scroll early and slowing down the container.masonry by 3 seconds which is working perfectly for now., but still waiting for proper solution.

e.g.

bufferPx: 700,

setTimeout(function(){
       var $newElems = $( newElements );
       $newElems.animate({ opacity: 1 });
       $container.masonry( 'appended', $newElems, true);
}, 3000);

above is delaying running masonry by 3 seconds.

i tried looking for something like window.load for div, but there is none, so my best option is check whether all the videos and images are loaded and then call masonry after calling infinite-scroll


added working demo http://plnkr.co/edit/46YzHBJ7eFAXfsPqZB1q you can see the issue, by clicking run and scrolling down.


Solution

  • Looks like you can fix it by waiting for the loadeddata event of the video's

    Here is the basic idea:

    function waitForvidLoad(vids, callback) {
         /* if no videos i.e. mobile mode only gifs and jpgs then call callback else masonry breaks.*/
            if(vids.length === 0){
                callback();
            }
        var vidsLoaded = 0;
        vids.on('loadeddata', function() {
          vidsLoaded++;
          if (vids.length === vidsLoaded) {
            callback();
          }
        });
      }
    

    .

      var $container = $('#container');
      var vids = $('#container').find('video');
      waitForvidLoad(vids, function() {
        $container.imagesLoaded(function() {
          $container.masonry({
            itemSelector: '.box',
            columnWidth: 100
          });
      });
    

    Working plunker here: http://plnkr.co/edit/jXJ7oFxF3sFWBAJuBqdQ?p=preview