Dynamic View Rendering In Ember 1.9


#1

Hello community,

I’m working on a project which is using ember 1.5.0. We developed a functionality to render dynamic content and works perfeclty (in Ember 1.5.0).

How it works

We have a helper which is called render-module.js:

export default Ember.Handlebars.makeBoundHelper(function(module, options) {
  options.types[0] = "STRING";

  var container = options.data.keywords.controller.container;
  var name = module.constructor.typeKey;
  if (!container.lookup('view:' + name)) {
    name = "module";
  }

  return Ember.Handlebars.helpers.render.call(this, name, "module", options);
});

A template which is called event.hbs and here is where we call the rendering helper :

<div class="modules-holder event-screen">
  <div {{bind-attr class=":modules-container view.columnsClass"}}>
    {{#each module in currentLayout.modules}}
      {{render-module module}}
    {{/each}}
  </div>
</div>

Finally we have differents views called <dynamic-module-name>-view. So, the template will render each view given in the currentLayout.modules array.

###Looking for a solution using Ember 1.9

We tried it a lot and we couldn’t find anything. Upgrading to Ember 1.9 will break the helper functionality. We also tried to implement a solution based on Dynamically render polymorphic component but with no results because we were able to render the views using that approach but the controllers (for that views) won’t be initialized.

Is there any approach to do this? We are stuck in it since two months ago.

Thanks a lot for reading this, we will be really thanksful if somebody could give us a hand !

Juan.


#2

I had similar issue like you did, although I couldn’t make the helper work, I did manage to get things working by making a wrapper view which may like this for you:

AS.RenderModuleView = Ember.View.extend({
    template: null,

    initialize: function () {
        var module= this.get('module'),
            name = module.constructor.typeKey;
    
        if (!container.lookup('view:' + name)) {
              name = "module";
       }
    
        this.set('template', Ember.Handlebars.compile('{{render "' + name + '" view.module}}'));
    }.on('init')
});

in hbs:

<div class="modules-holder event-screen">
  <div {{bind-attr class=":modules-container view.columnsClass"}}>
    {{#each module in currentLayout.modules}}
      {{view 'render-module' moduleBinding='module'}}
    {{/each}}
  </div>
</div>

#3

I’d shy away from using views at all, since they are basically going away in Ember 2.0.

Try something like https://www.npmjs.com/package/ember-dynamic-component


#4

I tried to use that but can’t init the controllers for each module. Do you have some example please?

Regards.


#5

Does it have to be Ember 1.9?

It looks like the feature ‘ember-htmlbars-component-helper’ might help you?

I’m not sure when it’s is going to be implemented by default, but you can enable it right now using a feature flag.


#6

Here is jsbin demonstrating this : http://emberjs.jsbin.com/gowufonuwi/1/


#7

Hi @Deewendra

I’ve been playing around with your JSBin for the past 2,3 days and I’ve been busy trying to create a Tabbed UI with Ember 1.10 and Bootstrap 3. I’ve been having some issues and questions and I would appreciate it if you and other friends on this topic could help clarify and achieve a solid implementation.

Out of the box, integrating your solution with my project worked fine. except the fact that my controllers weren’t being setup properly. for example the model hooks work fine and get resolved properly and passed down the chain to the setupController hook. you could confirm this by outputting the value of your controllers and models out to the console at various breakpoints (model hook, setupController, didInsertElement etc.). However, despite the fact that my models get resolved and passed to controllers without a problem, when you try to access your controllers from the View objects their properties return null. I’ve been trying to debug this issue for the past few hours. What I’ve found was, if you inspect the application with Ember Inspector (I’m using FireFox) you’ll find that when the render-module helper is being executed (within the each loop) the controller currently available to the RenderModuleView is the ApplicationController. which is odd, since the current view being rendered should have its corresponding controller available to it. for instance if we’re rendering two templates with the names Profile and Messages, then the controllers should be ProfileController and MessagesController respectively.

Another interesting thing to mention is that if you introduce an {{outlet}} in your application template, you’ll find that your desired template has been rendered correctly and the context (controller, model etc.) has been assigned properly. but I don’t want to use an outlet here, because with each route transition you’ll lose the rendered template, whereas I would like to keep them alive in the DOM, unless the user closes a tab item.

I’ve created a sample repo named ember-tabbed-ui. you can clone the project bower install then npm install and give it a try! I hope I’ve explained the situation clear enough, the source code is pretty much self explanatory, nothing fancy.

It’d be really cool if we could talk about this in depth and reach a solid, working implementation.

P.S some additional notes
Some features that you’ll find included in this demo repo are essential to what I’m trying to achieve. for instance, switching between the tabs will do a route transition, but in the beforeModel hooks of each route we have a check. where we see if the current route has been loaded before and is available in the Tabs Collection, which lives on the ApplicationController. If the answer is yes, we simply skip the model hook function.

Another thing is that there’s a close button rendered next to each Tab Item, except the Home tab, since its the root. this element is bound to an action controller, which simply removes the tab item from the collection.

Thanks in advance :sunglasses:


#8

Hi @inexuscore and @Deewendra,

Have you been able to determine the problem with the ApplicationController being used instead of the proper controller such that the model is not accessible from the view?

I’m trying to do virtually the same thing as @inexuscore with a tabbed layout where the tabs stay in the DOM after being activated until the tab is closed. If I can’t make this work, I’m going to have to ditch Ember and go back to my own homegrown jQuery based stuff.


#9

Guys in my example the each loop is within application context and hence the controller available to “RenderModuleView” is application controller. You could provide item level controller to the each look and then that would be the controller for the view. I was also able to access model via view. Here is a jsbin with models being logged from view : http://emberjs.jsbin.com/pugupeqoji/1/


#10

But does this render perform the actual working of a template and controller? I am unable to use “this.transitionToRoute” and the error thrown says “Cannot read property enter of undefined” and it talks about ControllerMixin.


#11

I am doing dynamic rendering in Ember 1.9 with the following helper:

export function helper(params, hash, options, env) {
    var model = this.get('context');
    var type = model.get('model.type') || model.get('type');
    params[0] = type;

    // pass modified parameters to underlying Ember render helper
    this.container.resolve('helper:render').helperFunction.call(this, params, hash, options, env);
}

And in the template:

{{ render-widget 'x' model }}

You need a name for the template even though you are not using it, hence ‘x’.