Question

I'm trying to create a second view for my collection.

main.js

window.App = {
    Models: {},
    Collections: {},
    Views: {},
    Routers: {},
    init: function () {
        console.log('Hello from Backbone!');
        var book = new this.Models.BookModel({
            title: 'JS is awesome',
            author: 'Douglas Crackford'
        });

        var book2 = new this.Models.BookModel({
            title: 'JS the good parts',
            author: 'Douglas Crackford'
        });

        var bookCollection = new this.Collections.BookCollection;
        bookCollection.add([book, book2]);


        var view = new this.Views.BookView();
        //next line creates error 
        var peopleView = new this.Views.PeopleView();
    }
};

$(document).ready(function () {
    App.init();
});

BookView.js

App.Views = App.Views || {};

(function () {
    App.Views.BookView = Backbone.View.extend({

        el: $('#footer'),

        template: _.template($ ('#books').html()),

        initialize: function () {
            console.log('BookView initialized');
        },

        render: function () {
            this.$el.html(this.template(this.model.toJSON()));
        }

    });
})();

PeopleView.js

App.Views = App.Views || {};

(function () {
    App.Views.PeopleView = Backbone.View.extend({

       tagName: 'ul',

       initialize: function() {
           console.log('peopleView init')
       }

    });
})();

Output created

Hello from Backbone!                                main.js:8
BookView initialized                                BookView.js:11
Uncaught TypeError: undefined is not a function     main.js:24

I find this error strange. If I copy the code from BookView to PeopleView and only call this new PeopleView (and edit out BookView) I get the same error, while the code looks valid because it executed (see the console.log). I find this very strange. What part am I missing?

edit:

Added picture to show the execution order.

enter image description here

Was it helpful?

Solution

The issue is one of scope.

When the init method is called, it is called in the Window scope, as such the value of this is Window. You can console.log(this) in your init method to see.

Couple of things you can do. As you attached App to the window object, you can call it directly:

  var bookCollection = new App.Collections.BookCollection;

Or you can bind the call of init to the App object:

App.init.call(App);

This will bind the value of this to the first argument of call.

You can simplify this further by binding directly when you pass the function doc ready method:

$(document).ready(App.init.bind(App));

More Info On Scopes

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top