requireJS with JQuery, Masonry, & ImagesLoaded: Object [object Object] has no method 'imagesLoaded'
Asked Answered
H

5

6

RequireJS newbie here. Trying to convert some JQuery code I had working fine in the old way to work w/ RequireJS.

Header of my page loads three JS files via script tags -- require.js itself, my require.cfg.js, and boot/main.js with the site-specific functionality.

Relevant require.cfg.js excerpt:

,paths: {
    'boot': 'src/boot'
    ,'jquery': 'lib/jquery.min'
    ,'jquery.masonry': 'lib/plugins/masonry.pkgd.min'
    ,'jquery.imagesloaded': 'lib/plugins/imagesloaded.pkgd.min'
}

,shim: {
    'jquery': {
        exports: 'jQuery'
    }
    ,'jquery.masonry': ['jquery']
    ,'jquery.imagesloaded': ['jquery']
}

boot/main.js:

require([
'jquery',
'jquery.masonry',
'jquery.imagesloaded',
], function($) {

    // The following code worked just fine when I included it in the header of the page as-is
$(function() {

    var $container = $('#container');
    // This doesn't work
    $container.imagesLoaded(function() {
                    // Neither does this
            $('#container').masonry({itemSelector : '.item',});
        });

});

});

I can confirm that all of these JS files are being found and loaded by the browser. And I confirm that if I do:

require([
'jquery',
'jquery.masonry',
'jquery.imagesloaded',
], function($, Masonry, ImagesLoad) {

the Masonry and ImagesLoaded variables are set correctly.... but I don't want to proceed w/o jQuery

But when I try to call .imagesLoaded() and .masonry() on the JQuery container object, I get:

Uncaught TypeError: Object [object Object] has no method 'imagesLoaded'

And if I comment out the imagesLoaded line, I get:

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

Not sure what I'm doing wrong here...? From what I've read in other StackOverflow questions, the code looks correct to me...?

Thanks!

Update:

If I use this code the non-JQuery way like so, it works:

        var container = document.querySelector('#container');
        imagesLoaded(container, function() {
            var msnry = new Masonry( container, {
                itemSelector: '.item',
            });
        });
Heptad answered 18/8, 2013 at 3:41 Comment(6)
any test location where you have this running yet ?Showboat
Ummm, locally. :-) I'll put something together....Heptad
Please see reliqry.com/test. I tried to strip out all extraneous stuff... possible I introduced some other error in doing so... Thanks for taking a look!Heptad
Have you found a solution for this? Got the same issue!Commemorative
Alas, no. I ended up rewriting the code to work the non-JQuery way. I'll update my question to show what I did.Heptad
No, I still have not... I've been running it the non-JQuery way (the last part of my question), which does get thing working reliably in all browsers, so I moved on to something else. First time on SO that I'm getting so many "me, too!" comments, but no one can figure out what the issue is...Heptad
D
2

Try defining exports for each plugin in the shim too...

, paths: {
    boot: 'src/boot'
    , jquery: 'bower_components/jquery'
    , masonry: 'bower_components/masonry',
    , imagesloaded: 'bower_components/imagesloaded'
}
, shim: {
    jquery: {
        exports: 'jQuery'
    }
    , masonry: {
        deps : ['jquery'],
        exports : 'jQuery.masonry'
    }
    , imagesloaded: {
        deps : ['jquery'],
        exports : 'jQuery.imagesLoaded'
    }
}
Dissertate answered 1/9, 2013 at 20:35 Comment(2)
Interesting idea... unfortunately it resulted in the same error for me. (I had to make some modifications to your code... it turned out that part of the orig prob was that I didn't have the right versions of masonry & imagesLoaded for requireJS. So in paths I now have 'masonry': 'bower_components/masonry' and 'imagesloaded': 'bower_components/imagesloaded', so I changed your exports to 'masonry' and 'imagesLoaded.' Does that seem right to you?)Heptad
The exports property is the object that the module exposes for other code to use. A good example is the underscore js library which exports '_'. I've edited my answer to work with your new paths variables. Might be easiest to debug if you could create a jsFiddle for it though?Dissertate
S
0

Try this instead:

require([
'jquery',
'jquery.masonry',
'jquery.imagesloaded',
], function($, Masonry, ImagesLoad) {

    // The following code worked just fine when I included it in the header of the page as-is
$(function() {

    var $container = $('#container');
    // This doesn't work
    $container.imagesLoaded(function() {
                    // Neither does this
            $('#container').masonry({itemSelector : '.item',});
        });

});

});
Showboat answered 18/8, 2013 at 4:14 Comment(1)
Thanks for the thought -- I tried that, too. If you look in the third gray box in my orig question, I did try that. Masonry and ImagesLoaded do seem to get set correctly, but I can't do anything w/ them unless I rewrite the orig code to work non-JQuery style...Heptad
T
0

Ok, I think I have the answer to your problem (and mine!).

If you're installing the versions hosted on github, you're probably installing the "vanilla" version, not the jquery plugin. That's what you'll be doing if you install via bower, for example, which is what I was doing.

Here's what I found with a search on bower:

% bower search masonry
# jquery-masonry git://github.com/desandro/masonry
# masonry git://github.com/desandro/masonry.git
# $.masonry git://github.com/tysoncadenhead/masonry
# angular-masonry git://github.com/passy/angular-masonry.git
# jquery.masonry git://github.com/tysoncadenhead/masonry.git

AFAICT, jquery-masonry, $.masonry and jquery.masonry are all pointing to the same source (in two different locations), and it's not the jquery plugin it's just the "vanilla" version of masonry.

Instead, just download from here and extract the file jquery.masonry.js, but it in your assets path, and add a shim for it with a dependency on jquery.

After you do all that, it should work. Of course since it's not installed through bower, you can't manage dependencies as you would with other bower packages. I honestly don't understand what's going on but it looks like a problem on the package-maintainer's side.

Hope that helps.

UPDATE: Although the above works, note that the version downloaded from meta.metafizzy.co is quite old and depends on an outdated version of jquery. I think I'm just going to go with the vanilla version, it seems that the plugin is not being maintained.

Tellurium answered 13/10, 2013 at 6:6 Comment(0)
O
0

Try using jquery-bridget: https://github.com/desandro/jquery-bridget to convert masonry to a jquery plugin. I created a new js file that gets loaded by requirejs to ensure it is converted before the application starts running:

//masonry-config.js:
'use strict'

define(['jquery-bridget', 'masonry'], function(Bridget, Masonry){
    Bridget('masonry', Masonry );
});   

Then in my requirejs file

//main.js
require.config({
   paths: {
       'masonry-config': 'masonry-config'
       .....
   },
   shim: {  
       'angular-masonry': ['angular', 'masonry'],
       'angular' : {
         deps: ['imagesloaded', 'masonry-config'],
         exports: 'angular'
       },
       'masonry': ['imagesloaded'],
   } 
}

This is for my app using angular and angular-masonry (with masonry) so you might need to config a little differently but hopefully that give you some idea.

Ornithine answered 11/1, 2014 at 20:55 Comment(1)
This tip was helpful! Got it to work. HOWEVER, I had to make one modification and added to masonry-config.js: Bridget('imagesLoaded', imagesLoaded );Druse
N
0

In our particular case we had RequireJS included and configured in our main template, but wanted to include Masonry/ImagesLoaded on one particular page.

We kept our code in the template:

<script type="text/javascript" src="/path/to/require.min.js"></script>
<script type="text/javascript">
    require.config({
        waitSeconds: 0,
        paths: {
            'jquery': "/path/to/jquery.min",
            // ...
        },
        shim: {
            // ...
        }
    });
    require(["jquery", /* ... */], function ($) {
        // ...
    });
</script>

Then we included a JavaScript file after this, on the page that used Masonry, that triggered Masonry/ImagesLoaded:

requirejs(['jquery', 'https://unpkg.com/[email protected]/dist/masonry.pkgd.min.js', 'https://unpkg.com/[email protected]/imagesloaded.pkgd.min.js'],
    function ($, Masonry, ImagesLoaded) {
        $(document).ready(function () {
            ImagesLoaded('.js-masonry', function () {
                new Masonry('.js-masonry', {
                    // This was required for us, but from what I can tell shouldn't need to be/may need to be updated per-usage.
                    itemSelector: '.item'
                });
            });
        });
    }
);

I'm sure this could be further optimized, but it resolved the errors and didn't require any new packages to be included.

Neutralism answered 15/3, 2019 at 18:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.