Question

I know this is somewhat duplicated, but All my efforts to create a dynamic component renderer are failing possibly due to my lack of knowledge in ember concepts.

My Scenario is a multi purpose search bar which will search for models in the cache. I would like each search result to be rendered below the search input according to the model's type key. the handlebars file will be named according to the model type with the syntax components/app-search-<model-type-key>.hbs e.g. the template name for a customer model should be components/app-search-customer.hbs

my search template looks like this:

<div class="well well-md">
    <div class="input-group">
        {{input value=searchTerm class="form-control"}}
    </div>
    {{#if searchTerm}} <!-- Updating searchTerm causes results to populate with models -->
    {{#if results.length}}
    <ul class="list-group search-results">
        {{#each result in results}}
            <!-- todo -->
            {{renderSearchComponent model=result}}
        {{/each}}
    </ul>
    {{else}}
        Nothing here Captain
    {{/if}}
    {{/if}}
</div>

And my attempt at a renderSearchComponent helper looks like this:

Ember.Handlebars.registerHelper('renderSearchComponent', function(model, options) {
    var modelType = options.model.constructor.typeKey,
        componentPath,
        component,
        helper;
    if (typeof modelType === 'undefined') {
        componentPath = "app-search-default";
    } else {
        componentPath = "app-search-" + modelType;
    }
    component = Ember.Handlebars.get(this, componentPath, options),
    helper = Ember.Handlebars.resolveHelper(options.data.view.container, component);
    helper.call(this, options);
});

When this runs the options.model throws: TypeError: options.model is undefined and additionally i have the following error:

Error: Assertion Failed: Emptying a view in the inBuffer state is not allowed and should not happen under normal circumstances. Most likely there is a bug in your application. This may be due to excessive property change notifications.

I have been batting my eyelids for what seems hours now trying to get this right. Is what I am asking for even possible?

Thank you in advance.

Was it helpful?

Solution

I know this is a year old question, but Ember since version 1.11+ has the new component helper to dynamically render components.

{{#each model as |post|}}
  {{!-- either foo-component or bar-component --}}
  {{component post.componentName post=post}}
{{/each}}

OTHER TIPS

You were on the right path, a working example could be like:

import {handlebarsGet} from "ember-handlebars/ext";

Ember.Handlebars.registerHelper('renderSearchComponent', function(value, options) {

  var propertyValue;
  if (options) {

    if ( options.types[0] !== 'STRING' ) {
      var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this;
      propertyValue = handlebarsGet(context, value, options);
      propertyValue = propertyValue.constructor.typeKey;
    } else {
      propertyValue = value;
    }

  } else {
    options = value;
    propertyValue = 'default';
  }

  var property = 'app-search-'+propertyValue;
  var helper = Ember.Handlebars.resolveHelper(options.data.view.container, property);
  if (helper) {
    return helper.call(this, options);
  }

});

This helper allows to pass either string, nothing or binding property.

{{renderSearchComponent}}
{{renderSearchComponent 'book'}}
{{renderSearchComponent result}}

Helper internals are not completed documented, i think because they are not a public API. But you could take inspiration by looking at the helper source code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top