Currently I'm using AJAX to pull in data from our webservice. The issue I'm having is that it doesn't want to load the data into the masonry layout, everything in .social_block floats left one under the next (and I haven't set any float for these). So masonry isn't working :(
I wanted the following to happen: Load initial items from webservice in the masonry layout and on "infinite" scroll it would make the paged request from the webservice to append new items into the masonry layout.
So the questions are as follows:
- Why aren't my webservice items loading using masonry and just loading to the left of page?
- How can I use infinite scroll with my existing AJAX request so it pulls in new data into the masonry layout using the paging code I have in place as (first request load http://example.com/ automatically, second request load http://example.com/1 on first infinite scroll, third request http://example.com/2 on second infinite scroll, etc.)?
As an added note, if I add in an alert rather than console.log before line $container.imagesLoaded(function(){ it seems to slow things down but then loads the initial request into masonry format - weird!
<div id="container">
</div>
<p id="loadmore">
<button id="more">'Load More!</button>
</p>
<script src="js/vendors/jquery/jquery-1.10.0.min.js"></script>
<script src="js/vendors/masonry/jquery.masonry.min.js"></script>
<script src="js/vendors/jquery/jquery.infinitescroll.min.js"></script>
<script>
$(function(){
var $container = $('#container');
//alert('Masonry loads items in the nice layout if I do this');
$container.imagesLoaded(function(){
$container.masonry({
itemSelector: '.block',
columnWidth: 100
});
});
$container.infinitescroll({
navSelector : '#loadmore', // selector for the paged navigation
nextSelector : '#more', // selector for the NEXT link (to receive next results)
itemSelector : '.block', // selector for all items to 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 );
});
}
);
// set here so it is in reach
var page = 0;
// this will call the required url with new json data.
function loadPage(page) {
var url = 'http://example.com/' + page;
$.getJSON(url, function(data) {
var cont = $('#container');
$.each(data.data, function(index, obj) {
var item = obj.Message;
cont.append(
$('<li>', {"class": "block"}).append(
$('<span>', {"class": item.Type}).append(
$('<span>', {"class":"post_image"}).append(
$('<img>', {src:item.postImageLarge})
)
)
)
)
)
});
//$.each(data.data, function(key, val) { console.log('Data key: ', key, ', Value: ', val)});
});
}
// load more handler
$('#more').click(function(){
page = page + 1;
loadPage(page); //load more items
});
// initial run with page empty
loadPage('');
});
</script>
Related
I am working on this blog here:
http://insights.signetaccel.com/blog
The blog summaries on this listing page are positioned using a script called masonry.js. The container for the summaries is ".grid", while the summaries are all classed ".grid-item".
I have another script that creates an infinity scroll effect which requests the url to the next page, finds all of the .grid-items, and appends them to the bottom of the .grid container on the page.
The issue is that the masonry.js script applies inline styling to the .grid-item divs to position them. The newly appended .grid-item divs aren't effected by masonry.js because they are appended after the page loads.
how can I get the masonry.js script to "re-apply" itself to the page after appending new elements in order to have it apply to these new elements?
infinity scroll Script
(function($) {
$.fn.swoosh=function(loadingImgUrl,callback){
if(!loadingImgUrl){
loadingImgUrl="Loading...";
}
if (callback==null){
callback=-1;
}
var postList=this;
//SET VARIABLES
var turnOff=false;
var pageNumber=2; //toggle switch for infinite scroll. shuts off when on last page
var urlArray=window.location.href.toString().split("/"); //the array of url sections
var blogUrl=urlArray[0]+"//"+urlArray[2]+"/"+urlArray[3]+"/"; //the url for the blog
var baseUrl=blogUrl+"page/"; //URL with the page number stripped off the end
var postUrl=""; //initialize postURL string
var processing = false; //tells the scripts if there is already an ajax load happening
//insert the loading bar at the end of the posts-list
if(loadingImgUrl!="Loading..."){
postList.parent().append('<div class="loading"><img src="'+loadingImgUrl+'"></div>');
}
else{
postList.parent().append('<div class="loading">'+loadingImgUrl+'</div>');
}
$(".loading").hide(); //make sure loading bar is hidden
$(document).scroll(function(){
//kick out of function if it's already running, if it has been shut off, or if there is no 2nd page
if (processing || turnOff || pageNumber==0){
return false;
}
//when scrolling gets to the footer, start chugging!
if ($(window).scrollTop() >= $(document).height() - $(window).height() - $(".footer-container-wrapper").height()-150){
processing = true;
//currently processessing, so don't call function again until done
$(".loading").fadeIn(200); //fade in loading bar
postUrl=baseUrl + pageNumber; //calculate the page to load
//AJAX CALL
$.get(postUrl, function(data){
//grab only post items from the loaded page
var posts=$(data).find(".grid-item");
//check that the loaded page has content
if (posts.length > 0){
console.log(loadingImgUrl);
//fade out the loading bar, then attach the new items to the end of the list
$(".loading").fadeOut(200,function(){
posts.appendTo(".grid");
console.log(posts);
});
pageNumber++; //increment the page to load.
$(".next-posts-link").attr("href",baseUrl+pageNumber);
}
//if the loaded page doesn't have content, it means we have reached the end.
else{
turnOff=true;
$(".next-posts-link").after('<div class="next-posts-link unactive">Next</div>');
$(".next-posts-link:not(.unactive)").remove();
$(".loading").fadeOut(200);
}
processing=false; //we are done processing, so set up for the next time
setTimeout(function(){
twttr.widgets.load();
IN.parse();
FB.XFBML.parse();
gapi.plusone.go();
},350);
});
}
});
};
})(jQuery);
You should rebind masonry after $.post after posts.appendTo(".grid");
//take your binding in a variable
var container = $('.grid').masonry({
// options
itemSelector: '.grid-item',
columnWidth: 200,
columnWidth: '.grid-item',
percentPosition: true
});
//do this on $.post
$(".loading").fadeOut(200,function(){
posts.appendTo(".grid");
console.log(posts);
//changes made here in your code
container.append(posts).masonry('appended', posts);
});
I cant figure out how to have the initial fadein animation when masonry is initialized at first page load exactly like the original plugin's page:
http://masonry.desandro.com/
Any help suggestions?
I used the imagesLoaded progress deferred API and Masonry's appended method.
$('#load-images').click( function() {
var $items = getItems();
// hide by default
$items.hide();
// append to container
$container.append( $items );
$items.imagesLoaded().progress( function( imgLoad, image ) {
// get item
// image is imagesLoaded class, not <img>, <img> is image.img
var $item = $( image.img ).parents('.item');
// un-hide item
$item.show();
// masonry does its thing
$container.masonry( 'appended', $item );
});
});
Items are first hidden, then appended to the container. After each item is loaded, it un-hidden then gets revealed by Masonry.
Source: http://codepen.io/desandro/pen/iHevA
So if you check out: http://uniplaces.micrositesonline.info/blog/cities/ you'll see the isotope masonry plugin in action. The entire theme is from https://themetrust.com/demos/swell/. The issue is, on our site, the isotope plugin loads in a strange manner, the div that contains the masonry images fails to adjust the height properly and thus, it sometimes gets cut off. You can typically replicate this by reloading the page once it has loaded.
The code containing the js is in 'themetrust.js':
///////////////////////////////
// Project Filtering
///////////////////////////////
function projectFilterInit() {
if( jQuery('#filter-nav a').length > 0 ) {
jQuery('#filter-nav a').click(function(){
var selector = jQuery(this).attr('data-filter');
jQuery('#projects.thumbs').isotope({
filter: selector,
hiddenStyle : {
opacity: 0,
scale : 1
}
});
if ( !jQuery(this).hasClass('selected') ) {
jQuery(this).parents('#filter-nav').find('.selected').removeClass('selected');
jQuery(this).addClass('selected');
}
return false;
});
} // if() - Don't have this element on every page on which we call Isotope
}
///////////////////////////////
// Project thumbs
///////////////////////////////
function isotopeInit() {
setColumns();
gridContainer.isotope({
resizable: true,
layoutMode: 'masonry',
masonry: {
columnWidth: colW
}
});
jQuery(".thumbs .small").css("visibility", "visible");
}
///////////////////////////////
// Isotope Grid Resize
///////////////////////////////
function setColumns()
{
var columns;
var gw = gridContainer.width();
var ww = jQuery(window).width()
if(ww<=700){
columns = 1;
}else if(ww<=870){
columns = 2;
}else{
columns = 3;
}
colW = Math.floor(gw / columns);
jQuery('.thumbs .small').each(function(id){
jQuery(this).css('width',colW+'px');
});
jQuery('.thumbs .small').show();
}
function gridResize() {
setColumns();
gridContainer.isotope({
resizable: false,
layoutMode: 'masonry',
masonry: {
columnWidth: colW
}
});
}
///////////////////////////////
// Center Home Banner Text
///////////////////////////////
function centerHomeBannerContent() {
var bannerContent = jQuery('.home #banner-content');
var bannerContentTop = (windowHeightAdjusted/2) - (jQuery('.home #banner-content').actual('height')/2);
bannerContent.css('margin-top', bannerContentTop+'px');
bannerContent.show();
}
///////////////////////////////
// Initialize
///////////////////////////////
jQuery.noConflict();
jQuery(document).ready(function(){
jQuery(".content-area").fitVids();
mmenu_nav();
jQuery('#video-background').height(windowHeight);
video_resize();
if(!isMobile()){
getVideoBGs();
}
jQuery('body').imagesLoaded(function(){
projectFilterInit();
isotopeInit();
centerHomeBannerContent();
});
jQuery(window).smartresize(function(){
gridResize();
//full_width_images();
video_resize();
mmenu_nav();
centerHomeBannerContent()
});
//Set Down Arrow Button
jQuery('#down-button').click(function(){
jQuery.scrollTo( ".middle", {easing: 'easeInOutExpo', duration: 1000} );
});
//pull_out_the_quote();
//full_width_images();
});
We've tried modifying it to no avail, removing and tweeking, but nothing seems to work. At this point we think it make be the css transition initialized by the class isotope-item, so we removed it, which seems to work but we are not entirely sure why. Is it possible to retain the transitions and get the isotope plugin to behave with them reliably?
WOOOO that theme is mental to say the least.
There are so many HTTP request's it's not surprising it's failing to load some scripts within the exec time.
Right because this is a theme and we don't want to mess about with stuff to much for updating sake's I would recommend using autoptomize
It will compress and conjoin all your scripts and css files into one nice neat and easy to download file so that no render blocking or partial loading occur's
Just reviewed your site on http://uniplaces.micrositesonline.info/blog/cities/, probably "jquery.isotope.js" file is missing on your directly. Make sure the presence of "jquery.isotope.js" at JS folder. lets try
Several days ago I tried to incorporate Isotope into my site, and combine it with Fancybox 2 to create a nice looking gallery with filtering/sorting possibilities. Since many pages contain a lot of images, I prefer to show and append each image directly after it has finished loading rather than showing a loader until all images have been loaded.
In order to achieve this, I came up with this piece of code so far:
$( function() {
// init isotope
var $container = $('.isotope_container').isotope({
itemSelector: '.isotope_image',
layoutMode: 'fitRows',
transitionDuration: '0.7s'
});
// reveal initial images
$container.isotopeImagesReveal($('#images_container').find('.isotope_image'));
});
$.fn.isotopeImagesReveal = function( $items ) {
var iso = this.data('isotope');
var itemSelector = iso.options.itemSelector;
// hide by default
$items.hide();
// append to container
this.append( $items );
$items.imagesLoaded().progress( function( imgLoad, image ) {
// get item
// image is imagesLoaded class, not <img>, <img> is image.img
var $item = $( image.img ).parents( itemSelector );
// un-hide item
$item.show();
// isotope does its thing
iso.appended( $item );
});
return this;
};
});
The code above already does to some extent what I am after. It 'pulls' the images initially present in the <div id='images_container'>, and appends an item to isotope once an image has finished loading. The problem however is that the code appends and shows images in the order they finish loading (image loaded first becomes #1 in grid, then #2 etc.). Adding the sortby parameter to the isotope options does not work, as the images are not loaded at the point isotope is initiated. Re-sorting them with isotope after all images have been appended this way is possible, but looks very messy.
What I would like to achieve is to have the images loaded in the order they are present in the <div id='images_container'>. Chronologically when it comes to the original document order so to say. So basically start loading image 1, show and append it once it has been loaded. Then proceed to image 2, show and append it after loading, etc. until all images have been processed.
I think the solution is to alter the $.fn.isotopeImagesReveal function to process each of the div items in chronological order, but I can't figure out how.
Update: added example of current code. http://codepen.io/micksanders/pen/KwXmwO
Firstly you need to add a sorting field to your markup. I added a data-order="xxxx" attribute to all elements with the .isotope_image class, like so:
<div class='isotope_image' data-order="1">
<p>1</p>
<img src='http://lorempixel.com/600/600/sports'>
</div>
...
Then you need to add that sorting field to your isotope initialisation code... both the getSortData and sortBy options are needed:
var $container = $('.isotope_container').isotope({
itemSelector: '.isotope_image',
layoutMode: 'fitRows',
transitionDuration: '0.7s',
getSortData: {
order: "[data-order]"
},
sortBy: 'order'
});
Finally at the end of your imagesLoaded.progress() function, use iso.insert($item) instead of iso.appended($item).
Here's the full amended code:
http://codepen.io/BenStevens/pen/MYEmBb
$( function() {
var $container = $('#container').isotope({
itemSelector: '.item',
masonry: {
columnWidth: 200
}
});
$('#load-images').click( function() {
var $items = getItems();
$container.isotopeImagesReveal( $items );
});
});
$.fn.isotopeImagesReveal = function( $items ) {
var iso = this.data('isotope');
var itemSelector = iso.options.itemSelector;
// hide by default
$items.hide();
// append to container
this.append( $items );
$items.imagesLoaded().progress( function( imgLoad, image ) {
// get item
// image is imagesLoaded class, not <img>, <img> is image.img
var $item = $( image.img ).parents( itemSelector );
// un-hide item
$item.show();
// isotope does its thing
iso.appended( $item );
});
return this;
};
function randomInt( min, max ) {
return Math.floor( Math.random() * max + min );
}
function getItem() {
var width = randomInt( 150, 400 );
var height = randomInt( 150, 250 );
var item = '<div class="item">'+
'<img src="http://lorempixel.com/' +
width + '/' + height + '/nature" /></div>';
return item;
}
function getItems() {
var items = '';
for ( var i=0; i < 12; i++ ) {
items += getItem();
}
// return jQuery object
return $( items );
}
See reveal each image as they load
I recently ran into some problems trying to setup Infinite scroll on my tumblr with masonry. I found some code, and it worked perfectly on the demo website: http://www.jquery4u.com/demos/infinite-scrolling-demo1/ But on my tumblr only the Masonry part works, but not the infinite scrolling part. Here is my Javascript:
<script>
$(function(){
var $container = $('SECTION');
$container.imagesLoaded(function () {
$container.masonry({
itemSelector: '.item',
columnWidth: '.item',
isFitWidth: true
});
});
$container.infinitescroll({
navSelector : '#page-nav', // selector for the paged navigation
nextSelector : '#nextPage', // 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 });
msnry.appended( $newElems );
});
}
);
});
</script>
Here is the html for the next Page link:
{block:Pagination}
<nav id="page-nav">
{block:NextPage}
<a style="color:red;" id="nextPage" href="{NextPage}">Next</a>
{/block:NextPage}
</nav>
{/block:Pagination}
I do already have the Masonry, ImageLoaded, and Infinite Scrolling scripts linked. As I said, The masonry works fine, but the infinite scroll seems to be doing nothing at all. The next link is also working too, since I tested it and it does take me to the next page. But again the Infinite scrolling does nothing whatsoever. If anyone could help it would be very appreciated, or if you have any other suggestions or alternatives, that would also be nice.
Its hard to tell without a demo link, but looking at the example you used for reference:
msnry.appended( $newElems );
There should throw an error saying undefined. This is due to msnry.appended.
The line should be:
$container.masonry( 'appended', $newElems, true );
Source: http://www.jquery4u.com/demos/infinite-scrolling-demo1/