2
votes

ContainerView.pushObject() does not automatically wire-up dynamically added views with a Container object. The lack of an auto-wired container causes a render failure when a view renders a template that contains a handlebars render helper.

SIMPLE CASE THAT WORKS (KIND OF)

View:

App.DynamicView = Em.View.extend({
    templateName: 'dynamic',
    didInsertElement: function() {
        var control = this.get('controller');
        control.send( 'view_inserted',  this.templateName, control._debugContainerKey);
        control.send('callDynamicController');
    }
});

Template:

<script type="text/x-handlebars" data-template-name="dynamic">
    dynamic
</script>

Controller (only used when manually assigned):

App.DynamicController = Em.ObjectController.extend({
    className: 'App.DynamicWithRenderController',
        callDynamicController: function() {
            console.log('DynamicController.callDynamicController()');
    }
});

Index Controller:

App.IndexController = Em.ObjectController.extend({
    view_inserted: function(aview, acontroller) { 
        console.log('view inserted!', aview, acontroller);
    }
})

Instantiation code:

var acontainer = App.DynamicController.create({});
var aview = App.DynamicView.create({ controller: acontroller })
acontainerView.pushObject(aview);

These classes render & behave as expected, but if you interogate them, lack some of the Ember-wiring (e.g. no _debugContainerKey & container properties IIRC):

MORE ADVANCED CASE THAT BREAKS

If we introduce a handlebars template that uses rendering helpers, it breaks rendering. The dynamically added view currently lacks some properties the rendering helper assumes

<script type="text/x-handlebars" data-template-name="dynamic-with-render">
    dynamic w/render:
    {{render knob}}
</script>

and make knob look like this:

<script type="text/x-handlebars" data-template-name="knob">
    &#123;&#123;render knob&#125;&#125;
</script>

The (failing) dynamic view instantiation code:

var acontainer = App.DynamicController.create({});
var aview = App.DynamicView.create({ 
    controller: acontroller, 
    template:'dynamic-with-render' })
acontainerView.pushObject(aview);

CODE EXAMPLE

A fuller example with some notes can be seen here:

http://jsfiddle.net/AshCoolman/KyJ2U/6/embedded/result/

NOTE: My tests include a custom handlebars helper based of the control helper called controlWithVars

THE PROBLEM

It looks like I need to write something that does the Ember-wiring, in either:

  1. the more native ContainerView (getting into the Ember guts), OR
  2. a more de-coupled new render helper possibly inelegant)

I'm not sure how to proceed. It would be great if someone has already come up with an elegant solution, or at least could give me some helpful tips.

EDIT: So it looks like creating and assigning a container, which includes the views dependencies might be a solution. Thoughts anyone?

HELPFUL READING

https://github.com/emberjs/ember.js/issues/2108

What is the purpose of the Ember.Container

http://mcdowall.info/posts/ember-application-initializers/

1

1 Answers

2
votes

The raison d'être of Ember.ContainerView is for dynamically adding and removing views, so I'm pretty confident you can do all the things you want to with it.

One thing I noticed in your examples is that you are creating your child views with View.create(attrs). It is important to use containerView.createChildView(viewClassName, attrs) to create views that get the container, parent view hierarchy, and more. See the implementation more details:

https://github.com/emberjs/ember.js/blob/master/packages/ember-views/lib/views/view.js#L2072