Reputation: 1301
This is presented in easy to understand fashion, so enjoy reading :)
I have a backbone app which is initialised with main.js file like this:
require([
'backbone',
'app',
'models/session'
], function (Backbone, Application, SessionModel) {
//new Application();
window.App = {
session: new SessionModel()
};
new Application();
Backbone.history.start();
});
As you can see, requirejs requires 'app' as a second param.
App is just a router which looks something like this (less important parts has been removed)
define(function(require){
'use strict';
var Backbone = require('backbone'),
Header = require('views/header'),
Login = require('views/login');
var Router = Backbone.Router.extend({
initialize: function(){
this.header = new Header();
this.header.render();
},
routes: {
'login': 'showLogin'
},
showLogin: function() {
this.showView(new Login(), {requiresAuth: false});
this.header.model.set('title', 'Login');
},
showView: function(view, options) {
if(this.currentView) this.currentView.remove();
$('.content').html(view.render().$el);
this.currentView = view;
return view;
}
});
return Router;
});
The important bit here is that in the first lines I'm requiring
Header = require('views/header');
Header view requires another view in a standard way:
LogoutView = require('views/logout');
Logout view looks like this and here I come to the essence of the problem :
define(function(require){
'use strict';
var Backbone = require('backbone'),
JST = require('templates')
return Backbone.View.extend({
model: App.session,
template: JST['app/scripts/templates/logout.hbs'],
events: {
'submit form': 'logout'
},
initialize: function(){
this.listenTo(this.model, 'change', this.render)
},
render: function(){
this.$el.html(this.template(this.model.toJSON()));
return this;
},
logout: function(e){
//nothing important here
}
});
});
As you can see at the very first line after Backbone.View.extend I'm trying to define the model property of the view:
model: App.session,
which I suppose should be accessible, because I was defining the:
window.App = {
session: new SessionModel()
};
in the main.js file.
But it seems that there is a require problem, because as require is trying to get all the files in the first lines of the program:
require([
'backbone',
'app', <<--- in this line it's trying to get all the files required in the app.js
'models/session'
], function (Backbone, Application, SessionModel) {
Then I'm getting this error :
Uncaught ReferenceError: App is not defined logout.js:8
Which is exactly the line trying to get access to App global variable:
model: App.session,
That should be defined after running main.js file, but it doesn't even go that far as require is getting the files and finds not defined App variable in the LogoutView.
I can work around this problem by defining the model inside the initialize function of the view like so:
initialize: function(){
this.model = App.session;
this.listenTo(this.model, 'change', this.render)
},
But what I really want is to understand why this error is occurring and what is the best practice of creating global Models using Backbone.js and Require.js.
Upvotes: 3
Views: 782
Reputation: 1301
The code below is more or less how I was trying to solve this problem before I've posted this question:
define(function(require) {
'use strict';
var SessionModel = require('models/session')
var session = (function(){
if(App.session instanceof SessionModel.constructor){
return App.session;
} else {
App.session = new SessionModel()
return App.session;
}
})();
return session;
});
But I think I've abandoned it for some reason, either because App wasn't defined or maybe it seemed that there is a better solution for this.
The dirty hack was that I had to create the:
window.App = {};
Just before I was running the entire application.
Upvotes: 0
Reputation: 33344
The list of dependencies in a define
or require
(the first argument in your require
or the simplified wrapper you use in your other modules) tells RequireJS that it should load and interpret those modules before interpreting the current file.
Here's what happens:
require
has backbone
, app
, models/session
as dependenciesviews/logout
views/logout
is interpreted, you try to assign App.session
to your view.model
but that does not exist at that point and you get a App is not defined
errorOne solution would be to create a singleton of your Session
object and require it when you need it.
For example, let's say you have globals/session
define(['models/session'], function (SessionModel) {
return new SessionModel();
});
You would define your app as
require([
'backbone',
'app',
'globals/session'
], function (Backbone, Application, session) {
//new Application();
window.App = {
session: session
};
new Application();
Backbone.history.start();
});
and the same change in your view/logout
define(function(require){
'use strict';
var Backbone = require('backbone'),
JST = require('templates')
return Backbone.View.extend({
model: require('globals/session'),
...
});
});
Upvotes: 1