Rendering specific templates for each model


#1

I’m trying to create an app where each model object contains as one of its attributes the template in which it should be rendered. Example:

{
    "parent_widget": {
        "id": "myParentWidget",
        "template": "<h1>\n  {{title}}\n</h1>\n{{#each child_widgets}}\n<p>widget {{title}}</p>\n{{view App.ChildWidgetView}}\n{{/each}}\n",
        "title": "Parent Widget",
        "child_widget_ids": [
            "childWidget1",
            "childWidget2",
            ...
        ],
    }
    "child_widgets": [
        {
            "id": "childWidget1",
            "template": "<h1>\n  {{title}}\n</h1><p>Hello from ChildWidget1</p>\n",
            "title": "Child Widget 1"
        },
       ...
    ]
}

In this example, the templates are obviously very similar, but pretend they’re more complicated, and what I’m trying to do actually makes sense.

I’ve gotten this working for the parent widget part, but setting the route object to render the template:

App.ParentWidgetRoute = Ember.Route.extend
  model: (params) ->
    App.ParentWidget.find(params.parent_widget_id)

  renderTemplate: (controller, model) ->
    template = Ember.Handlebars.compile(model.get("template"))
    Ember.TEMPLATES[model.get("slug")] = template
    @render(model.get("slug"))

App.ChildWidgetView = Ember.View.extend
  template: (widget) ->
    template = Ember.Handlebars.compile(widget.get("template"))
    template

Question 1: Is there an alternative/better way to do this? From reading the source, it looks like I have to have the template in the TEMPLATES object, because that’s the only way that Route.render knows how to find it.

Question 2: From reading the Ember.js guides, I thought what I wanted inside the {{#each child_widgets}} would be a {{render "childWidget" this}}, but that doesn’t seem to do anything, nothing ever gets rendered, and no errors are thrown. From some debugging console.log statements I added, the ChildWidgetView’s template method it never called. If I make my own ChildWidgetController, it never gets used either, but I’m probably setting it up wrong. Is render the right thing to use here?

Question 3: I managed to get the ChildWidgetView used when I use {{view App.ChildWidgetView} instead of render. However, rather than rendering the template, it seems like its rendering the handlebars function instead. I get this in my html output:

<div id="ember353" class="ember-view">function (context, options) {
      options = options || {};
      var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
      ...snip...
      return result;
    }</div>

The View.render method looks like something I don’t want to override, so what’s the proper way to return the template here? Just returning widget.get("template") from that function just outputs it unrendered, <h1>{{title}}</h1>.

I know what I’m trying to accomplish is a bit off the beaten path, but it seems like it should be possible. I’m pretty close, I just need a bit of help understanding the internals to get the last part here.

TIA, Paul


#2

I pinged @wycats on IM about it, he linked me to this: http://jsbin.com/onadUt/3/edit

I’ll see about incorporating this, and add another reply with my final solution.