I have divs that expand and contract when clicked on. The Masonry library has worked great for initializing the page. The problem I am experiencing is that with the absolute positioning in place from Masonry and the directive below, when divs expand they overlap with the divs below. I need to have the divs below the expanding div move down to deal with the expansion.
My sources are: http://masonry.desandro.com/
and
https://github.com/passy/angular-masonry/blob/master/src/angular-masonry.js
/*!
* angular-masonry <%= pkg.version %>
* Pascal Hartig, weluse GmbH, http://weluse.de/
* License: MIT
*/
(function () {
'use strict';
angular.module('wu.masonry', [])
.controller('MasonryCtrl', function controller($scope, $element, $timeout) {
var bricks = {};
var schedule = [];
var destroyed = false;
var self = this;
var timeout = null;
this.preserveOrder = false;
this.loadImages = true;
this.scheduleMasonryOnce = function scheduleMasonryOnce() {
var args = arguments;
var found = schedule.filter(function filterFn(item) {
return item[0] === args[0];
}).length > 0;
if (!found) {
this.scheduleMasonry.apply(null, arguments);
}
};
// Make sure it's only executed once within a reasonable time-frame in
// case multiple elements are removed or added at once.
this.scheduleMasonry = function scheduleMasonry() {
if (timeout) {
$timeout.cancel(timeout);
}
schedule.push([].slice.call(arguments));
timeout = $timeout(function runMasonry() {
if (destroyed) {
return;
}
schedule.forEach(function scheduleForEach(args) {
$element.masonry.apply($element, args);
});
schedule = [];
}, 30);
};
function defaultLoaded($element) {
$element.addClass('loaded');
}
this.appendBrick = function appendBrick(element, id) {
if (destroyed) {
return;
}
function _append() {
if (Object.keys(bricks).length === 0) {
$element.masonry('resize');
}
if (bricks[id] === undefined) {
// Keep track of added elements.
bricks[id] = true;
defaultLoaded(element);
$element.masonry('appended', element, true);
}
}
function _layout() {
// I wanted to make this dynamic but ran into huuuge memory leaks
// that I couldn't fix. If you know how to dynamically add a
// callback so one could say <masonry loaded="callback($element)">
// please submit a pull request!
self.scheduleMasonryOnce('layout');
}
if (!self.loadImages){
_append();
_layout();
} else if (self.preserveOrder) {
_append();
element.imagesLoaded(_layout);
} else {
element.imagesLoaded(function imagesLoaded() {
_append();
_layout();
});
}
};
this.removeBrick = function removeBrick(id, element) {
if (destroyed) {
return;
}
delete bricks[id];
$element.masonry('remove', element);
this.scheduleMasonryOnce('layout');
};
this.destroy = function destroy() {
destroyed = true;
if ($element.data('masonry')) {
// Gently uninitialize if still present
$element.masonry('destroy');
}
$scope.$emit('masonry.destroyed');
bricks = [];
};
this.reload = function reload() {
$element.masonry();
$scope.$emit('masonry.reloaded');
};
}).directive('masonry', function masonryDirective() {
return {
restrict: 'AE',
controller: 'MasonryCtrl',
link: {
pre: function preLink(scope, element, attrs, ctrl) {
var attrOptions = scope.$eval(attrs.masonry || attrs.masonryOptions);
var options = angular.extend({
itemSelector: attrs.itemSelector || '.masonry-brick',
columnWidth: parseInt(attrs.columnWidth, 10) || attrs.columnWidth
}, attrOptions || {});
element.masonry(options);
var loadImages = scope.$eval(attrs.loadImages);
ctrl.loadImages = loadImages !== false;
var preserveOrder = scope.$eval(attrs.preserveOrder);
ctrl.preserveOrder = (preserveOrder !== false && attrs.preserveOrder !== undefined);
scope.$emit('masonry.created', element);
scope.$on('$destroy', ctrl.destroy);
}
}
};
}).directive('masonryBrick', function masonryBrickDirective() {
return {
restrict: 'AC',
require: '^masonry',
scope: true,
link: {
pre: function preLink(scope, element, attrs, ctrl) {
var id = scope.$id, index;
ctrl.appendBrick(element, id);
element.on('$destroy', function () {
ctrl.removeBrick(id, element);
});
scope.$on('masonry.reload', function () {
ctrl.scheduleMasonryOnce('reloadItems');
ctrl.scheduleMasonryOnce('layout');
});
scope.$watch('$index', function () {
if (index !== undefined && index !== scope.$index) {
ctrl.scheduleMasonryOnce('reloadItems');
ctrl.scheduleMasonryOnce('layout');
}
index = scope.$index;
});
}
}
};
});
}());
Like with many non-Angular libraries, it appears the answer lies in wrapping the library in an Angular directive.
I haven't tried it out but it appears that is what this person did
You can use angular's $emit, $broadcast, and $on functionality.
Inside your masonry
directive link function:
scope.$on('$resizeMasonry', ctrl.scheduleMasonryOnce('layout'));
Inside your masonryBrick
directive link function or any other child element:
scope.$emit('$resizeMasonry');
Use $emit to send an event up the scope tree and $broadcast to send an event down the scope tree.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With