7
votes

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!

3
Do you want to use bindings or some other ember tecnology in that generated dom? Or is just something visual, and it isn't important? What is your third party libray?Marcio Junior
It's codemirror.net and yes - I need to use bindings in the generated dom. Not to sync the code in the editor, but to add extra visual widgets to the editor.Andrei Soare
This hack was suggested on IRC, but it seems to create some ugly side effects after switching through a couple of routes: jsbin.com/owepeh/1Andrei Soare
nice @AndreiSoare that works, however, we adding the run.next code ? it works without itfanta
Yeah, it seems to work without run.next. But as I said, it introduces some side effects: when leaving the route and entering it again, other issues start to appear :-sAndrei Soare

3 Answers

0
votes

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.

4
votes

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

0
votes

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