AngularJS + Masonry
HTML
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/masonry/2.1.08/jquery.masonry.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular.min.js"></script>
<div ng-controller="MainCtrl">
<input type="text" ng-model="nameFilter" />
<a href="#" ng-click="order = 'id'">Order by id</a>
<a href="#" ng-click="order = 'name'">Order by name</a>
<a href="#" ng-click="order = 'age'">Order by age</a>
<a href="#" ng-click="destroy = true">DESTROY</a>
<ul class="grid" masonry="true" ng-if="!destroy" item-selector="li:not(.zoom-leave)">
<li ng-repeat="item in items | filter: { name: nameFilter } | orderBy: order"
ng-animate="'zoom'">
<span>{{item.name}}</span>
<br /> <span>Age: {{item.age}}</span>
<br /> <span>Company: {{item.company}}</span>
</li>
</ul>
</div>
CSS
.grid {
border: solid 1px #ccc padding: 10px 10px 0 0;
}
.grid li {
display: inline-block;
width: 100px;
height: 100px;
border: solid 1px #ccc;
margin: 0 0 10px 10px;
background: #eee;
}
/**** Transitions ****/
.masonry, .masonry .masonry-brick {
-webkit-transition-duration: 0.7s;
transition-duration: 0.7s;
}
.masonry {
-webkit-transition-property: height, width;
-moz-transition-property: height, width;
-ms-transition-property: height, width;
-o-transition-property: height, width;
transition-property: height, width;
}
.masonry .masonry-brick {
-webkit-transition-property: all;
transition-property: all;
}
.grid li {
-wekit-transition: all .75s;
transition: all .75s;
}
.zoom-enter {
opacity: 0;
-webkit-transform: scale(0.1, 0.1);
transform: scale(0.1, 0.1);
}
.zoom-enter.zoom-enter-active {
opacity: 1;
-webkit-transform: scale(1, 1);
transform: scale(1, 1);
}
.zoom-leave {
opacity: 1;
-webkit-transform: scale(1, 1);
transform: scale(1, 1);
}
.zoom-leave.zoom-leave-active {
opacity: 0;
-webkit-transform: scale(0.1, 0.1);
transform: scale(0.1, 0.1);
}
JavaScript
angular.module('app', [])
.directive("masonry", function ($timeout) {
// todo: use compile to find attrs ngRepeat and ngAnimate in child
return function (scope, element, attrs) {
var options = {};
var init = false;
var reloadOn = null;
var oldDisplay = element.css("display");
element.css({
"display": "none"
});
// TODO: build item selector from ng-animate directive (li:not(.{{ngAnimate}}-leave))
if (attrs['itemSelector']) options.itemSelector = attrs['itemSelector'];
if (attrs['columnWidth']) options.columnWidth = attrs["columnWidth"];
if (attrs["isAnimated"]) options.isAnimated = true;
// reload when given model is updated
if (attrs["reloadOn"]) {
reloadOn = attrs["reloadOn"];
}
if (!attrs["reloadOn"]) { // try to find in ng-repeat
var elmHtml = element.html();
var ngRepeatMatch = elmHtml.match('<!-- ngRepeat: ((.*) in (.*)) -->');
if (ngRepeatMatch) {
reloadOn = ngRepeatMatch[3];
}
}
if (reloadOn) {
scope.$watch(reloadOn, function (_new, _old) {
if (init === true) {
$timeout(function () {
element.masonry("reload");
}, 100);
}
}, true);
}
// init masonry
element.ready(function () {
element.css("display", oldDisplay);
element.masonry(options);
init = true;
});
element.on("$destroy", function () {
element.masonry('destroy')
});
};
})
.controller('MainCtrl', function ($scope, $http) {
$scope.elements = [{
id: 1,
name: 'Jhon'
}];
$scope.items = $http.get('http://www.json-generator.com/j/dIxZ?indent=4')
.then(function (response) {
return response.data.result;
...