2010-08-30 13 views
11

Ho un server Basic Express:Come si passa il contenuto da un modello a un layout in Express?

// server.js: 
var Express = require('express'); 
app = Express.createServer(); 
app.configure(function(){ 
    app.set('views', Path.join(__dirname, 'views')); 
    app.set('view engine', 'jade'); 
    app.set('view options'); 
}); 
app.get('/', function (request, response) { 
    response.render('welcome', { 
    locals: {some: 'Locals'} 
    }); 
}); 

Con un layout di giada base:

// views/layout.jade: 
!!! 5 
html(lang='en') 
    head 
    title= pageTitle 
    body 
    h1= pageTitle 
    aside(id="sidebar")= sidebarContent 
    #content 
     #{body} 

E una semplice pagina:

# views/welcome.jade: 
// How do I pass pageTitle and sidebarContent out to the layout from here? 
p 
    Welcome to my fine site! 

(In Rails, questo potrebbe essere qualcosa di simile content_for o una semplice variabile di istanza.)

+0

Mentre è un cms basate su DocPad, forse lo troverete utile in quanto ha un supporto incorporato per i layout e giada. https://github.com/balupton/docpad – balupton

risposta

19

Utilizzando il suggerimento sopra su dynamicHelpers e la magia delle chiusure, ho trovato una soluzione abbastanza elegante che funziona senza coinvolgere l'oggetto request. Il trucco è di avvolgere la variabile del titolo della pagina in una chiusura che fornisce una funzione get() e set() attorno ad essa, e rendere tale oggetto wrapper il risultato dell'helper dinamico page_title.

Creare un property.js:

exports.create = function() { 
    var value = null; 
    return { 
     get: function() { 
      return value; 
     }, 
     set: function (new_value) { 
      value = new_value; 
     } 
    }; 
} 

Quindi chiamando creare() restituisce un oggetto con un get() e il metodo set() su di esso, che ottengono e impostare la variabile di chiusura.

Poi, nel codice di installazione della tua app:

var property = require("./property.js"); 
    app.dynamicHelpers ({ 
     page_title: function() { 
     return property.create(); 
     } 
    }); 

Poiché il valore della aiutante dinamica è il risultato della chiamata la sua funzione, secondo lei e il modello, la variabile page_title sarà l'oggetto wrapper con il get () e set() funzioni.

Secondo lei, si può poi dire:

- page_title.set ("my specific page title"); 

E nel layout:

title= page_title.get() 

Per semplificare questo un po 'oltre, aggiungendo che questo property.js:

exports.creator = function() { 
    return function() { 
     return exports.create(); 
    }; 
} 

Consente di semplificare il blocco di dichiarazione degli helper dinamici a questo:

 var property = require("./property.js"); 
     app.dynamicHelpers ({ 
      page_title: property.creator() 
     }); 
+0

Uno degli usi più pratici delle chiusure che ho incontrato! –

+0

Come hai effettivamente utilizzato questo nella vista? Mi piace questa idea, ma per me la funzione set() non viene mai chiamata e get() è sempre nullo. – qodeninja

0

in locali: {some: 'Locals', pageTitle: 'Welcome!'}

+0

Non ho 'locals' all'interno di quel modello. Dovrei tenere una mappa di '{template path: page title}' e cercare il titolo della pagina prima del rendering. Ci deve essere un modo per specificarlo da * all'interno * del modello stesso. –

5

Express non ha una nozione preconcetta di "blocchi" o come diavolo si chiama, che in in Rails, ma è possibile utilizzare una combinazione di aiutanti() e dynamicHelpers() per ottenere qualcosa di simile http://expressjs.com/guide.html#app-helpers-obj-

I locali passati sono disponibili sia per il layout che per la visualizzazione della pagina tramite

+0

Quindi l'idea sarebbe di aggiungere un helper dinamico che memorizza 'pageTitle' nella richiesta, che il layout può quindi leggere? Sembra una soluzione eccellente. Potrei persino avvolgerlo come un middleware e pubblicarlo! –

1

È possibile farlo utilizzando questo piccolo frammento.

prop.js:

var hash = {}; 
module.exports = function() { 
    return { 
     set: function(key, val) { hash[key] = val }, 
     get: function(key) { return hash[key] } 
    }; 
}; 

server.JS:

app.dynamicHelpers({ prop: require(__dirname + '/views/helpers/prop') }); 

Vista:

<% prop.set('foo', 'bar') %> 

Disposizione:

<%= prop.get('foo') %> 
2

layout.jade

# the following function is a safe getter/setter for locals 
- function pagevar(key, value) { var undef; return (value===undef) ? locals[key] || null : locals[key] = value; } 
block config 
    #intended as a non-rendered block so that locals can be overridden. 
    # put your defaults here... - use append in the child view 
!!! 
html 
    head 
    title=pagevar('title') 
    meta(name='description',content=pagevar('description')) 
...

page.jade

append config 
    - locals.title = 'override'; 
    - locals.description = 'override 2'; 
    - pagevars('somekey', 'some value'); 
...

Facile pacchiano.

0

Per Express 3 modello agnostico, funziona bene con express-partials

app.use (req, res, next)-> 
    req.locals = {} unless req.locals 

    res.locals.content_for = (k, v = null)-> 
    if !v 
     req.locals[k] 
    else 
     req.locals[k] = v 

    next() 
Problemi correlati