2013-09-06 3 views
3

Я новичок в Node, и я пытаюсь создать приложение MVC с помощью ExpressJS (http://expressjs.com/). Я использую ту же структуру папок, что и пример MVC (https://github.com/visionmedia/express/tree/master/examples/mvc) на GitHub.Как создать расширяемые контроллеры в ExpressJS

В моей папке контроллеров у меня есть 2 папки: основная и системная. Я хотел бы иметь базовый контроллер, определенный в /controllers/system/index.js, и /controllers/main/index.js наследует системный контроллер. Каждый другой модуль расширяет систему и отменяет несколько функций для создания страницы.

В другом учебнике я нашел следующий код.

base.js

var _ = require("underscore"); 
module.exports = { 
    name: "base", 
    extend: function(child) { 
     return _.extend({}, this, child); 
    }, 
    run: function(req, res, next) { 

    } 
}; 

Home.js

var BaseController = require("./Base"), 
    View = require("../views/Base"), 
    model = new (require("../models/ContentModel")); 

module.exports = BaseController.extend({ 
    name: "Home", 
    content: null, 
    run: function(req, res, next) { 
     model.setDB(req.db); 
     var self = this; 
     this.getContent(function() { 
      var v = new View(res, 'home'); 
      v.render(self.content); 
     }) 
    }, 
    getContent: function(callback) { 
     var self = this; 
     this.content = {}; 
     model.getlist(function(err, records) { 
      if(records.length > 0) { 
       self.content.bannerTitle = records[0].title; 
       self.content.bannerText = records[0].text; 
      } 
      model.getlist(function(err, records) { 
       var blogArticles = ''; 
       if(records.length > 0) { 
        var to = records.length < 5 ? records.length : 4; 
        for(var i=0; i<to; i++) { 
         var record = records[i]; 
         blogArticles += '\ 
          <div class="item">\ 
           <img src="' + record.picture + '" alt="" />\ 
           <a href="/blog/' + record.ID + '">' + record.title + '</a>\ 
          </div>\ 
         '; 
        } 
       } 
       self.content.blogArticles = blogArticles; 
       callback(); 
      }, { type: 'blog' }); 
     }, { type: 'home' }); 
    } 
}); 

Как вы это делаете без функции расширения Underscore в? У Express есть встроенный метод расширения модулей? Я использую doT.js для шаблонов, поэтому я не хочу включать другую большую библиотеку для одной функции.

Спасибо!

Редактировать: Придется внести несколько изменений, чтобы получить базовый код из dc5 для работы. Система работает, но для магистрали я получаю эту ошибку на наследуют вызов:

util.js:555 
    ctor.prototype = Object.create(superCtor.prototype, { 
         ^
TypeError: Object prototype may only be an Object or null 
    at Function.create (native) 
    at Object.exports.inherits (util.js:555:27) 

/controllers/system/index.js:

var util = require('util'), 
    system = { }; 

system.index = function(req, res, next) { 
    res.render('main'); 
}; 

module.exports = system; 

/controllers/main/index.js:

var util = require('util'), 
    system = require('./../system/index'), 
    main = { }; 

util.inherits(main, system); 

module.exports = main; 
+0

В этом случае как система, так и основной являются простыми объектами. Оба аргумента 'util.inherits' должны быть конструкторами. – dc5

+0

Я не уверен, что я следую. Я попытался поставить main.constructor, main.prototype и main.prototype.constructor, и никто из них не работал? – Jonathan

+0

система инициализируется {}, которая является пустым объектом типа 'Object'. Я добавлю обновление к моему ответу, которое в ближайшее время будет использовать те же имена и структуру каталогов. – dc5

ответ

9

Вы можете использовать util.inherits за то, что вы описали. Это не замена для _.extend(), но все, что необходимо для примера выше, является прямым наследованием.

Использование: util.inherits(constructor, superConstructor)

base.js:

var util = require('util'); 

function Base() {…} 

Base.prototype.run = function(req,res,next) {…} 
module.exports = Base; 

home.js:

var util = require('util'); 
var BaseController = require("./base"); 

function Home() {…} 

util.inherits(home, BaseController); 

Home.prototype.run = function(req,res,next) {…} 

Или стандартный шаблон наследования JS:

base.js:

function Base() {…} 

Base.prototype.run = function(req,res,next) {…} 
module.exports = Base; 

дом.ЯШ:

var BaseController = require("./base"); 

function Home() { 
    BaseController.apply(this, arguments); 
} 

Home.prototype = Object.create(BaseController.prototype); 
Home.prototype.run = function(req,res,next) {…} 

Из обновленных образцов в вопросе, модули должны выглядеть следующим образом:

система:

var util = require('util'); 

function System() { 
    this.txt = "hello from "; 
    this.name = "System"; 
} 

System.prototype.sayHello = function() { 
    console.log(this.txt + this.name); 
} 

System.prototype.run = function(req,res,next) { 
    this.sayHello(); 

    console.log('calling ==> overrideMe'); 
    this.overrideMe(); 

    console.log('calling ==> noOverride'); 
    this.noOverride(); 
    next ? next() : ""; 
} 

System.prototype.overrideMe = function() { 
    console.log('System.overrideMe'); 
} 

System.prototype.noOverride = function() { 
    console.log('System.noOverride'); 
} 


module.exports = System; 

Главная:

var util = require('util'); 
var System = require("../system/"); 

function Main() { 
    // Makes sure the System constructor is run 
    System.apply(this, arguments); 
    this.name = "Main"; 
} 

util.inherits(Main, System); 

Main.prototype.run = function(req,res,next) { 
    this.sayHello(); 

    console.log('calling ==> overrideMe'); 
    this.overrideMe(); 

    console.log('calling ==> noOverride'); 
    this.noOverride(); 

    next ? next() : ""; 
} 

Main.prototype.overrideMe = function() { 
    console.log('Main.overrideMe'); 
} 

module.exports = Main; 

приложение .js в корне - упрощенный экспресс-сервер :

var System = require('./controllers/system'); 
var Main = require('./controllers/main'); 
var express = require('express'); 
var path = require('path'); 
var http = require('http'); 
var app  = express(); 
var server; 

var system = new System(); 
var main = new Main(); 

app.configure(function() { 
    "use strict"; 
    app.set('port', process.env.PORT || 3000, '127.0.0.1'); 
    app.use(system.run.bind(system)); 
    app.use(main.run.bind(main)); 
    app.use(app.router); 
    //app.use(express.compress()); 
    app.use(express.static(path.join(__dirname, '..', 'public'), {redirect: false})); 
    app.use(express.static(path.join("/Users/dave/personal/playground/yo"), {redirect: false})); 
}); 


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

от доступа браузера: http://localhost:3000/

консоли Выход:

Express server listening on port 3000 
hello from System 
calling ==> overrideMe 
System.overrideMe 
calling ==> noOverride 
System.noOverride 
hello from Main 
calling ==> overrideMe 
Main.overrideMe 
calling ==> noOverride 
System.noOverride 

Важно

Поскольку этот пример использует экземпляры System и Main для обеспечения маршрутов, Метод run должен быть связан с экземпляр при передаче его для выражения. См.: MDN .bind documentation для получения дополнительной информации.

+0

Спасибо за ответ, я попробовал код, и я получаю эту ошибку: util.js: 555 ctor.prototype = Object.create (superCtor.prototype, { ^ TypeError: прототипом объекта может быть только объект или null – Jonathan

+0

Благодарим вас за подробный ответ, к сожалению, я не могу заставить его работать. Если в системе я делаю module.exports = system (function not instanced), то в основном я могу делать module.exports = new main() Я не получить какие-либо ошибки, но экспортированные методы не работают с динамической маршрутизацией в примере MVC, который я связал. Если в системе я создаю экземпляр (module.exports = new system()), этот модуль будет работать, как ожидалось, но затем, когда я пытаюсь Расширьте его в основном Я получаю ту же ошибку Object.create.Я не могу показаться, что вы расширяетесь на работу и все еще имеете оба контроллера, которые передают методы в module.exports? Любые идеи? – Jonathan

+0

@Jonathan У меня есть обновление пример работы в качестве основного экспресс-приложения, чтобы показать, как использовать метод 'run' как маршрут в экспресс. Самое главное - использовать 'bind()' для предоставления соответствующего контекста, когда маршруты 'run' вызывают экспресс. – dc5

0

Чтобы избежать сложной конфигурации и обходных решений, используйте ZinkyJS, он дает лучший подход, чтобы сделать наследование модулей возможным.