Jay
Jay

Reputation: 1033

backbonejs template not rendering, node.js

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!!!!

Upvotes: 0

Views: 357

Answers (1)

Nazar
Nazar

Reputation: 1799

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.

Upvotes: 1

Related Questions