Problem: I have implemented an infinitescroll plugin in my rails app, along with JQuery Masonry. It works perfectly but I am facing one little problem: starting from the second page, the hover function does not get triggered. This problem is very similar to this post on Stackoverflow. I'm supposed to call my hover function again after the Masonry callback.
My original code:
<script>
$(function () {
var $container = $('#container_masonry');
$container.infinitescroll({
navSelector: '.pagination'
nextSelector: '.pagination a',
itemSelector: '.image_masonry'
loading: {
finishedMsg: 'Done loading'
img: 'http://i.imgur.com/6RMhx.gif'
}
},
// trigger Masonry as a callback
function(newElements) {
//hide new items while loading
var $newElems = $(newElements).css({ opacity: 0 });
//images must be loaded completely before adding to layout
$newElems.imagesLoaded(function(){
//they are loaded and ready to be showed
$newElems.animate({ opacity: 1 });
$container.masonry( 'appended', $newElems, true );
});
}
);
$container.imagesLoaded(function(){
$container.masonry({
itemSelector: '.image_masonry',
columnWidth: 10,
isAnimated: true,
animationOptions: { duration: 400 },
isResizable: true,
isFitWidth: true
});
$('.image_masonry').hover(
function(){
$('.title',this).fadeIn();
$('.like_num',this).show();
var buttonDiv= $(this).children('.button');
buttonDiv.toggle();
}, function(){
$('.title',this).fadeOut();
$('.like_num',this).hide();
var buttonDiv= $(this).children('.button');
buttonDiv.toggle();
});
});
});
</script>
I should add the following,
$('.image_masonry').hover(
function(){
$('.title',this).fadeIn();
$('.like_num',this).show();
var buttonDiv= $(this).children('.button');
buttonDiv.toggle();
}, function(){
$('.title',this).fadeOut();
$('.like_num',this).hide();
var buttonDiv= $(this).children('.button');
buttonDiv.toggle();
});
to right after,
$newElems.imagesLoaded(function(){
//they are loaded and ready to be showed
$newElems.animate({ opacity: 1 });
$container.masonry( 'appended', $newElems, true );
//ADD HOVER FCN HERE
However, simply adding the whole hover function did not work. I'm new to jQuery so I'm not entirely sure, but I need to pass in the related variables along with the function for it to work (got this hint from the similar post. So I should add something like
$('.image_masonry').hover(
function(SOME-RELATED-VARIABLES){
$('.title',this).fadeIn();
$('.like_num',this).show();
var buttonDiv= $(this).children('.button');
buttonDiv.toggle();
}, function(SOME-RELATED-VARIABLES){
$('.title',this).fadeOut();
$('.like_num',this).hide();
var buttonDiv= $(this).children('.button');
buttonDiv.toggle();
});
But I need someone to teach me what I should put in there. I'm struggling because of my lack of familiarity with jQuery. I appreciate your help a lot!
You were missing some commas between rows 5-11. Also if you're loading external content at a later time, you need to delegate the hover event with on or delegate depending on your version. I added on below.
$(function () {
var $container = $('#container_masonry');
$container.infinitescroll({
navSelector: '.pagination',
nextSelector: '.pagination a',
itemSelector: '.image_masonry',
loading: {
finishedMsg: 'Done loading',
img: 'http://i.imgur.com/6RMhx.gif'
}
},
// trigger Masonry as a callback
function (newElements) {
//hide new items while loading
var $newElems = $(newElements).css({
opacity: 0
});
//images must be loaded completely before adding to layout
$newElems.imagesLoaded(function () {
//they are loaded and ready to be showed
$newElems.animate({
opacity: 1
});
$container.masonry('appended', $newElems, true);
});
});
$container.imagesLoaded(function () {
$container.masonry({
itemSelector: '.image_masonry',
columnWidth: 10,
isAnimated: true,
animationOptions: {
duration: 400
},
isResizable: true,
isFitWidth: true
});
$('body').on({
mouseenter: function () {
$('.title', this).fadeIn();
$('.like_num', this).show();
var buttonDiv = $(this).children('.button');
buttonDiv.toggle();
},
mouseleave: function () {
$('.title', this).fadeOut();
$('.like_num', this).hide();
var buttonDiv = $(this).children('.button');
buttonDiv.toggle();
}
}, '.image_masonry');
});
});
Related
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.
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
I am trying to get infinite scroll to work with Masonry.
+function ($) {
var $container = $('.masonry');
$container.imagesLoaded(function(){
$container.masonry({
columnWidth: '.grid-sizer',
gutter: '.gutter-sizer',
itemSelector: '.item'
})
});
$container.infinitescroll({
navSelector : '#page-nav', // selector for the paged navigation
nextSelector : '#page-nav a', // selector for the NEXT link (to page 2)
itemSelector : '.item', // selector for all items you'll retrieve
loading: {
finishedMsg: 'No more pages to load.',
img: 'http://i.imgur.com/6RMhx.gif'
}
},
// trigger Masonry as a callback
function( newElements ) {
// hide new items while they are loading
var $newElems = $( newElements ).css({ opacity: 0 });
// ensure that images load before adding to masonry layout
$newElems.imagesLoaded(function(){
// show elems now they're ready
$newElems.animate({ opacity: 1 });
$container.masonry( 'appended', $newElems, true );
});
}
);
}(jQuery);
It seems if I remove the imagesLoaded function and just call the masonry, it shows the images how Masonry intended, but doesn't infinitely scroll.
As it is I get an error:
Uncaught TypeError: undefined is not a function
I am using Foundation and I am calling my scripts in this order:
#import 'vendor/masonry.pkgd.js';
#import 'vendor/jquery.infinitescroll.min.js';
#import 'scripts.js';
Scripts included the code I have highlighted at the start. jQuery version is 2.0.3
you will have to add the imagesloaded library.
try this code
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-infinitescroll/2.0b2.120519/jquery.infinitescroll.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/masonry/3.1.2/masonry.pkgd.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery.imagesloaded/3.0.4/jquery.imagesloaded.min.js"></script>
(function() {
// Main content container
var $container = $('.masonry');
// Masonry + ImagesLoaded
$container.imagesLoaded(function(){
$container.masonry({
// selector for entry content
columnWidth: '.grid-sizer',
gutter: '.gutter-sizer',
itemSelector: '.item'
});
});
// Infinite Scroll
$container.infinitescroll({
// selector for the paged navigation (it will be hidden)
navSelector : "#page-nav",
// selector for the NEXT link (to page 2)
nextSelector : "#page-nav a",
// selector for all items you'll retrieve
itemSelector : ".item",
// finished message
loading: {
finishedMsg: 'No more pages to load.',
img: 'http://i.imgur.com/6RMhx.gif'
}
},
// Trigger Masonry as a callback
function( newElements ) {
// hide new items while they are loading
var $newElems = $( newElements ).css({ opacity: 0 });
// ensure that images load before adding to masonry layout
$newElems.imagesLoaded(function(){
// show elems now they're ready
$newElems.animate({ opacity: 1 });
$container.masonry( 'appended', $newElems, true );
});
});
/**
* OPTIONAL!
* Load new pages by clicking a link
*/
// Pause Infinite Scroll
$(window).unbind('.infscr');
// Resume Infinite Scroll
$('.#page-nav a').click(function(){
$container.infinitescroll('retrieve');
return false;
});
})();
Here is the site.
When I resize my window, the layout isn't triggered. So after I resize, I have to refresh the browser in order to see the reconfigured layout. I looked through the Masonry docs and found this page which I think describes my problem: http://masonry.desandro.com/methods.html#bindresize
$container.masonry('bindResize')
However, I'm not sure where I'm supposed to implement it. Below is the code that I'm currently using.
if(jQuery().isotope) {
$container = jQuery('#masonry');
$container.imagesLoaded( function() {
$container.isotope({
itemSelector : '.item',
masonry: {
columnWidth: $(document).width() > 1035 ? 240 : 320
},
getSortData: {
order: function($elem) {
return parseInt($elem.attr('data-order'));
}
},
sortBy: 'order'
}, function() {
// Isotope Chrome Fix
setTimeout(function () {
jQuery('#masonry').isotope('reLayout');
}, 1000);
});
});
// filter items when filter link is clicked
$container = jQuery('#masonry');
jQuery('#filter li').click(function(){
jQuery('#filter li').removeClass('active');
jQuery(this).addClass('active');
var selector = jQuery(this).find('a').attr('data-filter');
$container.isotope({ filter: selector });
return false;
});
}
Can someone help me out?
if(jQuery().isotope) {
$container = jQuery('#masonry');
$container.imagesLoaded( function() {
$container.isotope({
itemSelector : '.item',
masonry: {
columnWidth: 240
},
getSortData: {
order: function($elem) {
return parseInt($elem.attr('data-order'));
}
},
sortBy: 'order'
}, function() {
// Isotope Chrome Fix
setTimeout(function () {
jQuery('#masonry').isotope('reLayout');
}, 1000);
});
});
// filter items when filter link is clicked
$container = jQuery('#masonry');
jQuery('#filter li').click(function(){
jQuery('#filter li').removeClass('active');
jQuery(this).addClass('active');
var selector = jQuery(this).find('a').attr('data-filter');
$container.isotope({ filter: selector });
return false;
});
//added this line
jQuery(window).resize(function(){jQuery('#masonry').isotope('reLayout'); });
}
I have just added a single line in last and it will work.
Did you tried to insert the bindResize Snippet after your $container var?
// filter items when filter link is clicked
$container = jQuery('#masonry');
$container.masonry('bindResize');
jQuery('#filter li').click(function(){
...
}
The bindResize method should triggered on the Resize-Event so you don’t need to add it to the event manually. But the Amit’s solution should work too. But can you please remove the refreshing on the demo-site on resize? i can’t really test anything there.
I'm trying to get the tumblr like button to work with infinite scrolling.
Below is my code that doesn't work.
And after is a code that does work.
I am unfamiliair with Javascript so Im not sure how to mesh them to make it work
function( newElements ) {
var $newElems = $(newElements);
$newElems.hide();
$newElems.imagesLoaded(function(){
$wall.masonry( 'appended', $newElems,{isAnimated: false}, function() {
$newElems.fadeIn('fast');
});
});
});
$('#posts').show(0);
});
here one that works
function(newElements){
var $newElems = $(newElements).css("opacity","0").css("pointer-events","none");
$('.photoset-grid').photosetGrid({highresLinks: true,rel: $('.photoset-grid').attr('data-id'),gutter: '5px',onComplete: function(){}});
$('.photoset-grid,.lightbox').each(function() {
$(this).magnificPopup({delegate: 'a',type: 'image',gallery:{enabled:true},removalDelay: 200,mainClass: 'mfp-fade'});
});
var $newElemsIDs = $newElems.map(function (){return this.id;}).get();
$newElems.imagesLoaded(function(){
$newElems.css("opacity","1").css("pointer-events","auto");
$K.masonry('appended',$newElems,true);
console.log($newElems,$newElemsIDs);
Tumblr.LikeButton.get_status_by_post_ids($newElemsIDs);
});
});
thanks for any help.
edit: my full code
$(window).load(function(){
var $wall = $('#posts');
$wall.imagesLoaded(function(){
$wall.masonry({
itemSelector: '.entry, .entry_photo',
isAnimated : false
});
});
$wall.infinitescroll({
navSelector : '#pagination',
nextSelector : '#pagination a',
itemSelector : '.entry, .entry_photo',
bufferPx : 2000,
debug : false,
errorCallback: function() {
$('#infscr-loading').fadeOut('normal');
}},
function( newElements ) {
var $newElems = $( newElements );
$newElems.hide();
$newElems.imagesLoaded(function(){
$wall.masonry( 'appended', $newElems,{isAnimated: false}, function() {$newElems.fadeIn('fast');} );
});
}); $('#posts').show(0);
});
function( newElements ) {
var $newElems = $(newElements);
// Get IDs for new Elements
var $newElemsIDs = $newElems.map(function (){return this.id;}).get();
$newElems.hide();
// Tell Tumblr we need new LikeButton statuses
Tumblr.LikeButton.get_status_by_post_ids($newElemsIDs);
$newElems.imagesLoaded(function(){
$wall.masonry( 'appended', $newElems,{isAnimated: false}, function() {
$newElems.fadeIn('fast');
});
});
$('#posts').show(0);
});
I am using the following code to trigger infinitescroll on isotope masonry, however how do I use the "Click to load more posts" instead, "the manual trigger". I tried implementing from solutions on the internet but they do not work for me. Thanks.
/*--------------------------------------------------------------------------------*/
/* infinitescroll
/*--------------------------------------------------------------------------------*/
jQuery(document).ready(function($) {
var $container = $('.masonry');
$container.imagesLoaded( function(){
$container.isotope({
itemSelector : '.item'
});
});
$container.infinitescroll({
// selector for the paged navigation
navSelector : '.post-nav',
// selector for the NEXT link (to page 2)
nextSelector : '.post-nav .prev-post a',
// selector for all items you'll retrieve
itemSelector : '.item',
loading: {
finishedMsg: 'No more pages to load.',
img: 'http://i.imgur.com/qkKy8.gif'
}
},
function( newElements ) {
var $newElems = $( newElements ).css({ opacity: 0 });
$newElems.imagesLoaded(function() {
$newElems.animate({ opacity: 1 });
$container.isotope( 'appended', $( newElements ) );
$container.isotope('reLayout');
});
});
});
Assuming that you're using this plugin, the following should work to manually trigger a retrieve:
$container.infinitescroll('retrieve');