How to dynamically load ember components by name in a template?


#1

My question is basically the same as on this answer, but I can’t get the code to work with ember 1.7.0 and & ember-cli.

I have a widget property in my model, and in my template I want to have something like:

{{#each question in questions}}
{{#with question}}
  <label>{{title}}</label>
  {{render-component widget params=params}}
{{/with}}
{{/each}}

And a question model that looks like:

{ id: 6,
  title: "Is this a yes/no situation?",
  help_text: 'Pick an option',
  widget: 'yes-no',
  params:
  {
    yes: {
      text: 'You picked yes',
      class: 'success'
    },
    no: {
      text: 'Be careful, you picked no',
      class: 'danger'
    }
  }
}

I’ve created a render-component helper that contains the following:

import Ember from 'ember';

function renderComponent(componentPath, options) {
  console.log('inside helper with comp=' + componentPath + ', opts=' + options);
  var component = Ember.Handlebars.get(this, componentPath, options);
  var helper = Ember.Handlebars.resolveHelper(options.data.view.container, component);
  return helper.call(this, options);
}

export {
  renderComponent
};

export default Ember.Handlebars.makeBoundHelper(renderComponent);

But this doesn’t work. component is undefined. The API docs for Ember.Handlebars.get aren’t very helpful in explaining what the options parameter is. Also, there’s no mention of a resolveHelper method in the docs now, so I don’t know if the code is out of date anyway.

How can I load components by name from a variable?


Programmatically rendering ember components
Dynamically rendering a component via a template helper
#2

OK so I finally worked it out:

import Ember from 'ember';

function renderComponent(componentPath, options) {
  var helper = Ember.Handlebars.resolveHelper(options.data.view.container, componentPath);
  return helper.call(this, options);
}

export {
  renderComponent
};
export default Ember.Handlebars.makeBoundHelper(renderComponent);

#3

I use this to properly register components:

Ember.Application.initializer
  name: 'ui-search-field'
  initialize: (container, application)->
    container.register('component:ui-search-field', Ui.SearchFieldComponent)

#4

As of Ember 1.9, options.data.view.container no longer exists when using Ember.Handlebars.makeBoundHelper. I am currently trying to figure out where this went and how to go about rendering a component from inside a helper created via makeBoundHelper.

If anyone else has run into this, feel free to let me know what your solution was!


#5

+1 • I’m also facing the same issue. Any insight will be appreciated.


#6

I posted this in a new thread. The result there was to resurrect an old Github issue that suggests adding a built in helper to do this. Read through the issue for additional information.