Create / access global object with requirejs and backbonejs

This is presented in an easy-to-understand form, so enjoy reading :)

I have a basic application that is initialized by the 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 "application" as the second parameter.

The app is just a router that looks something like this (the less important parts have 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 thing here is that in the first lines I require

Header = require('views/header');

      

The header view requires a different view in the standard way:

LogoutView = require('views/logout');

      

The output looks like this, and this is where I come to the heart 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 in the first line after Backbone.View.extend I'm trying to define a property of the view model:

model: App.session,

      

which I suppose should be available because I was defining:

window.App = {
      session: new SessionModel()
    };

      

in the main.js file.

But it seems like there is a problem with the requirement, because since it is required, all the files in the first lines of the program need to be retrieved:

require([
    'backbone',
    'app', <<--- in this line it trying to get all the files required in the app.js 
    'models/session'
], function (Backbone, Application, SessionModel) {

      

Then I get this error:

Uncaught ReferenceError: App is not defined   logout.js:8

      

This is exactly the line trying to access the global variable of the application:

 model: App.session,

      

This should be defined after running the main.js file, but it doesn't even go as far as requiring files to be retrieved and finds an undefined App variable in the LogoutView.

I can work around this problem by defining the model inside the view initialization function like this:

initialize: function(){
    this.model = App.session;
    this.listenTo(this.model, 'change', this.render)
},

      

But I really want to understand why this error occurs and what is the best practice for creating global models using Backbone.js and Require.js.

+3


source to share


2 answers


The list of dependencies in define

or require

(the first argument in your require

or a lightweight wrapper that you use in other modules) tells RequireJS that it should load and interpret those modules before interpreting the current file.

Here's what's going on:

  • Origin require

    has backbone

    , app

    , models/session

    as dependencies
  • before its function is evaluated, it loads its dependencies and in turn searches for its dependencies
  • Rinse and repeat until you reach views/logout

  • views/logout

    is interpreted, you are trying to assign to App.session

    yours view.model

    , but it does not exist at this point and you get the errorApp is not defined


One solution would be to create a singleton of your object Session

and require it when you need it.

For example, let's say you have globals/session



define(['models/session'], function (SessionModel) {
    return new SessionModel();
});

      

Your application will be defined as

require([
    'backbone',
    'app',
    'globals/session'
], function (Backbone, Application, session) {

    //new Application();
    window.App = {
      session: session
    };

    new Application();

    Backbone.history.start();
});

      

and the same changes in your view/logout

define(function(require){
    'use strict';

    var Backbone = require('backbone'),
        JST = require('templates')

    return Backbone.View.extend({
        model: require('globals/session'),
        ...
    });
});

      

+1


source


In the code below, I am more or less trying to solve this problem before I 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 ditched it for some reason because the application was not defined or perhaps it seemed like there was a better solution for this.



The dirty hack was that I had to create:

window.App = {};

      

Just before starting the whole application.

0


source







All Articles