Reputation: 751
I am building a Backbone app using require.js for modular loading and Marionette to help with my application structuring and functionality. I have set up a require module for the event aggregator like this:-
define(['backbone', 'marionette'],function(Backbone, Marionette){
var ea = new Backbone.Wreqr.EventAggregator();
ea.on('all', function (e) { console.log("[EventAggregator] event: "+e);});
return ea;
});
I was hoping to pass it into my other require modules and have it function as a central event handling and messaging component and I am getting some success with this. I can pass the vent as a dependency into other modules without problem like so:-
define(['marionette', 'text!templates/nav.html', 'shell/vent'], function (Marionette, text, vent) {
return SplashView = Marionette.ItemView.extend({
template : text,
events : {
'click #splashContinueButton': 'onButtonClick'
},
onButtonClick : function(evt) {
vent.trigger('onSplashContinueClick');
}
});
});
The problem I am having is that although all the events are getting triggered across the different places in my app (which I can see in the console log), I am not able to listen to them in some parts of my app. For instance I have a Marionette module (loaded at runtime as a require module) which is trying to pick up some events like this:-
var SplashModule = shellApp.module("SplashModule");
SplashModule.addInitializer(function(){
vent.on("onSplashModelLoaded", this.onSplashModelLoaded);
vent.on("onSplashContinueClick", this.onSplashContinueClick);
}
I get nothing, even though if I log the vent from this place I can see it as an object. In the log, it contains an array of events that actually only contain the events being listened to by the root level application, not any other events that other parts of the app are listening for. And this is where my understanding falls apart: I thought I could use the event aggregator as a global communication and messaging system across my application structure. Can anyone please shed any insight into what might be going on?
Much thanks,
Sam
* UPDATE/EDIT/SOLUTION *
Hello, well, I have it working now (only 5 minutes after posting the above - doh!). Basically, adding my listeners in the initializer event of the module was too early (as far as I can tell). I moved them further along the chain of functions and now everything is behaving as expected.
Upvotes: 3
Views: 801
Reputation: 275
Using RequireJS also involves some clean modules... Backbone.Wreqr.EventAggregator is a module that is part of Marionette.js (for the record, Derrick Bailey just put this module that is made by someone else inside his library, same thing for Backbone.BabySitter) using RequireJS, you are limited to see what is exported by the library, and in this case Marionette I think the best way is to split marionette into the 3 modules it actually contains backbone.babysitter, backbone.wreqr, and marionette. Then you have to create a shim for each module
I used this
require.config({
baseUrl: "/Scripts/",
paths: {
"json2": "vendor/JSON2",
"backbone": "vendor/backbone/backbone.1.1.0",
"localStorage": "vendor/backbone/backbone.localStorage.1.1.9",
"marionette": "vendor/backbone/backbone.marionette.1.8.6",
"bootstrap": "vendor/bootstrap/bootstrap.3.1.1",
"jquery": "vendor/jquery/jquery.1.8.3",
"text": "vendor/Require/text.0.27.0",
"underscore": "vendor/underscore/underscore.1.5.2",
"wreqr": "vendor/backbone/backbone.wreqr",
"babysitter": "vendor/backbone/backbone.babysitter",
},
shim: {
"json2": {
exports: "JSON"
},
"jquery": {
exports: "$"
},
"underscore": {
exports: "_"
},
"bootstrap": {
deps: ["jquery"]
},
"backbone": {
deps: ["underscore", "jquery"],
exports: "Backbone"
},
"validation": {
deps: ["backbone"],
exports: "Backbone.Validation"
},
"wreqr": {
deps: ["backbone", "underscore"],
exports: "Backbone.Wreqr"
},
"marionette": {
deps: ["backbone", "babysitter", "wreqr"],
exports: "Backbone.Marionette"
},
"localStorage": {
deps: ["backbone"],
exports: "Backbone.LocalStorage"
}
}
});
once you have this, you will be able to use wreqr
There's another trick in your script, the fact you write
define(['backbone', 'marionette'],function(Backbone, Marionette){
is a bit disturbing, because you will never know if the use of Backbone or Marionette in your implementation is made on purpose or not. I mean, the namespaces related to backbone and marionette are Backbone and Marionette; I suggest you alias Backbone as backbone and Marionette as marionette like this:
define(['backbone', 'marionette'],function(backbone, marionette){
. Doing such , you will be able to check if your module has been downloaded on demand by RequireJS or not.
Then once the shim has been created, your first block code should look like this
define(["wreqr"],function(wreqr){
var ea = new wreqr.EventAggregator();
ea.on('all', function (e) { console.log("[EventAggregator] event: "+e);});
return ea;
});
Upvotes: 1
Reputation: 751
The change I had to make to get it working was that I had to remove the vent listener "onSplashContinueClick" within the module further along. Before this change, it was in the initializer function but now it is further along:-
define(["backbone", "marionette", "shell/vent", "shell/shellapp", "shell/splash/splashmodel", "shell/splash/splashview"], function(Backbone, Marionette, vent, shellApp, SplashModel, SplashView){
var SplashModule = shellApp.module("SplashModule");
SplashModule.addInitializer(function(){
trace("SplashModule.addInitializer()");
SplashModule.model = SplashModel;
SplashModule.model.fetch({
success:function(){
//trace("splashModel.fetch success")
SplashModule.onSplashModelLoaded();
},
error:function() {
//trace("splashModel.fetch error")
}
});
});
SplashModule.addFinalizer(function(){
});
SplashModule.initView = function () {
//trace("SplashModule.initView()");
SplashModule.mainView = new SplashView({model: SplashModel});
shellApp.mainRegion.show(SplashModule.mainView);
vent.on("onSplashContinueClick", this.onSplashContinueClick);
};
SplashModule.end = function () {
trace("SplashModule.end()");
shellApp.mainRegion.close();
vent.trigger("onSplashModuleComplete");
};
// events
SplashModule.onSplashModelLoaded = function () {
trace("SplashModule.onSplashModelLoaded");
SplashModule.initView();
};
SplashModule.onSplashContinueClick = function () {
trace("SplashModule.onSplashContinueClick()");
SplashModule.end();
};
return SplashModule;
});
I am guessing the problem has to do with the order of when dependencies are available and/or ready. I believe the vent was not ready for the listener during the initializer method. This may well be tied up to my usage of Marionette
modules within require modules.
Upvotes: 4