Menu Close

Server-Side Development with Hapi.js — View Helpers and Layouts

Hapi.js is a small Node framework for developing back end web apps.

In this article, we’ll look at how to create back end apps with Hapi.js.

View Helpers

We can add view helpers to our app.

For example, we can write:

index.js

const Path = require('path');
const Hapi = require('@hapi/hapi');
const Hoek = require('@hapi/hoek');

const context = {
  title: 'My personal site'
};

const init = async () => {
  const server = new Hapi.Server({
    port: 3000,
    host: '0.0.0.0',
    debug: { request: ['error'] }
  });
  await server.register(require('@hapi/vision'));
  server.views({
    engines: {
      html: {
        module: require('handlebars'),
        compileMode: 'sync'
      },
    },
    relativeTo: __dirname,
    path: 'templates',
    helpersPath: './templates/helpers',
    context
  });

  server.route({
    method: 'GET',
    path: '/',
    handler (request, h) {
      return h.view('index');
    }
  });

  await server.start();
  console.log('Server running at:', server.info.uri);
};
process.on('unhandledRejection', (err) => {
  console.log(err);
  process.exit(1);
});
init();

templates/helpers/fortunes.js

module.exports = () => {
  const fortunes = [
    'Wanna buy a duck?',
    'Say no, then negotiate.',
    'Time and tide wait for no man.',
    'To teach is to learn.',
    'Never ask the barber if you need a haircut.',
    'You will forget that you ever knew me.',
    'You will be run over by a beer truck.',
    'Fortune favors the lucky.',
    'Have a nice day!'
  ];

  const x = Math.floor(Math.random() * fortunes.length);
  return fortunes[x];
};

We create the fortune.js which has a function we exported.

It returns the value we want to display.

In index.html , we interpolate the value of the helper name to displayed the returned value:

<p>{{fortune}}</p>

And then we specify the path to the template helpers with the helpersPath property.

Now when we go to the / page, we see a random fortune displayed.

Layouts

We can add our layouts in their own files.

For example, we can write:

index.js

const Path = require('path');
const Hapi = require('@hapi/hapi');
const Hoek = require('@hapi/hoek');

const context = {
  title: 'My personal site'
};

const init = async () => {
  const server = new Hapi.Server({
    port: 3000,
    host: '0.0.0.0',
    debug: { request: ['error'] }
  });
  await server.register(require('@hapi/vision'));
  server.views({
    engines: {
      html: {
        module: require('handlebars'),
        compileMode: 'sync'
      },
    },
    relativeTo: __dirname,
    path: 'templates',
    layout: true,
    layoutPath: 'templates/layout',
  });

  server.route({
    method: 'GET',
    path: '/',
    handler (request, h) {
      return h.view('index');
    }
  });

  await server.start();
  console.log('Server running at:', server.info.uri);
};
process.on('unhandledRejection', (err) => {
  console.log(err);
  process.exit(1);
});
init();

templates/layout/layout.html

<html>
  <body>
    {{{content}}}
 </body>
</html>

templates/index.html

<div>Content</div>

We set the layout property to true to let us use layout files for layouts.

Then we set the layoutPath to set the layout path.

In layout.html , we have:

{{{content}}}

to display the content.

And in templates/index.html , we have the content.

We can also specify a different layout per view.

For instance, we can write:

const Path = require('path');
const Hapi = require('@hapi/hapi');
const Hoek = require('@hapi/hoek');

const context = {
  title: 'My personal site'
};

const init = async () => {
  const server = new Hapi.Server({
    port: 3000,
    host: '0.0.0.0',
    debug: { request: ['error'] }
  });
  await server.register(require('@hapi/vision'));
  server.views({
    engines: {
      html: {
        module: require('handlebars'),
        compileMode: 'sync'
      },
    },
    relativeTo: __dirname,
    path: 'templates',
    layout: true,
    layoutPath: 'templates/layout',
  });

  server.route({
    method: 'GET',
    path: '/',
    handler (request, h) {
      return h.view('index', null, { layout: 'another_layout' });
    }
  });

  await server.start();
  console.log('Server running at:', server.info.uri);
};
process.on('unhandledRejection', (err) => {
  console.log(err);
  process.exit(1);
});
init();

templates/layout/another_layout.html :

<html>
  <body>
    <b>{{{content}}}</b>
 </body>
</html>

We specify the layout we want to use by writing:

h.view('index', null, { layout: 'another_layout' });

The layout property has the name of the layout file we want to use.

Conclusion

We can render layouts and helpers in views with Hapi.

Posted in Hapi