I have a Backbone Marionette application whose layout's regions are not working properly. My app is structured using Require modules and some of these modules' regions are failing to close themselves when the module has been returned to a second time. The first time through the regions are closing as expected but upon return the layout object no longer contains the region objects it did during the first visit: I am using the browser debugger to ascertain this difference.
Here is my Module code:-
define(["marionette", "shell/shellapp", "interaction/videoreveal/model", "interaction/videoreveal/controller", "utils/loadingview", "utils/imagepreloader"], function(Marionette, shellApp, Model, Controller, LoadingView, imagePreloader){
var currentModuleModel = shellApp.model.get("currentInteractionModel"); // get module name from menu model
var Module = shellApp.module(currentModuleModel.get("moduleName")); // set application module name from menu model
Module.init = function() { // init function called by shell
//trace("Module.init()");
Module.model = new Model(shellApp.interactionModuleData); // pass in loaded data
Module.controller = new Controller({model: Module.model, mainRegion:shellApp.mainRegion}); // pass in loaded data and region for layout
Module.initMain();
};
Module.initMain = function() {
trace("Module.initMain()");
shellApp.mainRegion.show(new LoadingView());
// do some preloading
var imageURLs = this.model.get('imagesToLoad');
imagePreloader.preload(imageURLs, this.show, this);
};
Module.show = function() {
Module.controller.show();
};
Module.addInitializer(function(){
//trace("Module.addInitializer()");
});
Module.addFinalizer(function(){
//trace("Module.addFinalizer()");
});
return Module;
});
Here is the Controller class which is handling the Layout and Views:-
define(["marionette", "shell/vent", "shell/shellapp", "interaction/videoreveal/layout", "interaction/videoreveal/views/mainview", "ui/feedbackview", "ui/videoview"], function(Marionette, vent, shellApp, Layout, MainView, FeedbackView, VideoView){
return Marionette.Controller.extend({
initialize: function(options){
trace("controller.initialize()");
// store a region that will be used to show the stuff rendered by this component
this.mainRegion = options.mainRegion;
this.model = options.model;
this.model.on("model:updated", this.onModelUpdate, this);
this.layout = new Layout();
this.layout.render();
this.mainView = new MainView({model:this.model, controller:this});
this.feedbackView = new FeedbackView({feedbackBoxID:"vrFeedbackBox"});
this.videoView = new VideoView({videoContainerID:"vrVideoPlayer"});
vent.on("feedbackview:buttonclicked", this.onFeedbackClick, this);
vent.on("videoview:buttonclicked", this.onVideoClick, this);
},
// call the "show" method to get this thing on screen
show: function(){
// get the layout and show it
this.mainRegion.show(this.layout);
this.model.initInteraction();
},
initFeedback: function (index) {
this.model.set("currentItem", this.model.itemCollection.models[index]);
this.model.set("itemIndex", index);
this.model.initFeedback();
},
initVideo: function (index) {
this.model.set("currentItem", this.model.itemCollection.models[index]);
this.model.set("itemIndex", index);
this.model.initVideo();
},
finalizer: function() {
this.layout.close();
},
// events
onFeedbackClick: function(e) {
this.layout.overlayRegion.close();
},
onVideoClick: function(e) {
this.layout.overlayRegion.close();
},
onFinishClick: function() {
this.model.endInteraction();
},
onFeedbackClosed: function() {
this.layout.overlayRegion.off("close", this.onFeedbackClosed, this);
if (this.model.get("currentItem").get("correct") === true) {
this.model.initThumb();
}
},
onModelUpdate: function() {
trace("controller onModelUpdate()");
switch (this.model.get("mode")) {
case "initInteraction":
this.layout.mainRegion.show(this.mainView);
break;
case "initFeedback":
this.layout.overlayRegion.on("close", this.onFeedbackClosed, this);
this.feedbackView = new FeedbackView({feedbackBoxID:"vrFeedbackBox"})
this.feedbackView.setContent(this.model.get("currentItem").get("feedback"));
this.layout.overlayRegion.show(this.feedbackView );
break;
case "initVideo":
this.layout.overlayRegion.show(new VideoView({videoContainerID:"vrVideoPlayer"}));
break;
case "interactionComplete":
vent.trigger('interactionmodule:completed', this);
vent.trigger('interactionmodule:ended', this);
break;
}
}
});
});
Here is the FeedbackView class:-
define(['marionette', 'tweenmax', 'text!templates/ui/feedbackWithScrim.html', 'shell/vent'], function (Marionette, TweenMax, text, vent) {
return Marionette.ItemView.extend({
template: text,
initialize: function (options) {
this.model = options.model;
this.content = options.content; // content to add to box
this.feedbackBoxID = options.feedbackBoxID; // id to add to feedback box
this.hideScrim = options.hideScrim; // option to fully hide scrim
},
ui: {
feedbackBox: '.feedbackBox',
scrimBackground: '.scrimBackground'
},
events : {
'click button': 'onButtonClick' // any button events within scope will be caught and then relayed out using the vent
},
setContent: function(content) {
this.content = content;
},
// events
onRender: function () {
this.ui.feedbackBox.attr("id", this.feedbackBoxID);
this.ui.feedbackBox.html(this.content);
if (this.hideScrim) this.ui.scrimBackground.css("display", "none");
this.$el.css('visibility', 'hidden');
var tween;
tween = new TweenMax.to(this.$el,0.5,{autoAlpha:1});
},
onButtonClick: function(e) {
trace("onButtonClick(): "+ e.target.id);
vent.trigger("feedbackview:buttonclicked", e.target.id) // listen to this to catch any button events you want
},
onShow : function(evt) {
this.delegateEvents(); // when rerendering an existing view the events get lost in this instance. This fixes it.
}
});
});
Any idea why the region is not being retained in the layout when the module is restarted or what I can do to correct this?
Much thanks,
Sam
show
call. So what's going on is that when one of your other modules'layout
is shown, this module'slayout
isclose
d, making it unusable as @ekeren states below. I'll go ahead and add an answer with specific suggestions. – Chris Camaratta