I just got started using Marionette and I'm reading and following along Marionette - A Gentle Introduction by David Sulc. It's a really good read and it's easy to follow along building the sample application Contact Manager with the companion repository.
However, I had previously set up a project using RequireJS and wanted to translate and integrate the ideas and concepts of that book into this project. I haven't actually gotten that far and I think I might be a little bit confused about the use of Marionette Modules in combination with AMD modules which leads to undefined
objects.
To be more specific, let me list app.js
, listView.js
and listController.js
which should be the RequireJS version of this commit of the sample repo.
app.js
/*global define*/
define([
'marionette'
], function ( Marionette ) {
'use strict';
var ContactManager = new Marionette.Application();
ContactManager.addRegions({
mainRegion : '#main-region'
});
ContactManager.on( 'initialize:after', function() {
ContactManager.ContactsApp.List.Controller.listContacts();
});
return ContactManager;
});
listView.js
/*global define*/
define([
'app',
'marionette',
'handlebars',
'text!templates/contact.hbs'
], function ( ContactManager, Marionette, Handlebars, contactTemplate ) {
'use strict';
var List = ContactManager.module( 'ContactsApp.List' );
List.Contact = Marionette.ItemView.extend({
tagName: 'li',
template : Handlebars.compile( contactTemplate ),
});
List.Contacts = Marionette.CollectionView.extend({
tagName: 'ul',
itemView: List.Contact
});
return List;
});
listController.js
/*global define*/
define([
'app'
], function ( ContactManager ) {
'use strict';
var List = ContactManager.module( 'ContactsApp.List');
List.Controller = {
listContacts: function() {
var contacts = ContactManager.request('contact:entities');
var contactsListView = new ContactManager.ContactsApp.List.Contacts({
collection: contacts
});
ContactManager.mainRegion.show( contactsListView );
}
};
return List.Controller;
});
So, the error I get is Uncaught TypeError: Cannot read property 'List' of undefined
in app.js:15
which refers to this line:
ContactManager.ContactsApp.List.Controller.listContacts();
This means that the ContactsApp
module is undefined
and this is exactly what I don't understand.
To my understanding I attach the ContactsApp
module and the List
sub-module to the ContactManager
inside either listView.js
or listController.js
(whichever is called first) with the line:
ContactManager.module( 'ContactsApp.List' );
Shouldn't the ContactsApp
be defined inside app.js
then?
This is the main.js file which includes the require.config
and the entry point to the application:
require.config({
baseUrl: './scripts',
paths: {
jquery : '../bower_components/jquery/jquery',
underscore : '../bower_components/underscore/underscore',
backbone : '../bower_components/backbone/backbone',
marionette : '../bower_components/backbone.marionette/lib/backbone.marionette',
bootstrap : '../bower_components/sass-bootstrap/dist/js/bootstrap',
text : '../bower_components/requirejs-text/text',
handlebars : '../bower_components/handlebars/handlebars',
templates : '../templates'
},
shim: {
underscore : {
exports : '_'
},
backbone : {
deps : [ 'underscore', 'jquery' ],
exports : 'Backbone'
},
marionette : {
deps : [ 'backbone' ],
exports : 'Backbone.Marionette'
},
bootstrap : {
deps : [ 'jquery' ],
},
handlebars : {
exports : 'Handlebars'
}
},
deps : [ 'jquery', 'underscore' ]
});
require([
'app',
'bootstrap'
], function ( ContactManager ) {
'use strict';
ContactManager.start();
});
RequireJS bascially works like this: declare all the dependencies a given module has, then use them within the call back function.
Here's the issue with your code: in app.js
, you require only marionette
so as far as RequireJS is concerned, nothing else should be loaded for the module's code to be functional. But then, in that same file, you call ContactManager.ContactsApp.List.Controller.listContacts()
. Where does that come from? Nowhere: it isn't defined within the current module, and wasn't declared as a dependency. Therefore, it doesn't exist and you get the undefined
issue.
You can't just refer to the module, thinking it's attached to the main application: it only actually gets attached when the Marionette module code gets executed. And for that to happen, it needs to be required as a dependency.
As an aside, you'll have a tough time adapting the book's code to use with RequireJS, because it isn't architected for RequireJS use (in addition to the issue you ran into, you'll have circular dependencies, etc.).
I'd suggest you just read along the book to get a good feel for Marionette on its own, then look into using it with RequireJS. Shameless plug, I also wrote a book on marionette and requirejs.
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