admin管理员组

文章数量:1404923

I am trying to get Masonry working as an Angular directive, which is in part documented online, although I am having the following issues on the following code:

HTML code:

<div ng-controller="GridCtrl" class="grid-wrapper">
    <div class="masonry">
        <div ng-repeat="item in gridItems" ng-class="item.class">
            <h3>{{item.name}}</h3>
            <img ng-src="{{item.image}}"/>
            <br>
            <button ng-repeat="button in item.buttons">{{button.text}}</button>
        </div>
    </div>
</div>

Angular directive code:

'use strict';

angular.module('HomeCourtArenaApp').directive('masonry', function ($parse) {
    return {
        restrict: 'AC',
        link: function (scope, elem, attrs) {
            elem.masonry({ itemSelector: '.masonry-item', columnWidth: $parse(attrs.masonry)(scope) });
        }
    };        
});

angular.module('HomeCourtArenaApp').directive('masonryItem', function () {
    return {
        restrict: 'AC',
        link: function (scope, elem, attrs) {
            elem.imagesLoaded(function () {
               elem.parents('.masonry').masonry('reload');
            });
        }
    };        
});

SCSS code:

.grid-wrapper {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    padding-left: 40%;
    overflow-x: scroll;
    overflow-y: hidden;
    .masonry {
        position: absolute;
        width: 2600px;
        max-height: 1080px;
        .masonry-item,
        .poster {
            float: left;
            width: 465px;
            padding: 15px;
            margin: 12px 12px 0 0;
            box-shadow: 1px 1px 4px 3px rgba(55,55,55,0.25);
        }
        .masonry-item {
            background: #fafafa;
            height: 295px;
            h3 {
                width: 100%;
                text-align: left;
                font-size: 28px;
                color: #3D444A;
                display: block;
            }
            img {
                display: block;
                padding: 50px 0 10px;
                margin: 0 auto;
            }
        }
        .poster {
            height: 631px;
            background: #000;
            position: relative;
            h3 {
                color: #fff;
                font-family: 'adineuebold';
                font-size: 68px;
                position: absolute;
                top: 410px;
                left: 20px;
                z-index: 2;
            }
            img {
                position: absolute;
                left: 0;
                top: 0;
                z-index: 1;
                margin: 0;
                padding: 0;
            }
            button {
                position: absolute;
                z-index: 2;
                left: 20px;
                top: 590px;
            }
        }
        button {
            padding: 12px 15px;
            font-size: 15px;
            margin-right: 10px;
            font-family: 'adihausregular';
            color: #fff;
            text-transform: uppercase;
            border: none;
            background: linear-gradient(to bottom,  rgba(57,134,202,1) 0%,rgba(3,75,146,1) 100%);
            &:after {
                content: "";
                background: url('img/sprite.png') no-repeat -156px -9px;
                width: 16px;
                height: 16px;
                margin-left: 30px;
                display: inline-block;
            }
        }
    }
}

Then also, crucially, how my scripts are layered in my index file:

<script src="scripts/app.js"></script>
<script src="scripts/directives/masonry.js"></script>
<script src="scripts/controllers/main.js"></script>

I keep getting an error in the console which would suggest, I am not defining the masonry somewhere correctly:

Uncaught TypeError: Cannot call method 'create' of undefined

Then also:

TypeError: Object [object Object] has no method 'masonry'

Can anyone see where I am going wrong?

I would like to avoid using JQuery, possibly, as there is a newer Masonry available that doesn't use it.

I am trying to get Masonry working as an Angular directive, which is in part documented online, although I am having the following issues on the following code:

HTML code:

<div ng-controller="GridCtrl" class="grid-wrapper">
    <div class="masonry">
        <div ng-repeat="item in gridItems" ng-class="item.class">
            <h3>{{item.name}}</h3>
            <img ng-src="{{item.image}}"/>
            <br>
            <button ng-repeat="button in item.buttons">{{button.text}}</button>
        </div>
    </div>
</div>

Angular directive code:

'use strict';

angular.module('HomeCourtArenaApp').directive('masonry', function ($parse) {
    return {
        restrict: 'AC',
        link: function (scope, elem, attrs) {
            elem.masonry({ itemSelector: '.masonry-item', columnWidth: $parse(attrs.masonry)(scope) });
        }
    };        
});

angular.module('HomeCourtArenaApp').directive('masonryItem', function () {
    return {
        restrict: 'AC',
        link: function (scope, elem, attrs) {
            elem.imagesLoaded(function () {
               elem.parents('.masonry').masonry('reload');
            });
        }
    };        
});

SCSS code:

.grid-wrapper {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    padding-left: 40%;
    overflow-x: scroll;
    overflow-y: hidden;
    .masonry {
        position: absolute;
        width: 2600px;
        max-height: 1080px;
        .masonry-item,
        .poster {
            float: left;
            width: 465px;
            padding: 15px;
            margin: 12px 12px 0 0;
            box-shadow: 1px 1px 4px 3px rgba(55,55,55,0.25);
        }
        .masonry-item {
            background: #fafafa;
            height: 295px;
            h3 {
                width: 100%;
                text-align: left;
                font-size: 28px;
                color: #3D444A;
                display: block;
            }
            img {
                display: block;
                padding: 50px 0 10px;
                margin: 0 auto;
            }
        }
        .poster {
            height: 631px;
            background: #000;
            position: relative;
            h3 {
                color: #fff;
                font-family: 'adineuebold';
                font-size: 68px;
                position: absolute;
                top: 410px;
                left: 20px;
                z-index: 2;
            }
            img {
                position: absolute;
                left: 0;
                top: 0;
                z-index: 1;
                margin: 0;
                padding: 0;
            }
            button {
                position: absolute;
                z-index: 2;
                left: 20px;
                top: 590px;
            }
        }
        button {
            padding: 12px 15px;
            font-size: 15px;
            margin-right: 10px;
            font-family: 'adihausregular';
            color: #fff;
            text-transform: uppercase;
            border: none;
            background: linear-gradient(to bottom,  rgba(57,134,202,1) 0%,rgba(3,75,146,1) 100%);
            &:after {
                content: "";
                background: url('img/sprite.png') no-repeat -156px -9px;
                width: 16px;
                height: 16px;
                margin-left: 30px;
                display: inline-block;
            }
        }
    }
}

Then also, crucially, how my scripts are layered in my index file:

<script src="scripts/app.js"></script>
<script src="scripts/directives/masonry.js"></script>
<script src="scripts/controllers/main.js"></script>

I keep getting an error in the console which would suggest, I am not defining the masonry somewhere correctly:

Uncaught TypeError: Cannot call method 'create' of undefined

Then also:

TypeError: Object [object Object] has no method 'masonry'

Can anyone see where I am going wrong?

I would like to avoid using JQuery, possibly, as there is a newer Masonry available that doesn't use it.

Share Improve this question edited Jun 18, 2013 at 13:45 Keren Caelen 1,4663 gold badges17 silver badges40 bronze badges asked Jun 18, 2013 at 12:58 JohnRobertPettJohnRobertPett 1,1834 gold badges22 silver badges37 bronze badges 6
  • Have you tried loading masonry.js before app.js? (Putting its <script> tag before app.js's in the file) – user2000008 Commented Jun 18, 2013 at 13:08
  • Tried that, then it can't define the actual 'app' module. – JohnRobertPett Commented Jun 18, 2013 at 13:11
  • The rabbit hole goes pretty deep mate - I ran into this problem myself recently. Have a look: stackoverflow./questions/16504151/masonry-with-angularjs – Dan Kanze Commented Jun 18, 2013 at 14:49
  • That is what I started with and could never get the directive working in my app! A deep hole, indeed! – JohnRobertPett Commented Jun 18, 2013 at 15:11
  • If you can see if this is replicating any of the errors you experience, please let me know: jsfiddle/ADukg/3154 – JohnRobertPett Commented Jun 18, 2013 at 15:52
 |  Show 1 more ment

2 Answers 2

Reset to default 4

Ok, so after a serious hack/play, I have a solution for this: Where AngularJS is creating the view elements on the fly, there are many opportunities for error if the the 'ng-repeat' loads slower than the creation of masonry elements. I am sure there are more Angular style responses to this, but this allows for clean mark up and less Javascript needing to be written to achieve what is needed. Just add this code as a directive, add your child selector and then add 'masonry' to the parent div of the grid in your view:

'use strict';

app.directive('masonry', function ($parse) {
    return {
        link: function (scope, elem, attrs) {   
            setTimeout(function() {
                $(".masonry").masonry({
                    itemSelector : ".masonry-item"
                });
            }, 0);
        }
    };        
});

It looks like you are not actually applying the directive within your html.

<div ng-controller="GridCtrl" class="grid-wrapper">
    <div class="masonry" masonry>
        <div ng-repeat="item in gridItems" ng-class="item.class" masonry-item>
            <h3>{{item.name}}</h3>
            <img ng-src="{{item.image}}"/>
            <br>
            <button ng-repeat="button in item.buttons">{{button.text}}</button>
        </div>
    </div>
</div>

It took me a while to make isotope work in my app, let me know if this helps and if the error you are receiving changes.

Also try and add the column width statically inside your directive for now and see what happens. The error TypeError: Object [object Object] has no method 'masonry' might relate to attrs.masonry:

angular.module('HomeCourtArenaApp').directive('masonry', function ($parse) {
    return {
        restrict: 'AC',
        link: function (scope, elem, attrs) {
            elem.masonry({ itemSelector: '.masonry-item', columnWidth: 200 });
        }
    };        
});

angular.module('HomeCourtArenaApp').directive('masonryItem', function () {
    return {
        restrict: 'AC',
        link: function (scope, elem, attrs) {
            elem.imagesLoaded(function () {
               elem.parents('.masonry').masonry('reload');
            });
        }
    };        
});

本文标签: javascriptAdding Masonry to Angular without JQueryStack Overflow