Ernesto
Ernesto

Reputation: 4017

Render ember.js .hbs template to a string

I currently can do the following:

var template = Handlebars.compile("Hello <em>{{name}}</em>!");
var html = template({ name: 'World' });

The html variable now holds the string "Hello <em>World</em>!".

But how can I do the same with a template whose code is in a .hbs file inside my app/templates directory?

(I'm using ember-cli with ember 1.9.1)

Upvotes: 4

Views: 1828

Answers (1)

Ed .
Ed .

Reputation: 6403

In Ember 1.13.15 this will work (UPDATE to work with v2.4 at the bottom):

// template-to-string.js
import Ember from 'ember';

export default function(container, template, context) {
  let resolvedTemplate =
    typeof template === 'string' ? container.lookup('template:' + template) : template;
  context = context || {};

  Ember.assert(`Template '${template}' could not be resolved`, !!template);

  return new Ember.RSVP.Promise((resolve) => {

    Ember.Component.create(Ember.merge({
      style: 'display:none;',
      layout: resolvedTemplate,
      container,

      didRender() {
        resolve(this.$().html());
        this.destroy();
      }
    }, context)).append();

  });
}

It's based on a solution proposed in this post: How to Render an HTMLBars Template to a String in Ember 2.0? where further explanation is offered.

I have extended to support passing in a template context.

Use the function like so:

// my-component.js
import Ember from 'ember';
import templateToString from './template-to-string';

export default Ember.Component.extend({

  _appendMyChildTemplate() {
    let myTemplateContext = ...;

    templateToString(this.container, '<my-template-path>', myTemplateContext)
     .then((html) => {
       this.$().append(html);
     });
  }

})

Update to work in Ember 2.4:

I can't claim to fully understand this or that it is anywhere near the best solution, but it works :)

Not massively different from the function above:

import Ember from 'ember';

export default function(container, template, context) {
  let resolvedTemplate =
    typeof template === 'string' ? container.lookup('template:' + template) : template;
  context = context || {};

  Ember.assert(`Template '${template}' could not be resolved`, !!template);

  return new Ember.RSVP.Promise((resolve) => {

    Ember.Component.extend(Ember.merge({
      style: 'display:none;',
      layout: resolvedTemplate,
      container,

      init() {
        this._super.apply(this, arguments);
        Ember.setOwner(this, container);
      },

      didRender() {
        resolve(this.$().html());
        this.destroy();
      }
    }, context))
      .create()
      .append();

  });
}

Upvotes: 4

Related Questions