Handlebars – section, partials

Sekcja pozwala wstrzykiwać kod do layoutu: arkusze CSS w <head> lub skrypty JS przed </body>. Nie jest wbudowana w silnik handlebars – wprowadzamy ją jako helper w konfiguracji engine.

app.engine('handlebars', expressHandlebars({ 
  defaultLayout: 'main', 
  extname: '.hbs', 
  helpers: { 
    section: function(name, options) { 
      if(!this._sections) this._sections = {} 
      this._sections[name] = options.fn(this) 
      return null 
    }, 
  },   
}))

Zdefiniowanie sekcji w szablonie /views/my_template.handlebars

{{#section 'head'}}
   <!-- we want Google to ignore this page -->
   <meta name="robots" content="noindex">
{{/section}}

<h1>Test Page</h1>
<p>We're testing some script stuff.</p> 


{{#section 'scripts'}}
<script>
  document.querySelector('body') 
          .insertAdjacentHTML('beforeEnd', '<small>(scripting works!)</small>')
</script>
{{/section}} 

Do layout’u dodajemy sekcje o tych samych nazwach co w widokach (home, scripts)

 <head>
   {{#section 'head'}}  
     <meta name="robots" content="noindex">
   {{/section}} 
 </head>

 <footer>...</footer>
  {{#section 'scripts'}}
   <script>
     const div = document.createElement('div')
     div.appendChild(document.createTextNode('(scripting works!)'))
     document.querySelector('body').appendChild(div)
   </script>
  {{/section}} 
</body>

Partials views/partials/weather.handlebars – elementy, widget’y do użycia w wielu szablonach

<div class="weatherWidget">
  {{#each partials.weatherContext}}
    <div class="location">
      <h3>{{location.name}}</h3>
      <a href="{{location.forecastUrl}}">
        <img src="{{iconUrl}}" alt="{{weather}}">
        {{weather}}, {{temp}}
      </a>
    </div>
  {{/each}}
  <small>Source: <a href="https://www.weather.gov/documentation/services-webapi">
  National Weather Service</a></small>
</div> 

Kontekst (dane) do widgetu (partials) dostarczamy poprzez midleware korzystajc  z obiektu res.locals.partials.partial_name. Poniżej część biblioteki zapisana w pliku /lib/middleware/weather.js

// Dane z sieci, bazy danych - tu z tablicy - dostępne poprzez obietnicę
const getWeatherData = () => Promise.resolve([
{
  location: {
    name: 'Portland',
    coordinates: { lat: 45.5154586, lng: -122.6793461 },
  },
  forecastUrl: 'https://api.weather.gov/gridpoints/PQR/112,103/forecast',
  iconUrl: 'https://api.weather.gov/icons/land/day/tsra,40?size=medium',
  weather: 'Chance Showers And Thunderstorms',
  temp: '59 F',
  },
{
  location: {
    name: 'Bend',
    coordinates: { lat: 44.0581728, lng: -121.3153096 },
  },
  forecastUrl: 'https://api.weather.gov/gridpoints/PDT/34,40/forecast',
  iconUrl: 'https://api.weather.gov/icons/land/day/tsra_sct,50?size=medium',
  weather: 'Scattered Showers And Thunderstorms',
  temp: '51 F',
}, 
...
])
// Pobrane dane przypisane do zmiennej partials.weatherContext poprzez res.locals
const weatherMiddleware = async (req, res, next) => {
  if(!res.locals.partials) res.locals.partials = {}
  res.locals.partials.weatherContext = await getWeatherData()
  next()
}

// Export middleware jako moduł
module.exports = weatherMiddleware 

W pliku głównym dołączamy middleware

const weatherMiddleware = require('./lib/middleware/weather')
....
app.use( weatherMiddleware )

Wywołanie pliku (partials) w widoku (szablonie) np. /views/home.handlebars. Nazwa pliku z widgetem

{{> weather}}