Bad masonry element: null - using wordpress - javascript

I am writing a wordpress plugin in php. In that plugin I output pictures with a little text and want to do that with masonry.
When I initialize masonry in HTML, it seems to work, but the pictures overlap:
<div id="container" class="js-masonry" data-masonry-options='{ "columnWidth": 200, "itemSelector": ".item" }'>
Therefore I am trying to use "Imagesloaded" (by the same developer?).
But as I see it, before I can use ImagesLoaded I need to get Masonry up and running with javascript. When I initialize Masonry in my plugin_scripts.js I get an error on the frontend:
plugin_scripts.js:
jQuery(function() {
alert("hallo");
var container = document.querySelector('#container');
var msnry = new Masonry( container, {
// options
columnWidth: 200,
itemSelector: '.item'
});
});
Console Error in Frontend:
Bad masonry element: null
masonry.min.js?ver=3.1.2:1
q masonry.min.js?ver=3.1.2:1
d masonry.min.js?ver=3.1.2:1
(anonymous function) schnoogle_scripts_frontend.js?ver=3.9.2:10
j jquery.js?ver=1.11.0:2
k.fireWith jquery.js?ver=1.11.0:2
n.extend.ready jquery.js?ver=1.11.0:2
K jquery.js?ver=1.11.0:2
Can you help?

window.onload = function(){
//call masonry
}
You should load html before call masonry so query selector can find query

It looks like Masonry can't find your container for some reason. I assume you've tried the obvious, such as making sure #container is actually on the page.
If you're using jQuery (which you are), you can use jQuery's selector engine.
var $container = $('#container');
// initialize
$container.masonry({
columnWidth: 200,
itemSelector: '.item'
});
Ensure this is within a document.ready call, so that you're doing it after the rest of the page is ready.

if using vanilla js in WordPress, if you enqueue a script it's everywhere. to solve this I query to see if the element is on the page for initializing Masonry.
var masonry_element = document.querySelector( '.masonry' );
if( typeof( masonry_element ) != 'undefined' && masonry_element != null ){
var msnry = new Masonry( '.masonry', { ... } );
}

Related

isotope plugin fails to load properly, and cuts off div

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

Isotope: append each image after loading (in chronological order)

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

Setting up infinite scroll

I am trying to set up infinite scroll for days now on my site.
Finally i found a plugin that almost works - jetpack.
PROBLEM: When you scroll down, freshly loaded posts are put on top of the displayed ones.
SOLVED...solution see answer
How do we solve this?
SOLUTION SUGGESTION? Maybe it has to do with the fact that my theme uses java-masonry for the grid display and I found this tutorial page providing code snippets to deal with that.
Maybe I enqueued them wrong?
I added this in the bottom of my functions.php to enqueue the script and configure jetpack
// Jetpack infinite js addon
wp_register_script('ininite-addon', (get_template_directory_uri()."/js/infinite-addon.js"),'infinite-addon',false,true);
wp_enqueue_script('infinite-addon');
// Jetpack infinite scroll
add_theme_support( 'infinite-scroll', array(
'container' => 'post-area',
'footer' => 'footer',
'wrapper' => false,
'posts_per_page' => '7',
) );
and this is the file I created called infinite-addon.js according to the tutorial mentioned above:
jQuery( document ).ready( function( $ ) {
infinite_count = 0;
// Triggers re-layout on infinite scroll
$( document.body ).on( 'post-load', function () {
infinite_count = infinite_count + 1;
var $container = $('#content');
var $selector = $('#infinite-view-' + infinite_count);
var $elements = $selector.find('.hentry');
$elements.hide();
$container.masonry( 'appended', $elements, true );
$elements.fadeIn();
});
});
Thank you SO MUCH for any help !!! And let me know if you need more of my code!
Solved the problem.
I found a file called funtions.js in my theme's /js/ directory which contained the following code, obviously for making masonry work:
$(document).ready(function() {
$('#post-area').masonry({
// options
itemSelector : '.post',
// options...
isAnimated: true,
animationOptions: {
duration: 400,
easing: 'linear',
queue: false
}
});
});
I just deleted this and replaced it with the snippet above, and now it works like magic!

Masonry not working using ajax and infinite scroll

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>

center single column in Masonry layout

I'm using the jquery/css masonry layout for a menu layout. Some menu pages only have one column so I need to centre the column, any idea how to do this? Currently using the following javascript:
<script>
var msnry;
function triggerMasonry() {
// don't proceed if masonry has not been initialized
if ( !msnry ) {
return;
}
msnry.layout();
}
// initialize masonry on document ready
docReady( function() {
var container = document.querySelector('.menu-columns');
msnry = new Masonry( container, {
gutter: 10
});
});
// trigger masonry when fonts have loaded
Typekit.load({
active: triggerMasonry,
inactive: triggerMasonry
});
</script>
You can add empty or hidden bricks to replace the wanted column.

Categories

Resources