2014-02-26 59 views
3

每次我用新的菜單項更新數據庫時,我試圖讓路由更新一個路由。這是我的悲傷小丑嘗試:Express.js動態路由 - 這甚至可能嗎?

這裏在app.js,我檢查菜單數據庫和shazaam ...路線在啓動在飛行。酷!:

// in app.js // 
var attachDB = function(req, res, next) { 
    req.contentdb = db.content; 
    req.menudb = db.menu; 
    req.app = app; // this is the express() app itself 
    req.page = PageController; 
    next(); 
}; 
db.menu.find({}, function (err, menuitems){ 
    for(var i=0; record = menuitems[i]; i++) { 
     var menuitem = record.menuitem; 
     app.all('/' + menuitem, attachDB, function(req, res, next) { 
      console.log('req from app all route: ',req) 
      PageController.run(menuitem, req, res, next); 
     }); 
    } 

    http.createServer(app).listen(config.port, function() { 
     console.log(
      '\nExpress server listening on port ' + config.port 
     ); 
    }); 
}); 

不是真正的優雅,但它是一種概念證明。現在問題是:當我在Admin.js文件中保存一個新的菜單項時,數據庫get被更新,路由器似乎得到更新,但點擊帶有動態創建的路由的菜單鏈接後,該請求剛好爆炸

請求中的很多東西似乎都已丟失,我覺得有些基本的東西我不明白路由,回調或者這可能只是錯誤的解決方案。這裏就是負責創建一個新的菜單項,並創造了我的Admin.js文件的新路徑的功能看起來像:

// in Admin.js // 
menuItem: function(req, res, callback) { 
    var returnMenuForm = function() { 
     res.render('admin-menuitem', {}, function(err, html) { 
      callback(html); 
     }); 
    }; 
    var reqMenudb = req.menudb, 
     reqContentdb = req.contentdb, 
     reqApp = req.app, 
     reqPage = req.page; 

    if(req.body && req.body.menuitemsubmitted && req.body.menuitemsubmitted === 'yes') { 
     var data = { menuitem: req.body.menuitem }; 
     menuModel.insert(data, function(err) { 
      if (err) { 
       console.log('Whoa there...',err.message); 
       returnMenuForm(); 
      } else { 
       // data is inserted....great. PROBLEM...the routes have not been updated!!! Attempt that mimics what I do in app.js here... 
       reqApp.all('/' + data.menuitem, function(req, res, next) { 
        // the 2 db references below are set with the right values here 
        req.contentdb = reqContentdb; 
        req.menudb = reqMenudb; 
        next(); 
       }, function(req, res, next) { 
        reqPage.run(data.menuitem, req, res, next); 
       }); 

       returnMenuForm(); 
      } 
     }); 
    } else { 
     returnMenuForm(); 
    } 
}, 

在管理部分保存數據的正常工作。如果您控制檯登錄app.routes,它甚至會顯示一條非常酷的新路線。但是,在刷新頁面並單擊新路由應該工作的鏈接後,我得到一個未定義的錯誤。

管理員將數據傳遞到我的頁面控制器:

// in PageController.js // 
module.exports = BaseController.extend({ 
    name: "Page", 
    content: null, 
    run: function(type, req, res, next) { 
     model.setDB(req.contentdb); /* <-- problem here, req.contentdb is undefined which causes me problems when talking to the Page model */ 
     var self = this; 
     this.getContent(type, function() { 
      var v = new View(res, 'inner'); 
      self.navMenu(req, res, function(navMenuMarkup){ 
       self.content.menunav = navMenuMarkup; 
       v.render(self.content); 
      }); 
     }); 
    }, 
    getContent: function(type, callback) { 
     var self = this; 
     this.content = {} 
     model.getlist(function(records) { 
      if(records.length > 0) { 
       self.content = records[0]; 
      } 
      callback(); 
     }, { type: type }); 
    } 

最後,錯誤的一點是這裏的模型

// in Model.js // 
module.exports = function() { 

    return { 
     setDB: function(db) { 
      this.db = db; 
     }, 
     getlist: function(callback, query) { 
      this.db.find(query || {}, function (err, doc) { callback(doc) }); 
     }, 

這裏終於看到了「這個」上面的獲取列表方法是未定義的,並導致頁面被彈出。

如果我重新啓動服務器,由於我的動態加載器在app.js中,所有事情都可以再次運行。但是在更新數據庫之後沒有一些方法可以重新加載路由嗎?我的技術在這裏不起作用,並且將主應用程序傳遞給控制器​​是件醜陋的事,因爲我正在這裏做。

回答

3

我建議兩個轉變:

  1. 移動此菜單連接東西一個獨立的模塊。
  2. 當你在它的時候,做一些緩存。

概念證明菜單分貝功能,異步與setTimeout的製作,你會與實際工作DB調用替換它。

// menuitems is cached here in this module. You can make an initial load from db instead. 
var menuitems = []; 
// getting them is simple, always just get the current array. We'll use that. 
var getMenuItems = function() { 
    return menuitems; 
} 

// this executes when we have already inserted - calls the callback 
var addMenuItemHandler = function(newItem, callback) { 
    // validate that it's not empty or that it does not match any of the existing ones 
    menuitems.push(newItem); 
    // remember, push item to local array only after it's added to db without errors 
    callback(); 
} 
// this one accepts a request to add a new menuitem 
var addMenuItem = function(req, res) { 
    var newItem = req.query.newitem; 

    // it will do db insert, or setTimeout in my case 
    setTimeout(function(newItem){ 
     // we also close our request in a callback 
     addMenuItemHandler(newItem, function(){ 
      res.end('Added.'); 
     }); 

    }, 2000); 
}; 

module.exports = { 
    addMenuItem: addMenuItem, 
    getMenuItems: getMenuItems 
} 

所以,現在你有一個模塊menuhandler.js。讓我們構建它並在我們的應用程序中使用它。

var menuHandler = require('./menuhandler'); 
var app = express(); 
// config, insert middleware etc here 

// first, capture your static routes - the ones before the dynamic ones. 
app.get('/addmenuitem', menuHandler.addMenuItem); 
app.get('/someotherstaticroute', function(req, res) { 
    var menu = menuHandler.getMenuItems(); 
    res.render('someview', {menu: menu}); 
}); 


// now capture everything in your menus. 
app.get('/:routename', function(req, res){ 
    // get current items and check if requested route is in there. 

    var menuitems = menuHandler.getMenuItems(); 
    if(menuitems.indexOf(req.params.routename) !== -1) { 
     res.render('myview', {menu: menuitems}); 
    } else { 
     // if we missed the route, render some default page or whatever. 
    } 
}); 

app.get('/', function(req, res) { 
    // ... 
}); 

現在,你不必去分貝,如果沒有新的更新(因爲排列的菜單項總是最新的),所以你的初始視圖渲染速度更快(對於一個1 DB調用,反正)。

編輯:哦,我剛纔看到你的Model.js。這個問題存在着this是指你已返回的對象:

{ 
    setDB: function(db) { 
     this.db = db; 
    }, 
    getlist: function(callback, query) { 
     this.db.find(query || {}, function (err, doc) { callback(doc) }); 
    } 
} 

所以,沒有DB默認。而且,由於您在初始頁面加載中附加了一些東西到app,您確實得到了一些東西。

但是,在您當前的更新功能中,您將東西附加到新應用程序(reqApp = req.app),所以現在您不是在與原始應用程序交談,而是在與另一個實例交談。我認爲你的後續請求(更新後)會讓範圍混淆在一起,因此與實際的最新數據失去聯繫。

+1

這是代碼的一個很好的例子,讓我走向正確的方向,組織良好。今天我學到了一個新的竅門。謝謝你,茲拉特科。 –

+1

你的評論是更好的司機回答人們的問題,然後聲譽點:) – Zlatko

3

在你的代碼中,當你啓動你的服務器時,它從菜單db中讀取並創建你的路由。當你的菜單改變時,你不會再次從數據庫讀取數據。

我建議你這樣做以下

app.all('*', function(req, res) { 
    //read from your menu db and do the the route management yourself 
}); 
+0

是的,這似乎是一個完美的可行的方式來解決這個問題。我曾考慮過這種策略作爲一種選擇,但在我看來,應該能夠在快速應用程序運行時添加和從路線中刪除,而不是通過路線尋找路線。這最終是我想弄明白的。 –

+0

我面臨同樣的問題,我認爲這可能是解決它的可行方法。 – Tokimon