I'm new to backbone.js and express and I have been adapting Christophe Coenraets Wine Cellar REST API example application for my own project.
I am building a form that has several menus needing to be populated from multiple unrelated collections in mongodb.
I am able to populate one menu with one collection, but I have no idea how to get more than one collection to my form View.
Here are the files I am using to populate one menu. How do I expand this to populate two menus?
I suppose I could make a new View for every menu I want to populate - but that seems like overkill.
Can I combine two mongodb find() collections into one object, and list them separately on a page? If so, how?
thanks in advance!
/routes/modules.js contains:
exports.findAllModules = function(req, res) {
db.collection('modules', function(err, collection) { collection.find().toArray(function(err, items) { res.send(items); }); });};
/server.js contains:
app.get('/modules', module.findAllModules);
/public/js/main.js contains:
routes: {
"modules" : "list" }
...
list: function(page) {
var p = page ? parseInt(page, 10) : 1; var moduleList = new ModuleCollection(); moduleList.fetch({success: function(){ console.log('in list function'); $("#content").html(new ModuleListView({model: moduleList, page: p}).el); }}); this.headerView.selectMenuItem('home-menu'); },
...
utils.loadTemplate([
'ModuleListItemView' ], function() { app = new AppRouter(); Backbone.history.start(); });
/public/models/models.js contains:
window.Module = Backbone.Model.extend({
urlRoot: "/modules", idAttribute: "_id", initialize: function () { this.validators = {}; this.validators.name = function (value) { return value.length > 0 ? {isValid: true} : {isValid: false, message: "You must enter a name"}; }; validateItem: function (key) { return (this.validators[key]) ? this.validators[key](this.get(key)) : {isValid: true}; }, 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, name: "" } });window.ModuleCollection = Backbone.Collection.extend({
model: Module, url: "/modules"});
/public/js/views/modulelist.js contains:
window.ModuleListView = Backbone.View.extend({
initialize: function () { this.render(); }, render: function () { var modules = this.model.models; $(this.el).html('<ul class="thumbnails"></ul>'); for (var i = 0; i < modules.length; i++) { $('.thumbnails', this.el).append(new ModuleListItemView({model: modules[i]}).render().el); } return this; } });window.ModuleListItemView = 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; } });
/public/tpl/ModuleListView.html contains:
Not entirely sure how your code works, but here are a few backbone tips.
If you wanna build a menu from a collection don't pass the collection as a model.
Instead of:
$("#content").html(new ModuleListView({model: moduleList, page: p}).el);
Use:
$("#content").empty().append(new ModuleListView({collection: moduleList, page: p}).el);
Instead of:
render: function () {
var modules = this.model.models;
$(this.el).html('<ul class="thumbnails"></ul>');
for (var i = 0; i < modules.length; i++) {
$('.thumbnails', this.el).append(new ModuleListItemView({model: modules[i]}).render().el);
}
return this;
}
Use:
render: function () {
this.$el.html('<ul class="thumbnails">');
this.collection.each(function(model) {
this.$('.thumbnails').append(new ModuleListItemView({model: model}).render().el);
}, this);
return this;
}
If you have no need in updating or deleting your models, it's enough to add the url path /modules only to the collection, for reading the initial modules.