0

I've been getting to grips learning backbonejs via nodecellar, I've delved into it and have a good understanding of the principles of how data is being passed around.

I'm a bit stuck, I'm pulling bits of the Nodecellar code and modifying it to grasp my understanding of backbone.js. I'm having a problem rendering lists:

Here's the code:

Server.js

var express = require('express'),
path = require('path'),
http = require('http'),
wine = require('./routes/wines');
users = require('./routes/users');
impulse = require('./routes/impulse');
//dashboard = require('./routes/dashboard');

var app = express();


app.configure(function () {
    app.set('port', process.env.PORT || 3000);
    app.use(express.logger('dev'));  /* 'default', 'short', 'tiny', 'dev' */
    app.use(express.bodyParser()),
    app.use(express.static(path.join(__dirname, 'public')));
});

//impulse management dynamic display
app.get('/', impulse.findAll);
app.get('/impulse', impulse.findAll);


http.createServer(app).listen(app.get('port'), function () {
    console.log("Express server listening on port " + app.get('port'));
});

So, we can see the server is set up on port 3000. The model looks like this, it has some validation in it:

Model.

window.Impulse = Backbone.Model.extend({

    urlRoot: "/impulse",

    idAttribute: "_id",

    initialize: function () {
        this.validators = {};

        this.validators.page = function (value) {
            return value.length > 0 ? {isValid: true} : {isValid: false, message: "The module needs a url"};
        };

        this.validators.picture = function (value) {
            return value.length > 0 ? {isValid: true} : {isValid: false, message: "The module needs a unique picture"};
        };

        this.validators.description = function (value) {
            return value.length > 0 ? {isValid: true} : {isValid: false, message: "The module needs a description"};
        };
    },

    validateItem: function (key) {
        return (this.validators[key]) ? this.validators[key](this.get(key)) : {isValid: true};
    },

    // TODO: Implement Backbone's standard validate() method instead.
    validateAll: function () {

        var messages = {};

        for (var key in this.validators) {
            if(this.validators.hasOwnProperty(key)) {
                var check = this.validators[key](this.get(key));
                if (check.isValid === false) {
                    messages[key] = check.message;
                }
            }
        }

        return _.size(messages) > 0 ? {isValid: false, messages: messages} : {isValid: true};
    },

    defaults: {
        _id: null,
        page: "#",
        picture: "users.png",
        name: "Impulse Dynamic Engine",
        subicon: "fa-exclamation-triangle",
        description: "The Impulse view engine has not been set up correctly or has failed to set up. Please contact SandWTech for technical support."
    }
});

window.ImpulseCollection  = Backbone.Collection.extend({

    model: Impulse,

    url: "/impulse"

});

Routes.js Handles the routes based on the app.get functionality, so I currently only have what is being called in the app.js.

var mongo = require('mongodb');

var Server = mongo.Server,
    Db = mongo.Db,
    BSON = mongo.BSONPure;

var server = new Server('localhost', 27017, {auto_reconnect: true});
db = new Db('engine', server, {safe: true});

db.open(function(err, db) {
    if(!err) {
        console.log("Connected to the engine database");
        db.collection('impulse', {safe:true}, function(err, collection) {
            if (err) {
                console.log("WARNING 'impulse' collection doesn't exist. Setting up impulse settings");
                populateDB();
            }
        });
    }
});


exports.findAll = function(req, res) {
    db.collection('impulse', function(err, collection) {
        collection.find().toArray(function(err, items) {
            res.send(items);
        });
    });
};

Main.js handles the routes and decides what to display.

var AppRouter = Backbone.Router.extend({

routes: {
    ""                  : "home",
    "impulse"           : "home",
    "*actions"          : "home"
},


initialize: function () {
        this.headerView = new HeaderView();
        $('.header').html(this.headerView.el);
    },

    home: function (page) {
      var p = page ? parseInt(page, 10) : 1;
        var impulseList = new ImpulseCollection();
        impulseList.fetch({success: function(){
            $("#content").html(new HomeView({model: impulseList, page: p}).el);
        }});
        this.headerView.selectMenuItem('home-menu');
    },
utils.loadTemplate(['HomeView', 'HeaderView', 'WineView', 'WineListItemView', 'AboutView'], function() {
    app = new AppRouter();
    Backbone.history.start();
});

The model is supposed to be passed into the HomeView and displayed:

<a href="#impulse/<%= page %>" class="thumbnail plain" style="text-align: center;">
    <img src="<%= picture === null ? 'pics/generic.jpg' : 'pics/' + picture %>" height="150" width="125" alt="">
    <h5><%= name %></h5>
    <br/>
    <i class="<%= subicon %>"></i> <%= description %>
</a>

Now, when I go to run this I get the following error:

Uncaught TypeError: Object [object Object] has no method 'template'

The error is on line 35 in home.js which holds the homeView:

window.HomeView = Backbone.View.extend({

initialize: function () {
    this.render();
},

render: function () {
    var impulses = this.model.models;
    var len = impulses.length;
    var startPos = (this.options.page - 1) * 8;
    var endPos = Math.min(startPos + 8, len);

    $(this.el).html('<ul class="thumbnails"></ul>');

    for (var i = startPos; i < endPos; i++) {
        $('.thumbnails', this.el).append(new HomeViewItemView({model: impulses[i]}).render().el);
    }

    $(this.el).append(new Paginator({model: this.model, page: this.options.page}).render().el);

    return this;
    }
});

window.HomeViewItemView = Backbone.View.extend({

    tagName: "li",

    initialize: function () {
        this.model.bind("change", this.render, this);
        this.model.bind("destroy", this.close, this);
    },

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

});

It's saying that the error is here :

   $(this.el).html(this.template(this.model.toJSON()));

But I can't for the life of me firgue it out ._.;

Why is the template not rendering when it is all hooked up correctly? What Am I missing? GAAAAAAAHHHHHH!!!!

4
  • 1
    Where's the code for HomeView? Commented Oct 28, 2013 at 22:50
  • The error message indicates that at some point in your code you have tried to call a 'template' method on an object that doesn't contain a template method. Commented Oct 28, 2013 at 23:06
  • I added it at the bottom Commented Oct 28, 2013 at 23:07
  • Ah ok, I had a look at my code and the error stems from home.js which i forgot to add Commented Oct 28, 2013 at 23:17

1 Answer 1

1

In HomeView you have this code:

new HomeViewItemView({model: impulses[i]})

And than in HomeViewItemView you have:

$(this.el).html(this.template(this.model.toJSON()));

But I don't see a template in the HomeViewItemView. It is undefined.

Sign up to request clarification or add additional context in comments.

1 Comment

Hi, this is because the template is in another code, it's in main.js

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.