Andrei Soare
Andrei Soare

Reputation: 180

How do I programmatically add child views to an Ember view at specific DOM selectors?

I have a view that uses a 3rd party library to render additional DOM elements in the didInsertElement hook. After these new elements are added, I need to add some child views inside them, so that they can render dynamic data.

Here's what I tried:

App.MyView = Ember.View.extend({
  didInsertElement: function() {
    create3rdPartyDomElements();
    var element = this.$('someSelector');
    childView = this.createChildView(App.SomeViewClass, attributesDict);
    childView.appendTo(element);
  }
});

(jsbin: http://jsbin.com/idoyic/3)

This renders my views as expected, but gives the following assertion error with Ember RC 7: "You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead."

I have tried extending ContainerView, as advised here and that works, but I have no way of inserting the child views at specific DOM selectors. It just inserts the child views at the beginning of the parent view.

Can someone please help me? Thanks a lot!

Upvotes: 7

Views: 3748

Answers (3)

jesenko
jesenko

Reputation: 1293

You can render child views into parent view's hidden div, and then detach and append them to arbitrary DOM elements in didInsertElement hook.

http://jsbin.com/qaqome/1/

For related issue (components instead of views) see also this question.

Upvotes: 0

Marcio Junior
Marcio Junior

Reputation: 19128

This is how I created:

An implementation where you have the main view, in that case codemirror, in the middle. And it's possible add more views, in the top or bottom.

App.EditorView = Ember.View.extend({
  templateName: 'editor-view',
  topView: Ember.ContainerView.extend(),
  bottomView: Ember.ContainerView.extend(),
  CodeMirrorView: Ember.TextArea.extend({  
    didInsertElement: function() {      
      this.codeMirror = CodeMirror.fromTextArea(this.get('element'));                  
    }
  })
});

The template:

<script type="text/x-handlebars" data-template-name="editor-view">
  {{view view.topView viewName="topViewInstance"}}
  {{view view.CodeMirrorView}}
  {{view view.bottomView viewName="bottomViewInstance"}}
</script>

A view to represent a custom component:

App.MyComponent = Ember.View.extend({
  templateName: 'click-here',
  message: null,
  click: function() {
    alert(this.get('message'));
  }
});

The implementation:

App.MyEditorView = App.EditorView.extend({  
  didInsertElement: function() {
    this._super();
    this.get('topViewInstance').pushObject(App.MyComponent.create({ message: "Hello" }));

    this.get('bottomViewInstance').pushObject(App.MyComponent.create({ message: "World" }));
  }
});

With this is possible to create a new instance, or extend App.EditorView and insert more views in top or bottom. Because the topView and bottomView are Ember.ContainerViews, all views added will have the bindings, events, and other ember features.

Give a look in that jsbin to see it working http://jsbin.com/ucanam/686/edit

Upvotes: 4

fanta
fanta

Reputation: 1489

try adding a property in your view, something like this:

App.MyView = Ember.View.extend({
  childViewsContainer: Em.ContainerView.create({}),
  didInsertElement: function() {
    create3rdPartyDomElements();
    var element = this.$('someSelector');
    childViewsContainer.createChildView(App.SomeViewClass, attributesDict);
    childView.appendTo(element);
  }
});

then, you can access your childViewsContainer and do what ever you want with it

Upvotes: 0

Related Questions