Reputation: 18909
I'm porting a web service into a single-page webapp with Backbone. There is a basic layout consisting on a header, an empty div#content
where I'm attaching the views and a footer.
Every route creates the corresponding view and attachtes it to div#content
replacing the view that was rendered before with the new one.
I'm using require.js
to load the backbone app and it's dependencies.
All Backbone code is pretty small, only one file as I'm only using a router and a view.
This AMD module depends on a util.js
file exporting functions that are used in the views.
After a view is created and rendered, It executes the utilities (jquery stuff, ajax, etc) it needs from util.js
.
The problem is that when I render a view, it's utilities get called, and when I navigate to another route, and a new view is created, the new view's utilities are called now, but the older view's utilities are still running.
At some point, I have utilities from like five views running altogether, causing conflicts sometimes.
It's clear than my approach is not good enough, as I should have a way to stop/start
utilities functions as some kind of services.
I'll paste relevant code that shows my current approach:
require(["utilities"], function(util) {
...
Application.view.template = Backbone.View.extend({
el: "div#content",
initialize: function(){
this.render();
},
render: function(){
var that = this;
// ajax request to html
getTemplate(this.options.template, {
success: function(template) {
var parsedTemplate = _.template( template, that.options.templateOptions || {});
that.$el.html(parsedTemplate);
// execute corresponding utilities
if(that.options.onReady) {
that.options.onReady();
}
},
error: function(template) {
that.$el.html(template);
}
})
}
});
...
Application.router.on('route:requestPayment', function(actions) {
var params = { template: 'request-payment', onReady: util.requestPayment };
var view = new Application.view.template(params);
});
...
});
util.requestPayment
consist of a function having all stuff needed to make template work.
I'm confused about how should I handle this issue. I hope I was clear, and any suggestions or help will be appreciated.
EDIT: utilities.js
snippet:
...
var textareaCounter = function() {
$('#requestMessage').bind('input propertychange', function() {
var textarea_length = 40 - $(this).val().length;
if(textarea_length === 40 || textarea_length < 0) {
$('#message-counter').addClass('error').removeClass('valid');
$("#submitForm").attr('disabled', 'disabled');
}
else if(textarea_length < 40 && textarea_length > 0) {
$('#message-counter').removeClass('error');
$("#submitForm").removeAttr('disabled');
}
$('#message-counter').text(textarea_length);
});
}
...
var utilities = utilities || {};
...
utilities.requestPayment = function() {
textareaCounter();
initForm();
preventCatching();
requestPaymentCalcFallback();
};
...
return utilities;
...
Upvotes: 0
Views: 78
Reputation: 11538
I would suggest that you should store reference to the currently active view somewhere in your app.
You create a new view here :
var view = new Application.view.template(params);
but you have no access to this variable afterwards. So it exists but you can't stop/delete/get rid of it.
What we normally do is to have a Parent App class which initializes the whole app and manages everything. Your every module in requirejs would be depenedent on it. When a new route is navigating, you ask the Parent App class to change the view. It will delete the old view, create a new one, populate div#content and then store the reference of it.
I think when you delete the old view, all the utilities will stop responding to it.
If you still have the issue with events being called, then you might need to use stopListening
event binders before deleting the view reference.
Upvotes: 1