I am trying to append Masonry elements to existing ones.
However, what I currently have is this - the items show before Masonry is initialised then jump into position a second later. I'd like them to be hidden until they're in position.
This is the code (within an infinite scroll plugin) that I'm using to append the Masonry items:
$container.append(data);
$container.imagesLoaded( function()
{
$container.masonry('reloadItems').masonry();
});
And here it is being initialised:
$(document).ready(function ()
{
$container = $('#container');
// initialize the masonry instance
$container.imagesLoaded(function(){
$container.masonry({
columnWidth: 1,
itemSelector: '.item',
transitionDuration: 0
});
});
$('#container').scrollPagination({
nop : 36, // The number of posts per scroll to be loaded
offset : 0, // Initial offset, begins at 0 in this case
error : 'No More Posts!', // When the user reaches the end this is the message that is
// displayed. You can change this if you want.
delay : 500, // When you scroll down the posts will load after a delayed amount of time.
// This is mainly for usability concerns. You can alter this as you see fit
scroll : true // The main bit, if set to false posts will not load as the user scrolls.
// but will still load if the user clicks.
});
});
UPDATE
Based on Josh's answer, my code now looks like this:
$container.append(data);
$container.imagesLoaded( function()
{
$(".item").show();
$container.masonry('reloadItems').masonry();
});
And I've added <class='hide'> to the item tag.
However, now no elements show up when I refresh the page.
Have them load with the bootstrap hidden class set, and remove it after masonry runs.
If masonry needs them to be visible to do its calculations, have them displayed off-screen when loaded. Z-index, crazy position, etc.
Update
http://masonry.desandro.com/methods.html
So I gave a quick glance at methods here, without this trickery I talked about, I do believe you can ajax-load your new items, then use the masonry.addItems( items ) method.
Related
I am using mCustomScrollbar and I am trying to dynamically load content on top and bottom of the scroll (of course, not the same time).
http://manos.malihu.gr/jquery-custom-content-scroller/
When appending content it works awesome, the scroll will stay in the correct position (the position you scrolled to, and will automatically change the scroll bar position so that you can continue to scroll down to see the new content).
However, when you prepend content (place it on top in the scrollbar), and the user scrolls up, the content will load but the scrollbar will be forced to move up to the top. I want this to work exactly the same way as when appending content on the bottom: let the user scroll up to see the new content.
$(selector).mCustomScrollbar({
mouseWheel: {
scrollAmount: 500,
preventDefault: true
},
callbacks: {
advanced: {
updateOnContentResize: true
},
onScroll: function() {
// this.mcs.topPct contains the current scroll position (when scroll animation is completed.
// it can be between 0-100, where 100 is bottom and 0 is top
//
// my scroll starts on the bottom, and when this.mcs.topPct is 0
// I load dynamic content and place it on the very top of all content
// this causes the scroll to display this content immediately,
// and I would like the user to manually scroll up to see the added content.
}
}
});
if it's still relevant, my solution is:
Before loading new data (assuming you use jquery load/post) get your first ,the top most entry (comment,picture etc.) as an object 'YourObject' (name it how you like it)
Once you load new content use the following line
$(selector).mCustomScrollbar("scrollTo",YourObject,{scrollInertia:0});
It flickers a bit, but at the moment that's about the only way to achieve it.
$(selector).mCustomScrollbar({
mouseWheel: {
scrollAmount: 500,
preventDefault: true
},
callbacks: {
advanced: {
updateOnContentResize: true
},
onBeforeUpdate:function(){
this.totalScroll = this.mcs.topPct.slice(0);
},
onUpdate:function(){
this.mcs.topPct = this.totalScroll;
}
});
Not sure if it works because I don't really have time to make a list that renders objects both on the top and bottom, but if it works then great!
Let me know if it works :)
I ended with the solution below which is not perfect because of flickering.
It requires that the item size is fixed, that you compute "itemsPerRow" beforehand, and (preferably) that you prepend full rows
My content is generated by angular directives doing asynchronous calls. Maybe it is the cause of the flickering.
I'll have to dig again into malihu code to find a better way I guess.
var container=$('.mCustomScrollbar');
var mcs=container[0].mcs;
if (mcs.direction=='y') {
var offset=Math.round(items.length/itemsPerRow)*itemHeight;
} else {
var offset=items.length*itemWidth;
}
var side={x: 'left', y: 'top'};
var pos=mcs[side[mcs.direction]];
var scrollOptions={scrollInertia: 0};
container.mCustomScrollbar('scrollTo', pos-offset, scrollOptions);
Head's up!
There's a pending feature-request issue on Isotope's GitHub repo that you should add a "👍" reaction to if you're interested in seeing official docs and demos for this (how to combine Isotope, Infinite Scroll, filtering, and sorting). It was opened by Isotope's creator to gauge interest. If interested, please upvote!
**TL;DR: To help get official docs and demos for this, go here and add a "👍" reaction.**
Trying to piece together a filterable layout using the Isotope JS plugin and Paul Irish's (sadly unmaintained) Infinite Scroll plugin.
Filtering is somewhat working. Initially it filters the page 1 content. For it to filter items not on page 1 I need to scroll down (I suppose this is bringing the elements in the browser's memory, thus making it available to the filtering script?)
via a set of select boxes for the initial page content (ie: the content on page 1).
Question 1:
How to get the filter to work for all page items? ie: How to reference all elements in the filter script, even those not yet brought onto the page via infinite scroll?
Question 2:
Once I have scrolled down and all the elements are filterable, the window does not resize on filtering. so when there are only one or two elements shown via the filter, it's still possible to scroll way down the page (even though no elements are shown). Upon inspection of these elements, I see that they're still in the DOM.
Filtering Script
function filterTags(){
isotopeInit();
var $checkboxes = $('#tag-wrap input')
$checkboxes.change(function(){
var arr = [];
$checkboxes.filter(':checked').each(function(){
var $dataToFilter = $(this).attr('data-filter');
arr.push( $dataToFilter );
});
arr = arr.join(', ');
$container.isotope({ filter: arr });
});
};
Isotope Init
function isotopeInit(){
var $container = $('.post-excerpts').imagesLoaded( function() {
$container.isotope({
itemSelector: '.post-excerpt-block-wrap',
layoutMode: 'masonry',
animationEngine: "best-available",
masonry: {
columnWidth: '.post-excerpt-block-wrap'
},
transitionDuration: '2.0',
hiddenStyle: {
opacity: 0
},
visibleStyle: {
opacity: 1,
transform: 'scale(1)'
}
});
});
};
Infinite Scroll Init
$container.infinitescroll({
loading: {
finished: undefined,
finishedMsg: "<em>No more posts to load.</em>",
img: "http://www.infinite-scroll.com/loading.gif",
msg: null,
msgText: "<em>Loading the next set of posts...</em>",
selector: '.infinite-loader',
speed: 'fast',
start: undefined
},
binder: $(window),
//pixelsFromNavToBottom: Math.round($(window).height() * 0.9),
//bufferPx: Math.round($(window).height() * 0.9),
nextSelector: "a.older-posts",
navSelector: "nav.pagination",
contentSelector: ".content",
itemSelector: ".post-excerpt-block-wrap",
maxPage: {{pagination.pages}},
appendCallback: true
},
// Callback for initializing scripts to added post excerpts
function(newElements) {
var $newElems = $( newElements );
loadImages();
checkForFeatured();
makeFontResponsive();
addReadMoreLinks();
fitVidInit();
$newElems.imagesLoaded(function(){
$container.isotope( 'appended', $newElems );
});
}
);
Any ideas, suggestions, or other insights are incredibly welcomed. Many thanks in advance.
##Update:
Regarding Questions 2: Seems the problem is related to how Isotope is being told to filter the items. Specifically, this code from the isotope init function:
transitionDuration: '2.0',
hiddenStyle: {
opacity: 0
},
visibleStyle: {
opacity: 1,
transform: 'scale(1)'
}
I've tried changing it to the following, though this removes the completely from the DOM (fixing the spacing issue) and they're not returned into the DOM upon "unfiltering" them. So it's not a solution:
hiddenStyle: {
display: 'none'
},
visibleStyle: {
display: 'visible',
transform: 'scale(1)'
}
I've also tried simply removing these config lines altogether, which seems like the obvious "clean" solution, but this too still leaves lots of white space on the page upon filtering. Not sure whether the problem here is with my Isotope or Infinite Scroll implementation.
For question 2, one thing you could do is applying the display:none style to all hidden elements (and remove from all the visible ones) after isotope filtering.
I think you should be able to use the "on layoutComplete" event listener of isotope to apply it at the right time, like this:
$container.isotope( 'on', 'layoutComplete',
function( isoInstance, laidOutItems ) {
$('.my-elements-class.hiddenStyle').addClass('reallyHiddenStyle');
$('.my-elements-class.visibleStyle').removeClass('reallyHiddenStyle');
}
);
Where, of course, the elements you want to filter are of css class my-elements-class, you applied isotope filtering to $container and you define
reallyHiddenStyle: {
display: 'none'
}
in your CSS.
For question 1, perhaps you need to use a similar strategy with infinitescrolling callback, adding new elements to the filter once they appear because of scrolling.
You already have the callback passed as last parameter of the infinitescroll method, so at a quick look it seems that something like this might work:
$container.isotope('destroy');
$.each(newElements, function (i, el){/** add new elements to arr */});
$container.isotope({ filter: arr });
Do you have a working example you can share? So that I can check it out, if you'd like me to.
I am using Zurb Foundation to create a small website and I have a top navigation bar with four links. On clicking each link, I want to horizontally slide to a different page every time.
The content in the page should be loaded via ajax and not loading all pages on visiting index page itself. (note: content for slide-to page should be loaded not after the slide animation but somehow with the slide itself or else the empty sliding would look a little weird)
In addition, since I am using foundation to get responsive layouts, I am confused how to place the sections for the different pages horizontally. If the website wouldn't have been responsive, I probably would have placed the other pages separated by a margin property and to slide them, I could have done an animate of the margin property.
But, how do I get a horizontal page sliding effect (along with ajax loading) on my current page?
I think you want a 'single page website'? There are a lot of tutorials about this but this one is great:
http://vandelaydesign.com/blog/web-development/single-page-sliding-nav/
A live demo can be found here:
http://vandelaydesign.com/demos/single-page/
This uses jquery to scroll to the element with a specific id on the page. When you click one of the menu items it scrolls/slides automatically to that part of the page.
Just because the code is a bit long I'll only post the Jquery, to give you an idea.
<script type="text/javascript">
$(document).ready(function(){
$('#topnav').onePageNav({
currentClass: 'current',
scrollOffset: 0
});
});
</script>
$('#nav').onePageNav({
currentClass: 'current',
changeHash: false,
scrollSpeed: 750,
scrollOffset: 30,
scrollThreshold: 0.5,
filter: '',
easing: 'swing',
begin: function() {
//I get fired when the animation is starting
},
end: function() {
//I get fired when the animation is ending
},
scrollChange: function($currentListItem) {
//I get fired when you enter a section and I pass the list item of the section
}
});
Hope it helps :)
I have some divs that have dynamic heights controlled by a 'click' function as below:
$('.expand').click(function() {
$(this).next('.collapse').slideToggle();
});
I am attempting to apply the jQuery wookmark plugin to the divs, and it works, apart from when their heights are dynamically resized by expanding one of the sections. From the documentation, I copied over one of the examples to my code, and the dynamic height works
$(document).ready(new function() {
// Prepare layout options.
var options = {
autoResize: true, // This will auto-update the layout when the browser window is resized.
container: $('#container'), // Optional, used for some extra CSS styling
offset: 30, // Optional, the distance between grid items
itemWidth: 300 // Optional, the width of a grid item
};
// Get a reference to your grid items.
var handler = $('.outerwrapper');
// Call the layout function.
handler.wookmark(options);
// Capture clicks on grid items.
handler.click(function(){
// Randomize the height of the clicked item.
var newHeight = $('img', this).height() + Math.round(Math.random()*300+30);
$(this).css('height', newHeight+'px');
// Update the layout.
handler.wookmark();
});
});
You can see this working here. How can I make it so that when you click one of the headings inside the divs, the layout updates, as it does in the example. Thanks in advance.
Usually third party jQuery plugins include some kind of "Refresh" or "Resize" function.
Taking a quick look at the function, it doesn't appear to have one; however, since there is an "autoResize" option (which will reload the layout on browser resize), you could simply create a click event that triggers the "resize" event like so:
JAVASCRIPT:
$("h1.resize").live("click", function()
{
$(window).trigger('resize');
});
http://api.jquery.com/trigger/
http://api.jquery.com/resize/
EDIT:
Re-reading the question again,
Looks like this:
handler.wookmark();
should refresh the layout (based on your posted code). So you should be able to use that instead of the resize trigger.
$("h1.resize").live("click", function()
{
handler.wookmark();
});
I'm a little confused with the next steps to take on a project I'm working on and hopefully you could give me some ideas/help.
http://goo.gl/4d72h
I'm using Wordpress, and a combination of Portfolio Slideshow Pro (http://madebyraygun.com/wordpress/plugins/portfolio-slideshow-pro/) and Masonry (http://masonry.desandro.com/index.html) to create the landing page of this project.
As you can see by visiting the site, each 'post' is wrapped in a grid_6 float, allowing two floats per row, and then I am using masonry to place everything together as it does. I've wrapped the masonry code in a (window).load function to wait until all the featured images have loaded and then it starts the masonry. Pretty straightforward.
<script>
$(window).load(function(){
var $container = $('.masonry-cont-area');
$container.imagesLoaded( function(){
$container.masonry({
itemSelector : '.single-fg-post'
});
});
});
</script>
However, the masonry is only taking into consideration the first feature image for it's positioning etc. If you click the images, or the dots, it'll advance to the next image which can be longer or shorter in height, which is causing a few problems. Because the masonry has already taken place, it's overlaping with the next post etc. You can see what I mean when you click on the images on the link given above.
So, what I'm after today, is any ideas on how this can be fixed? Can masonry take the height from the tallest image in the slideshow? Can it changes dynamically as the images are clicked? Can I make sure that a margin at the bottom is ALWAYS given on absolute positioned items?
Any ideas would be really appreciated.
Thanks all,
Richard
You slideshow plugin does not seem to expose any event hooks. So you will have to do it the verbose way ..
Change the code where you initialize the masonry plugin to
$(window).load(function(){
var $container = $('.masonry-cont-area');
$container.imagesLoaded( function(){
$container.masonry({
itemSelector : '.single-fg-post',
isAnimated: true // added this line to make the resizing of the masonry animated and not instant..
});
// whenever we click on a bullet element
$('.pager').on('click','.bullet', function(){
// we use timeout to delay the redrawing of masonry
// because the slideshow takes sometime to fade out the current slide
// and slide in the new one..
// We have to wait until the slideshow has completed its transition before
// redrawing masonry, so that the masonry plugin can use the new slide's dimensions..
setTimeout(function(){
// we make masonry recalculate the element based on their current state.
$container.masonry();
}, 250); // 250 is the milliseconds of delay between the click to the bullet and the calling of the masonry redraw..
});
});
});
See it live at http://jsfiddle.net/XjVWN/embedded/result/
One thing you could do is to call .masonry('reload') when an image is changed.