-->

accessing variable globally in marko template

2020-07-27 06:59发布

问题:

We are using marko template engine in nodejs application. We have 3 marko layout

  1. header.marko
  2. layout.marko
  3. footer.marko

header and footer layout render inside layout.marko

when ever we create a new marko page (content page) we use layout marko like this

<layout-use template="./../layout.marko">

and load marko like this

this.body = marko.load("./views/home.marko").stream(data);

Now we want to access a variably globally. i-e if we have a variable username='abc'. we want to access and display this name in header , layout or footer marko file. But we do not want to pass username for each content marko page. i-e if we have 100 pages on website we do not want to pass username for all 100 pages. whenever user log in save username in global variable and use this global variable throughout all pages.

How we can achieve this global variable functionality.

回答1:

Looks like you can use the $global property to expose data for all templates.

For example:

router.get('/test', function * () {
  this.type = 'html'
  this.body = marko.load("./views/home.marko")
    .stream({
      color: 'red',
      $global: { 
        currUser: { id: 2, username: 'hansel' }
      }
    })
})

And then these templates:

// home.marko
<include('./header.marko') />
<h1>color is ${data.color}</h1>

// header.marko
<h2>Header</h2>
<p if(out.global.currUser)>
  Logged in as ${out.global.currUser.username}
</p>
<p else>
  Not logged in
</p>

That works.

But obviously you don't want to have to pass $global into every .stream(), so one idea is to store it on the Koa context, let any middleware attach data to it, and then write a helper that passes it into the template for us.

// initialize the object early so other middleware can use it
// and define a helper, this.stream(templatePath, data) that will
// pass $global in for us
router.use(function * (next) {
  this.global = {}
  this.stream = function (path, data) {
    data.$global = this.global
    return marko.load(path).stream(data)
  }
  yield next
})

// here is an example of middleware that might load a current user
// from the database and attach it for all templates to access
router.use(function * (next) {
  this.global.currUser = {
    id: 2,
    username: 'hansel'
  }
  yield next
})

// now in our route we can call the helper we defined,
// and pass any additional data
router.get('/test', function * () {
  this.type = 'html'
  this.body = this.stream('./views/home.marko', {
    color: red
  })
})

That code works with the templates I defined above: ${out.global.currUser} is accessible from header.marko, yet ${data.color} is accessible from home.marko.

I've never used Marko, but I was curious enough to read the docs after seeing your question since I've thought of using it from time to time. I didn't feel like figuring out how <layout-use> works, so I used <include> instead.