Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding TodoMVC Example

Starting to learn node.js and backbone.js and am using the TodoMVC example as my guide. There are a couple parts I am having trouble wrapping my head around. See below.

Here is app.js.

var express = require('express')
  , http = require('http')
  , mongoose = require('mongoose')
  , models = require('./models')
  , routes = require('./routes')
  , app = express();

app.configure(function () {
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(require('stylus').middleware({ src: __dirname + '/public' }));
  app.use(express.static(__dirname + '/public'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
});

app.configure('development', function () {
  app.use(express.errorHandler());
});

routes.init(app);


mongoose.connect("127.0.0.1", "todomvc", 27017);

http.createServer(app).listen(3000);

console.log("Express server listening on port 3000");

Heres is ./models:

var mongoose = require('mongoose'),

  TodoSchema = new mongoose.Schema({
    title: { 'type': String, 'default': 'empty todo...' },
    order: { 'type': Number },
    done: { 'type': Boolean, 'default': false }
  });

module.exports = mongoose.model('Todo', TodoSchema);

Andy finally, here is ./routes:

(function (exports) {

  "use strict";

  var mongoose = require('mongoose')
    , crudUtils = require('../utils/crudUtils')
    , Todo = mongoose.model('Todo');

  function index(req, res) {
    res.render('index', { 'title': 'Backbone.js, Node.js, MongoDB Todos' });
  }

  exports.init = function (app) {
    app.get('/', index);
    crudUtils.initRoutesForModel({ 'app': app, 'model': Todo });
  };

}(exports));

So my question is, how is the 'Todo' model in mongoose.model('Todo') in the routes module available in this scope? I see that the models module is exporting mongoose.model('Todo', TodoSchema); so I have to believe that is how the routes module has access to it, but I don't know why. What am I missing? I have a feeling its just not a complete understanding of scope in this situation. Also, I am not sure of the reasoning of having the routes function anonymous.

Many thanks!

like image 214
Andy Thornton Avatar asked Oct 24 '12 01:10

Andy Thornton


1 Answers

This is one of the more confusing things to deal with when starting out in Node and Mongoose.

When you require('mongoose') for the first time, it creates a singleton instance of Mongoose - the same instance is returned every subsequent time you require it.

This makes it really easy to work with, but is a bit of 'magic' that's hard to understand at the beginning.

It means that when you call mongoose.connect("127.0.0.1", "todomvc", 27017); in app.js, it creates a connection that persists with the app.

It also means that mongoose.model('Todo', TodoSchema); makes the Todo model available in any other scope that calls require('mongoose'), via mongoose.model('Todo'). This could be var'd at the top of another file you require as in the example above, or the moment you need it in the middle of a callback.

This is how you get the Todo model into your routes.js, and a very good reason to ensure telling Mongoose about your models is one of the first things you do in your application.

To answer your questions regarding understanding scopes; each file you require effectively has its own scope and doesn't have access to anything except global objects like process. You have to require everything you want to work with, and can only pass variables in by calling functions or creating classes that are exposed via the exports object.

So for the actual example above there is no benefit in exporting the model from models.js as it's not subsequently referenced in app.'s where models.js is required. It's these lines in routes.js that make the Todo model available:

var mongoose = require('mongoose')
, Todo = mongoose.model('Todo'); // returns the Todo model that was registered by models.js

That's how Todo exists on this line:

crudUtils.initRoutesForModel({ 'app': app, 'model': Todo });

There's also no benefit (as far as I know) in wrapping the routes in an anonymous function as this is essentially provided by require.

like image 163
Jed Watson Avatar answered Nov 14 '22 20:11

Jed Watson