I have an issue with my masonry code.
It works fine on pageload, but the items that are inside the masonry can be filtered, I am doing this using ajax and I'm replacing the entire div with elements to show the filtered items.
After this happens, the masonry code is not applied again and it falls apart.
How can I make sure the masonry stays applied even when content changes after pageload?
In my footer I have the following code:
<script type="text/javascript">
$(document).ready(function() {
$('.gridlist').isotope({
itemSelector: '.masonryitem',
layoutMode: 'masonry',
});
});
</script>
Then in my custom.js I have the following:
$( document ).ready(function() {
/* Ajax code voor aanbiedingen */
$("#branche").on('change', function() {
var option = $('#branche > option').filter(':selected');
if(option.val() == 'default'){
$.post("includes/ledenall.php", {
filter: option.val()
}, function(result){
$("#content1").html(result);
});
}else{
$.post("includes/leden.php?option=" + option.val(), {
filter: option.val()
}, function(result){
$("#content1").html(result);
});
}
});
});
Which returns my php file, but this time without the masonry being applied.
What can I do about this?
You can try reapplying your isotope library after changing the DOM:
/* Ajax code voor aanbiedingen */
$("#branche").on('change', function() {
var option = $('#branche > option').filter(':selected');
if(option.val() == 'default'){
$.post("includes/ledenall.php", {
filter: option.val()
}, function(result){
$("#content1").html(result);
$('.gridlist').isotope({
itemSelector: '.masonryitem',
layoutMode: 'masonry',
});
});
}else{
$.post("includes/leden.php?option=" + option.val(), {
filter: option.val()
}, function(result){
$("#content1").html(result);
$('.gridlist').isotope({
itemSelector: '.masonryitem',
layoutMode: 'masonry',
});
});
}
});
I don't know if .gridlist is totally replaced in your updated DOM. If not, you may need to somehow "remove" the old isotope instance, but something like this is what you need to do.
Add your code to a function
function func() {
$('.gridlist').isotope({
itemSelector: '.masonryitem',
layoutMode: 'masonry',
});
}
Then you can call the function and apply your isotope at any point you want
Related
I am trying to get Packery.js to work with LazyLoad.js, while having the ability to filter the gallery by tags.
www.temp.fokuspunkt.de
On the initial page load everything works fine:
After clicking throgh the tags and then clicking on the "all" button again, the layout is scrambled, however:
I assume this has to do with the lazy loading, as it can throw off the layout, as described in the documentation here:
https://packery.metafizzy.co/layout.html#imagesloaded
Adding the recommended solution
$grid.imagesLoaded().progress( function() {
$grid.isotope('layout');
});
throws an error, though:
My complete javascript file calling Isotope looks like this, I had tried to copy the above code right beneath the "$(window).on('load',function[...]" function block:
jQuery(function ($) {
var $grid = $('.isotope-list').packery({
layoutMode: 'packery',
filter: '*',
itemSelector: '.isotope-item',
gutter: 0,
});
$(window).on('load',function(){
$grid.packery('layout');
});
imagesLoaded( $grid ).on( 'progress', function() {
pckry.layout();
});
$('.filters li').click(function(){
//css button styling
$('.filters li').removeClass('current');
$(this).addClass('current');
// set isotope filter
var selector = $(this).attr('data-filter');
$grid.isotope({
filter: selector,
animationOptions: {
duration: 750,
easing: 'linear',
queue: false
}
});
$grid.packery('layout');
return false;
});
var $win = $(window),
$imgs = $("img"),
$loadVisible = function($els, trigger) {
$els.filter(function () {
var rect = this.getBoundingClientRect();
return rect.top >= 0 && rect.top <= window.innerHeight;
}).trigger(trigger);
}
$grid.packery('on', 'layoutComplete', function () {
$loadVisible($imgs, 'lazylazy');
$grid.packery('layout');
});
$win.on('scroll', function () {
$loadVisible($imgs, 'lazylazy');
});
$win.on('resize', function () {
$grid.packery('layout');
});
$imgs.lazyload({
effect: "fadeIn",
failure_limit: Math.max($imgs.length - 1, 0),
event: 'lazylazy'
});
});
I am certain I am doing something stupid, would anybody be kind enough to tell me what I am doing wrong? Thank you very much in advance!
So, it took a while, but I wanted to return and share my solution. Maybe it helps out somebody else in the future. My main problem was that I used isotope and packery (which is a standalone library), and not isotope and isotope-packery (which is an addon for isotope). I also changed my lazy loading plugin to "lozad", which makes a lot of thins easier.
In the code below you can also find a solution for using multiple filter terms in combination. In my case I use a row of row of radio buttons below the old button row you can see above.
jQuery(function ($) {
// initialize Packery
var $pckry = $('.isotope-list').isotope({
layoutMode: 'packery',
filter: '*',
itemSelector: '.isotope-item',
packery: {
gutter: 0
},
animationOptions: {
duration: 750,
easing: 'linear',
queue: false
}
});
// layout on first page load, so that the gutter gets set up
$(window).on('load', function () {
$pckry.isotope('layout');
});
// filter items on button click
$('.filters li').click(function () {
$('.filters li').removeClass('current');
$(this).addClass('current');
var combinedFilter = getFilter($('.filters li.current').attr('data-filter')) + getFilter($('input[name="isotope-type-filter"]:checked').val().toLowerCase());
$pckry.isotope({ filter: combinedFilter });
$pckry.isotope('layout');
});
// filter items on radio button change
$('input[name="isotope-type-filter"]').change(function () {
var combinedFilter = getFilter($('.filters li.current').attr('data-filter')) + getFilter($('input[name="isotope-type-filter"]:checked').val().toLowerCase());
$pckry.isotope({ filter: combinedFilter });
$pckry.isotope('layout');
});
function getFilter(buttonGroup) {
var filterValue = '';
if (buttonGroup === '*') {
filterValue = "";
} else {
filterValue = "." + buttonGroup;
}
return filterValue;
};
});
This could be kind of complex cause there is a lot of ravioli code involved. I'm just looking for possible causes of this behavior.
Im using Jquery Isotope, it works correctly. The only thing that is not working is a function that I call when the document is ready, why could that be? :
$( document ).ready(function(){
$('.grid').isotope({
itemSelector: '.element-item',
layoutMode: 'packery',
packery: {
gutter: 10
}
});
var isotopeFilter = function(f){
console.log(f);
$(".grid").isotope({filter: f});
}
isotopeFilter('.xp'); // Doesn't Work!!
$("#filter-basket").on("click", function(){
isotopeFilter('.basket'); // Works correctly
});
$("#filter-all").on("click", function(){
$(".grid").isotope({ filter: '.xp' }); // Works correctly
});
$("#filter-ghacking").on("click", function(){
$(".grid").isotope({ filter: '.ghacking' }); // Works correctly
});
})
The reason I need to call that function at document load is because I want to set a default filtering.
So here's what I'm trying to do. I have a grid with a lot of images, so I'm using the imagesLoaded library along with masonry.
Here's my CSS:
.grid {
opacity:0;
}
And HTML:
<div class="grid">
<div class="grid-sizer"></div>
<div class="gutter-sizer"></div>
<div class="item">image</div>
<div class="item">image</div>
<div class="item">image</div>
</div>
And here's my JS:
var $container = $('.grid');
// initialize Masonry after all images have loaded
$container.imagesLoaded( function() {
$container.masonry({
columnWidth: '.grid-sizer',
itemSelector: '.item',
gutter: '.gutter-sizer'
});
$container.masonry('on', 'layoutComplete', function(){
console.log('got here');
$container.animate({'opacity':1});
});
});
My goal is to have the grid hidden until all images are load and the layout is complete, and then fade it in. For some reason in my code above, it's never getting into the on layoutComplete block.
If I move that block outside of imagesLoaded, $container.masonry is undefined that point.
Any ideas?
FIDDLE HERE
If you change the grid opacity to 1 you can see everything is getting laid out fine. Just trying to figure out how to get the layoutComplete to call to set the opacity to 1.
You don't need to use the layoutComplete event on masonry. As you can just add your animation code under the masonry initialization .
When all images are loaded, the imageLoaded function will execute. You can then create the masonry object and animate right away like so:
var $grid = $('.grid').imagesLoaded( function() {
// init Masonry after all images have loaded
$grid.masonry({
columnWidth: 200,
itemSelector: '.item',
gutter: 10
});
console.log('got here');
$('.grid').animate({'opacity':1});
});
Here is a jsfiddle that demonstrate that
jQuery(document).ready(function($){
var wdm_wait = function(){
jQuery("body").find("img").each(function(i) {
if(!this.complete)
{
return false;
}
});
// when code reaches here Its assured that all the images are loaded
clearInterval(waiting);
console.log('got here');
var $container = $('.grid');
// initialize Masonry after all images have loaded
$container.masonry({
columnWidth: 100,
itemSelector: '.item',
gutter: 10
});
$container.animate({'opacity':1});
}
waiting = setInterval(wdm_wait,100);
});
This would certainly assure that your js code executes only after all the images have been loaded (rendered)
Hope this helps! :)
have you ever try this one, I think this is your answer
var $container = $('.grid').masonry({
columnWidth: 200,
itemSelector: '.item',
gutter: 10
});
$container.masonry( 'on', 'layoutComplete', function() {
$container.animate({'opacity':1});
});
$container.masonry();
i had implemented infinite scroll with masonry i got stucked in addthis share button not working when i scroll to next loading images the addthis button getting displayed but it is not sharing appropriate images.
if i remove following three lines from masonry function
addthis.toolbox('.addthis_toolbox');<br/>
addthis.counter('.addthis_counter');<br/>
addthis.init();
i am only able see addthis share button on first list of images after i scroll to next list of images the addthis share gets hidden
Javascript Code
<script type="text/javascript">var addthis_config = { "data_track_addressbar": false ;</script>
<script src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4e142f1d185c5361"></script>
<script src="js/jquery.masonry.min.js"></script>
<script src="js/jquery.infinitescroll.min.js"></script>
<script type="text/javascript">
$(function () {
var $container = $('#container');
$container.imagesLoaded(function () {
$container.masonry({
itemSelector: '.box',
columnWidth: 95
});
});
$container.infinitescroll({
navSelector: '#page-nav', // selector for the paged navigation
nextSelector: '#page-nav a', // selector for the NEXT link (to page 2)
itemSelector: '.box', // selector for all items you'll retrieve
loading: {
finishedMsg: 'No more photos 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);
addthis.toolbox('.addthis_toolbox');
addthis.counter('.addthis_counter');
addthis.init();
});
$('.listing_img_wrapper').hover(
function () { $(this).find('.hover_img').fadeIn("slow"); },
function () { $(this).find('.hover_img').fadeOut("slow"); }
);
// console.log("called");
// window.addthis.toolbox('.addthis_toolbox');
}
);
});
</script>
i had solved the solution by adding
addthis.counter('.addthis_counter');
and
if (window.addthis) {
window.addthis.ost = 0;
window.addthis.ready();
}
So I have a site that has 2 containers #container and #container2. I use jquery to append content that is of a certain size to one container, and the others to the other. Here is that code:
$(document).ready(function() {
$('.entry').each(function() {
if ($(this).height() > 200) {
$('#container2').append(this);
}
else {
$('#container').append(this);
}
});
});
So my issue is that with the infinite scroll and masonry, when the new content becomes available, the jquery does not run again in order to append the content to the right container. What can I add so that it will be able to append the content to the correct container?
Note: Each container can have tens of thousands of images.
Update:
Here is my masonry code:
$(window).load(function() {
var $wall = $('#container');
$wall.imagesLoaded(function() {
$wall.masonry({
itemSelector: '.entry, .entry_photo',
isAnimated: false
});
});
$wall.infinitescroll({
navSelector: '#page-nav',
nextSelector: '#page-nav 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('slow');
});
});
});
$('#container').show(500);
});
So what happens is that the next posts when they load, all load into #container regardless of their height. This clearly shows that masonry is working fine, but it's just not calling the jquery again when they load. Is there any way to insure that it calls the jquery I need? How do I do that?
I think you have to initialize masonry plugin after adding your content in containers
like,
$(document).ready(function(){
$('.entry').each(function(){
if($(this).height()>200){
$('#container2').append(this);
}
else{
$('#container').append(this);
}
});
// masonry plugin initialization after adding content to div
});