Angular with Masonry Sorting

by ian_smithz

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/masonry/2.1.08/jquery.masonry.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.5/angular.min.js"></script>
<div class="container">
    <div ng-controller="MainCtrl">
            <div class="row">
                <div class="col-xs-1"></div>
                <div class="col-xs-5">
                    <input type="text" class="form-control col-sm-6" placeholder="filter by title" ng-model="nameFilter" />
                </div>
                <!-- Single button -->
                <div class="btn-group col-xs-5">
                    <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Sort by .. <span class="caret"></span>

                    </button>
                    <ul class="dropdown-menu">
                        <li>
                            <li> <a href="#" ng-click="changeSort('created')">Sort by last edited</a>

                            </li>
                            <li> <a href="#" ng-click="changeSort('title')">Sort by title</a>

                            </li>
                            <li><a href="#" ng-click="changeSort('url')">Sort by url</a>

                            </li>
                    </ul>
                </div>
        </div>
        <br />
        <hr />
        <ul class="grid" masonry="true">
            <li ng-repeat="item in items | filter: { title: nameFilter } | orderBy:sort:reverse: order"><span>Fiddle Title: </span> 
                <br />
                 <h5> <a href="http:{{item.url}}" target="_blank"><span>{{item.title}}</span></a></h5>
 <span>Framework: <strong>{{item.framework}}</strong></span>

                <br />
                <br />
                <!--br />...

CSS

body{padding:20px}
.grid {
    border: solid 1px #ccc padding: 10px 10px 0 0;
}
.grid li {
    display: inline-block;
    width: 200px;
    height: 100px;
    padding:5px;
    border: solid 1px #ccc;
    margin: 0 0 10px 10px;
    background: #f6f6f6;
}
.grid li img {
    margin-left:35%;
    margin-top:5px
}
/**** Transitions ****/
 .masonry, .masonry li {
    /* apply before masonry add class */
    position: absolute;
    /* important to add it before enter animation start */
    -webkit-transition-duration: .7s;
    transition-duration: .7s;
    -webkit-transition-property: all;
    transition-property: all;
}
.masonry .masonry-enter {
    /* limit animated properties for entering elements */
    -webkit-transition-property: -webkit-transform, opacity;
    transition-property: transform, opacity;
}
.masonry-enter, .masonry-leave.masonry-leave-active {
    opacity: 0;
    -webkit-transform: scale(0.1);
    transform: scale(0.1);
}
.masonry-leave, .masonry-enter.masonry-enter-active {
    opacity: 1;
    -webkit-transform: scale(1);
    transform: scale(1);
}

JavaScript

angular.module('app', [])
    .directive("masonry", function () {
    var NGREPEAT_SOURCE_RE = '<!-- ngRepeat: ((.*) in ((.*?)( track by (.*))?)) -->';
    return {
        compile: function (element, attrs) {
            // auto add animation to brick element
            var animation = attrs.ngAnimate || "'masonry'";
            var $brick = element.children();
            $brick.attr("ng-animate", animation);

            // generate item selector (exclude leaving items)
            var type = $brick.prop('tagName');
            var itemSelector = type + ":not([class$='-leave-active'])";

            return function (scope, element, attrs) {
                var options = angular.extend({
                    itemSelector: itemSelector
                }, scope.$eval(attrs.masonry));

                // try to infer model from ngRepeat
                if (!options.model) {
                    var ngRepeatMatch = element.html().match(NGREPEAT_SOURCE_RE);
                    if (ngRepeatMatch) {
                        options.model = ngRepeatMatch[4];
                    }
                }

                // initial animation
                element.addClass('masonry');

                // Wait inside directives to render
                setTimeout(function () {
                    element.masonry(options);

                    element.on("$destroy", function () {
                        element.masonry('destroy')
                    });

                    if (options.model) {
                        scope.$apply(function () {
                            scope.$watchCollection(options.model, function (_new, _old) {
                                if (_new == _old) return;

                                // Wait inside directives to render
                                setTimeout(function () {
                                    element.masonry("reload");
                                });
                            });
                        });
        ...