or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

express-integration.mdhelper-management.mdindex.mdpartial-management.md
tile.json

helper-management.mddocs/

Helper Management

Register and manage Handlebars helper functions, including asynchronous helpers with callback support for complex operations.

Capabilities

Synchronous Helpers

Register standard Handlebars helpers that return values immediately.

/**
 * Register synchronous helper function
 * @param name - Helper name to use in templates
 * @param helper - Helper function that returns a value
 */
function registerHelper(name, helper);

Usage Examples:

const hbs = require('hbs');

// Simple string helper
hbs.registerHelper('uppercase', function(str) {
  return str.toUpperCase();
});

// Helper with multiple parameters
hbs.registerHelper('link_to', function(title, url) {
  return '<a href="' + url + '">' + title + '</a>';
});

// Block helper
hbs.registerHelper('list', function(items, options) {
  let out = '<ul>';
  for (let i = 0; i < items.length; i++) {
    out += '<li>' + options.fn(items[i]) + '</li>';
  }
  return out + '</ul>';
});

// Helper with context access
hbs.registerHelper('conditional', function(v1, operator, v2, options) {
  switch (operator) {
    case '==':
      return (v1 == v2) ? options.fn(this) : options.inverse(this);
    case '!=':
      return (v1 != v2) ? options.fn(this) : options.inverse(this);
    default:
      return options.inverse(this);
  }
});

In Templates:

<!-- Simple helper -->
{{uppercase "hello world"}}
<!-- Output: HELLO WORLD -->

<!-- Helper with parameters -->
{{{link_to "Google" "https://google.com"}}}
<!-- Output: <a href="https://google.com">Google</a> -->

<!-- Block helper -->
{{#list people}}
  {{name}} - {{age}}
{{/list}}

<!-- Conditional helper -->
{{#conditional score ">=" 90}}
  Grade: A
{{else}}
  Grade: B or lower
{{/conditional}}

Asynchronous Helpers

Register helpers that perform asynchronous operations like API calls, file I/O, or database queries.

/**
 * Register asynchronous helper function
 * @param name - Helper name to use in templates
 * @param helper - Helper function that calls callback with result
 */
function registerAsyncHelper(name, helper);

Usage Examples:

const hbs = require('hbs');
const fs = require('fs');

// File reading helper
hbs.registerAsyncHelper('readFile', function(filename, callback) {
  fs.readFile(filename, 'utf8', (err, data) => {
    if (err) {
      callback('Error reading file');
    } else {
      callback(data);
    }
  });
});

// API call helper
hbs.registerAsyncHelper('fetchUserName', function(userId, callback) {
  // Simulate API call
  setTimeout(() => {
    const users = { 1: 'Alice', 2: 'Bob', 3: 'Charlie' };
    callback(users[userId] || 'Unknown User');
  }, 100);
});

// Helper with multiple parameters
hbs.registerAsyncHelper('formatDate', function(date, format, callback) {
  // Simulate async date formatting
  process.nextTick(() => {
    const formatted = new Date(date).toLocaleDateString();
    callback(formatted);
  });
});

// Helper with context access
hbs.registerAsyncHelper('checkPermission', function(action, callback) {
  // this.user would be available from template context
  const user = this.user || {};
  
  // Simulate permission check
  setTimeout(() => {
    const hasPermission = user.permissions && user.permissions.includes(action);
    callback(hasPermission ? 'Allowed' : 'Denied');
  }, 50);
});

In Templates:

<!-- File content helper -->
<pre>{{readFile "config.txt"}}</pre>

<!-- User data helper -->
<p>Welcome, {{fetchUserName userId}}!</p>

<!-- Date formatting helper -->
<span>Created: {{formatDate createdAt "short"}}</span>

<!-- Permission helper -->
<div class="status">{{checkPermission "admin"}}</div>

Handlebars Access

Direct access to the underlying Handlebars instance for advanced operations.

/**
 * Direct access to Handlebars instance
 * @type HandlebarsStatic
 */
handlebars;

Usage Examples:

const hbs = require('hbs');

// Access Handlebars directly
const SafeString = hbs.handlebars.SafeString;
const Utils = hbs.handlebars.Utils;

// Use Handlebars SafeString in helpers
hbs.registerHelper('safeHtml', function(html) {
  return new SafeString(html);
});

// Use Handlebars utilities
hbs.registerHelper('escapeExpression', function(str) {
  return hbs.handlebars.Utils.escapeExpression(str);
});

// Register helper on Handlebars directly (not recommended)
hbs.handlebars.registerHelper('directHelper', function() {
  return 'Registered directly';
});

Helper Context and Options

All helpers receive the current template context as this and access to Handlebars options.

Context Access

hbs.registerHelper('contextExample', function() {
  // Access current template data
  console.log('Current context:', this);
  
  // Access specific properties
  return this.someProperty || 'default';
});

Block Helper Options

Block helpers receive an options parameter with additional functionality:

hbs.registerHelper('blockExample', function(options) {
  // options.fn - renders the block content
  // options.inverse - renders the {{else}} content
  // options.hash - contains hash parameters
  // options.data - contains @index, @first, @last, etc.
  
  return options.fn(this); // Render block content
});

Hash Parameters

Helpers can accept named parameters via hash notation:

hbs.registerHelper('withDefaults', function(options) {
  const defaults = {
    color: 'blue',
    size: 'medium',
    ...options.hash // Override with provided values
  };
  
  return `<div class="${defaults.color} ${defaults.size}">Content</div>`;
});

In Template:

{{withDefaults color="red" size="large"}}
<!-- Output: <div class="red large">Content</div> -->

Async Helper Coordination

Asynchronous helpers are automatically coordinated so templates wait for all async operations to complete before rendering.

Async Flow:

  1. Template parsing identifies async helper calls
  2. Each async helper receives a unique callback
  3. Template rendering waits for all callbacks to complete
  4. Final template output includes all async results
  5. Placeholders are replaced with actual values

Multiple Async Helpers:

hbs.registerAsyncHelper('slowHelper1', function(callback) {
  setTimeout(() => callback('Result 1'), 100);
});

hbs.registerAsyncHelper('slowHelper2', function(callback) {
  setTimeout(() => callback('Result 2'), 200);
});

In Template:

<p>{{slowHelper1}} and {{slowHelper2}}</p>
<!-- Template waits for both helpers, then outputs: -->
<!-- <p>Result 1 and Result 2</p> -->