angular-masonry
angular-masonry copied to clipboard
If imagesLoaded calls its callback in the same tick, the display is corrupted
This happens if the images are already cached and causes the images to overlap until either a resize or a manual $(element).masonry('layout') is triggered.

Workarounds: Set the height and width of images before they are loaded or disable the imagesLoaded cache.
I've runned into the same problem, we use a library that resizes the images dynamically. How do you disable the imageLoaded cache?
@goldnarms hey would you mind sharing the library you've used, I came accross the same issue :) thanks.
I have this problem and setting the width and height of each image is not an option for me and I can't seem to find any information on that imagesloaded cache.
@mafrost Is it possible to disable ImagesLoaded cache?
@rmariuzzo Nah, not exactly, at least it didn't work for me. I found this pull request over at ImagesLoaded github though: https://github.com/nyroDev/imagesloaded/commit/51288c54bca5b36137d3065a6b45dee6f02a2a90 where nyroDev posts a fix. It works great for me since the problem has not reoccured.
Thanks @mafrost you have solved all my problems! :thumbsup:
I'm having this issue and the patch to ImagesLoaded doesn't seem to help.
Here is an example: http://www.youngbloods.org/estate-sale Notice how items overlap each other until you resize the page enough to case the layout to change.
@cayblood I worked around the problem by making a direct call to to the layout method on the masonry instance after angular-masonry has done doing its thing.
I found that angular-masonry wasn't handling image addition very well and wasn't giving the masonry instance enough time to relayout the page after adding all images to the container. I worked around having to make multiple calls to masonry by wrapping the call in a $timeout and basically waiting until angular-masonry fired the last layoutComplete event and then manually triggered it one more time. This works about 90% of the time and definitely isn't a great fix, but it's doable for me. Here's my code
Thanks @FoxxMD. I'm going to see if I can accomplish something similar without having to create my own directive.
Hi everybody. Had the same issue, here is what helped:
in controller, you can call
setTimeout(function(){ $rootScope.$broadcast('masonry.reload'); }, 1000);
So it will make your masonry reload after all the images were loaded.
Thanks @youanswer, your solution was great, I use it in several places in my app!
However, I think the timeout duration needs to be longer on slower devices or on narrow bandwidth. I keep getting complaints that on mobiles and even on some desktops the lists appear scrambled on first load (by entering URL directly in the address bar) but they seem to work fine after navigating away and then coming back to the list (probably because the resources are already loaded at that time).
I think that setting a higher timeout (device-dependent) would break user experience.
Anyone encountered these kind of "random" problems? How are your lists on smartphones?
@rbosneag I used @youanswer's timeout workaround, but getting the timeout duration right on devices on low-speed internet is tricky. I ended up tracking the load events of all images in the masonry bricks and triggering a reload when all the images have loaded. It's a crude way of triggering a reload, but it seems to do the trick on all devices.
A directive to call a function on load event
angular.module('sbLoad', []) //Credit: http://stackoverflow.com/a/26781900/293847
.directive('onImgLoad', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
var fn = $parse(attrs.onImgLoad);
elem.on('load', function (event) {
scope.$apply(function() {
fn(scope, { $event: event });
});
});
}
};
}]);
on-img-load in HTML
<div masonry reload-on-show class="artists-container">
<div class="artist-wrapper masonry-brick" ng-repeat="artist in artists">
<img class="artist" ng-src="{{artist.image}}" on-img-load="notifyImgLoad($index)"/>
<h2 class="name">{{artist.name}}</h2>
</div>
</div>
Calling masonry.reload when all images have loaded
var loadedCount = 0;
$scope.notifyImgLoad = function(index) {
loadedCount++;
if (loadedCount === $scope.artists.length) {
console.log('Triggering reload');
$rootScope.$broadcast('masonry.reload');
}
};
Plunkr here
@vinaygopinath: I previously tried a solution similar to yours but it didn't work well, it appears that your code solves the problem (disregarding the flickering in the page).
Now the problem is with the Back button: if you click an artist (or change the route to anything) and then go back, the onLoad event is fired immediately because the images are cached so the masonry.refresh event is emitted sooner than it should. I might add a $timeout but this gets us back to where we started.
Do you have an issue on Back as well?
I'm also experiencing the images being overlapped when changing the view, then clicking Back. For me, it only happens if I don't specify a transitionDuration. Even a value of 0 solves the issue. No idea why, haven't looked much through the source code yet.
It works for me when I clicked on the tab it loads masonry with this code.
setTimeout(function () {
$rootScope.$broadcast('masonry.reload');
$scope.$apply();
}, 100);