By Oleksii Rudenko August 13, 2015 8:42 PM
How to render an HTMLBars template to a string in Ember 2.0?

Sometimes you need to do uncommon things like rendering a template to a string. Before Ember Views were deprecated one could do the following to render a template to a string:

var controller = Ember.Controller.create({
  name: 'templateToString'
});

var view = Ember.View.create({
  template: template,
  controller: controller,
  container: container
});

view.createElement();
return view.element.innerHTML;

In Ember 2.0.0 there is no Ember.View anymore and 1-to-1 replacement of Ember.View with Ember.Component does not work because the way the rendering works was changed with Glimmer.

Nevertheles I have found a bit hacky solution for my use case which I would like to share. The following snippet defines a function that renders a template to a string. Unlike the previous method, it’s asynchronous and returns a promise:

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

// container is needed to have access to app helpers, components etc.
var container = null;

Ember.Application.instanceInitializer({
  name: 'template-to-string',
  initialize: function(instance) {
    // grab the container using the instance initializer
    container = instance.container;
  }
});

// when you call this function
// app initialization must be finished
export default function(template) {
  return new Ember.RSVP.Promise(function(resolve) {
  // create a new component 
    var component = Ember.Component.create({
      style: 'display:none;', // hide it
      layout: template, // specify your template as a layout
      container: container // provide container
    });
    // subscribing to didRender event
    component.on('didRender', function() {
      // no we can grab the result of rendering
      var el = component.element.innerHTML;
      // remove the component
      this.remove();
      resolve(el);
    })

    // append the component to the body to make it render
    component.append();
  })
}

Here is an example of using it:

// /some-route.js
import templateToString from 'ember-template-to-string';

model: function () {
  // it accepts a pre-compiled template
  return templateToString(Ember.TEMPLATES['my-template']).then(
    function (tmpl) { // and returns a string via `tmpl` var
      return {
        templateAsString: tmpl
      };
    }
  );
}

I am not sure if it’s the best solution or if it’s reliable but currently it works for me. Thanks for reading and post alternative solutions to the problem if you know some.