Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?

This document aims to help aggregate issues and solutions around the defaultContainer deprecation.

The Error Message:

Using the defaultContainer is no longer supported. [defaultContainer#lookup]

breaux, where's my defaultContainer?

Well it is still there, and will continue to work for some time. Likely it will be gone by 1.0.0 final

Why is this happening.

We recieved several issues, these issues were non-obvious but it appeared that they where caused by the defaultContainer leaking between tests. This obviously lead to very unexpected test failures. The quick fix was obviously to ensure the defaultContainer was purged between tests. Upon further investigation, almost all the issues turned out to be childViews which were not wired up correctly. For example not using this.createChildView on creation of childViews. Ultimately, the existence of the defaultContainer was masking the reported issues, and likely many more. In addition the obvious issues, we are trying to remove our dependency on globals (but that is another story).

migration paths: (WIP)

if you are creating dynamic views in the context of the parentView, you should be using:

this.createChildView(viewClass, viewAttributes)

if you are creating views outside the context of a parentView (this may not be recommended, but it is happening) you will want to make sure to instantiate your view via the container itself.

this.container.lookup('view:apple')
// will provide a instance of apple view.

how container lookups are resolved

Action items

  • appendTo another ember view, should then grab the container of that view.
  • continue to flush out this gist
  • improve docs/guides
  • improve deprecation warnings
  • explore methods where this works without developer thought (without perf regressions)

fixes in the wild:

But I have a legitmate usecase not expressed here.

Post a comment, describing the issue, and hopefully a jsbin or jsfiddle demonstrating the issue. As time permits, a solution or migration path will finds its way up into this document.

Q/A

Q: can we not have views get a container by default? The App gets a container right?

A: App is the root, and as such it creates the initial container.

Q: So when I do createChildView, which container is that using?

A: typically, it is using the container passed down the view hierarchy, and this typically occurs at creation.

Q: Could we set the container when you append it to a container view's childViews array?

A: likely, but its not just the container, it is a place for the framework to wire-up other things. https://github.com/emberjs/ember.js/blob/master/packages/ember-views/lib/views/view.js#L2072

(ask questions in the comments and I will hoist them here.)

@cyril-sf

This comment has been minimized.

Copy link

commented May 23, 2013

It looks good and it will definitely help people.

@pivotal-medici

This comment has been minimized.

Copy link

commented May 24, 2013

Nice work. Thanks for this.

-- AK

@fanta

This comment has been minimized.

Copy link

commented May 28, 2013

thanks for the heads up on this.

@stefanpenner

This comment has been minimized.

Copy link
Owner Author

commented May 28, 2013

@cyril-sf, @pivotal-medici, @MikeAski & @fanta thanks for your corrections.

@nightire

This comment has been minimized.

Copy link

commented Jun 2, 2013

I'm not quite sure whether I understand this correctly, I've encountered this issue just now when I try to do this:

window.App = Ember.Application.create({
  ready: function() {
    App.AChildView.create().append();
  }
})

Ok, I got what I want in browser, but meantime Ember.js throw me a deprecation warning:

Using the defaultContainer is no longer supported. [defaultContainer#lookup]

After read your article, I'm still confused about how to do this right. Is this means the ApplicationView is not a ContainerView, so I should create & append the AChildView in another place? or I was totally do this in the wrong way?

@edimoldovan

This comment has been minimized.

Copy link

commented Jun 2, 2013

@stefanpenner
Hey Stefan,
In this case, how should I use createChildView? I seam to have a problem with it. Also, I would like to pass some custom context to those views. How should I do that in here?

for (i=0;i<portlets.length;i+=1) {
    index = Ember.String.classify(portlets[i].name) + "View";
    newView = App[index].create();
    App.LayoutContainer.pushObject(newView);
}
@pivotal-medici

This comment has been minimized.

Copy link

commented Jun 3, 2013

@stefanpenner how do you propose we handle setting the currentView?

-- AK

@stefanpenner

This comment has been minimized.

Copy link
Owner Author

commented Jun 13, 2013

@pivotal-medici & @edimoldovan emberjs/ember.js#2821 should handle your scenarios.

@nightire by default the ApplicationView is correctly appended to the rootElement for you, container and all. This view will be setup correctly and all its children and descendants should also be setup for you. If you choose to append a view yourself, which is totally allowed, although not needed in many situations, you must setup the dependencies correctly yourself.

When appending a root view yourself, you will typically do this within the router, not from Application#ready. That being said, ember is flexible and allows you to solve the problem in many ways. Can you provide a more detail example so i can understand your intent?

@edimoldovan

This comment has been minimized.

Copy link

commented Jun 13, 2013

That looks perfect, let me give that a delightful tryout! :) Thank you!

@stefanpenner

This comment has been minimized.

Copy link
Owner Author

commented Jun 14, 2013

@edimoldovan let me know how it goes.

@pixelchild

This comment has been minimized.

Copy link

commented Jun 25, 2013

@nightire I was doing the exact same.. I've ended up changing it for something like this instead

App.IndexRoute = Ember.Route.extend({
    setupController: function (controller)
    {
         App.AChildView.create({container: this.container}).append();
    }
});
@dlpatri

This comment has been minimized.

Copy link

commented Jul 18, 2013

So... I have an interesting scenario that I don't see brought up here yet (either that or I'm just not understanding something).

I've been in the process of creating a rather large CRUD application with 14 data types to manage (more will be coming later); so as I've been creating this application, I've been developing a "component" library that is capable of auto-generating Twitter Bootstrap forms from JSON.

For one of my newest form components, the user can see a list of items, edit them, remove them, or add to them. When adding or editing, a generated Modal Form pops up to capture the user's input with the Modal's own Form Element.

So... the Ember View that creates the list and "Add" button are all inside of the "main" Form; meanwhile the Modal needs to be added to the DOM so that it can expose it's own Form.

I only just got that bit working today... before, I just didn't have the Modal expose a Form, and it was just embedded in the parent view. But then there were interesting side-effects when property names collide and just the general lack of HTML5 Form Validation.

Here is how my "ItemList" component is currently managing the ModalForm. (Note: It's pretty rough at the moment since I'm really just trying to get things to work)

App.ItemListView = App.ControlGroupView.extend
  templateName: 'bootstrap/itemList'

  didInsertElement: ->
    @_super()

    modalName = @get 'content.property'

    modalForm = App.ModalFormView.create
      parentView        : @
      contentBinding    : 'parentView.content'
      componentsBinding : 'content.edit'
      name              : modalName
      elementId         : modalName + "Modal"
    modalForm.append()

    @set 'modalForm', modalForm

  willDestroyElement: ->
    @_super()
    @modalForm.remove()

So, if there's a much better way to do something like this, please let me know. If not, I'd prefer to be able to append Views to the DOM when needed. It isn't often.

@dlpatri

This comment has been minimized.

Copy link

commented Jul 18, 2013

Never mind my earlier comments. For some reason I thought that View.append() was deprecated. And then, I didn't realize that, "this.container.lookup('view:apple')" would actually create a new instance of the view.

So, for anyone else as confused as I was, just replace your View.create call with "this.container.lookup(...)".

@Adriaaaaan

This comment has been minimized.

Copy link

commented Jul 26, 2013

So does this mean we can't use layoutName in views anymore??

App = Ember.Application.create();

App.aView = Ember.View.extend({
    layoutName:'index',
    templateName:'lorem'
});
App.aView.create().append();

I haven't seen any mention of how to use the layoutName.

@H1D

This comment has been minimized.

Copy link

commented Aug 6, 2013

@stefanpenner how to unit test views now? To get a controller I need to initialize application.
Restarting whole application at each unit-test seems weird and slow.

Now I'm using this approach:

test 'a test', ->
    a_view = App.AView.create();
    return Em.run ->
      a_view.appendTo($('#fixture'));
@stefanpenner

This comment has been minimized.

Copy link
Owner Author

commented Aug 23, 2013

@H1D you merely need to create a container per unit test, and ensure the view has a container, and the template can be fetched from the container.

This ensues proper isolation.

@knownasilya

This comment has been minimized.

Copy link

commented Sep 4, 2013

@dlpatri thanks for clarifying that. Is it possible to pass a hash to the lookup? I just used setters after the fact, which works as well.

@leonelag

This comment has been minimized.

Copy link

commented Sep 10, 2013

@stefanpenner Care to update the Views guide at http://emberjs.com/guides/views/defining-a-view/ ?
As an Ember noob, on my first 20 minutes following it, I have just been bitten by this commit.

@mayatskiy

This comment has been minimized.

Copy link

commented Nov 7, 2013

@velesin

This comment has been minimized.

Copy link

commented Nov 12, 2013

@stefanpenner "you merely need to create a container per unit test, and ensure [...] the template can be fetched from the container". Can you provide some example how this should be correctly configured? Right now in my tests I'm using (probably not correct) hack:

Ember.View.create({ container: App.__container__ });

From your comment I understood that I should be creating a new, isolated container instance for my tests (plus configure it somehow so the template can be fetched from it) - but I have no idea what is the correct way to do this?

@stefanpenner

This comment has been minimized.

Copy link
Owner Author

commented Dec 12, 2013

@velesin

container.register('view:foo', FooView , { singleton true });
container.lookup('view:foo') // instance of theview
@jmorvan

This comment has been minimized.

Copy link

commented Jan 7, 2014

How should I proceed in the case where I am creating dynamic view from a loop:

switch (itm.type) {
            case "Page":
                view = Ember.ContainerView.create({classNames: itm.options.class, elementId: itm.id});
                break;
            case "Row":
                view = Ember.ContainerView.create({classNames: itm.options.class, elementId: itm.id});
                break;
            case "Container":
                view = Ember.ContainerView.create({classNames: itm.options.class, elementId: itm.options.id});
                break;
}

Am I doing this wrong by extending views in this manner?

I could potentially have dozens of different itm.type and I would like to avoid having to explicitly declare a class for each.

@H1D

This comment has been minimized.

Copy link

commented Apr 3, 2014

Here is the setup I'm using:


post_view = container = null
module "Post View",
  setup: ->
    container = new Em.Container
    container.optionsForType 'template', { instantiate: false }
    container.register 'template:post', Ember.Handlebars.compile('{{text}}')

    post_view = App.PostView.create(context: {text:'foo'}, container: container)
    Em.run ->
      post_view.createElement()
      post_view.set 'context', step
  teardown: ->
    Ember.run ->
      post_view.destroy()
      container.destroy()

test "renders 'text' property", 1, ->
  equal post_view.$().text(), 'foo', 'rendered text doesn\'t match context'

Note container.optionsForType, otherwise ember will try to call create() on template (i.e. instantiate). Also I was surprised that Em.Container is probably the only object you have to instantiate using new

@happycollision

This comment has been minimized.

Copy link

commented May 5, 2014

I changed a bit of my code based on a suggestion by @pixelchild for @nightire to no avail:

App.SomeRoute = Ember.Route.extend({
    someFunction: function(){
        App.myViewHolder = App.MyView.create({container: this.container});
        App.myViewHolder.append();
    }
});

I am still getting this deprecation warning when someFunction is called. 😕

All I really want to do is append a couple elements to the DOM when I am in a certain route.

Update: Seems that it was actually a run loop issue. I was changing my target to window by mistake.

@tachang

This comment has been minimized.

Copy link

commented Jun 30, 2014

I'm lost.

window.Application = Ember.Application.create();

var view = Ember.View.create({
templateName: 'info',
name: "Bob"
});
view.appendTo(''#info');

I do this and get this warning. But this is from the docs: http://emberjs.com/guides/views/defining-a-view/

@ghost

This comment has been minimized.

Copy link

commented Jul 7, 2014

Please update the guide.

@stefanpenner

This comment has been minimized.

Copy link
Owner Author

commented Jul 25, 2014

@hannicolas im unsure what needs to be updated?

@richardkmichael

This comment has been minimized.

Copy link

commented Aug 22, 2014

@stefanpenner The example in the guide poses problems for newcomers (me). I can't tell you what it should say (because I'm just learning Ember), but as @tachang also mentions, I expected (something like the guide's example):

<!-- index.html -->
...
<head>
  <!-- Other script tags for Ember itself and dependencies omitted. -->
  <script type="x-handlebars" data-template-name="foo-view-template">
    Hello, World! from foo view
  </script>
  <script src="myapp.js"></script>
</head>
// myapp.js -- only this content, nothing else.

var app = Ember.Application.create();  // Is this even necessary?

var fooView = Ember.View.create({
  templateName: "foo-view-template"
});

fooView.append();

.. to display a page containing:

<body>
  <!-- Possibly other stuff in index.html, followed by... -->
  Hello World! from foo view
</body>

.. but instead the console prints (the git.io link points to this gist):

Uncaught Error: Container was not found when looking up a views template. This is most likely due to manually instantiating an Ember.View. See: http://git.io/EKPpnA
@supairish

This comment has been minimized.

Copy link

commented Sep 1, 2014

@richardkmichael I'm having the same problem, did you find a fix?

@johnmcdowall

This comment has been minimized.

Copy link

commented Sep 7, 2014

@richardkmichael @supairish @stefanpenner I've found that changing from .create to .extend from making new view for insertion prevents the deprecation warning from being triggered when you set a templateName. YMMV.

@avaz

This comment has been minimized.

Copy link

commented Oct 26, 2014

The docs of Route.loading event is showing an example of the old way: [http://emberjs.com/api/classes/Ember.Route.html#event_loading]
How this would be with the this.container.lookup strategy? I mean, what is the best way to pass the 'classNames' is the example in the Route.loading of create and append views?
I'm willing to update the docs but I'm don't know for what put in the example.

@markmilman

This comment has been minimized.

Copy link

commented Nov 28, 2014

I'm trying to use Ember component in an existing rails app as part of gradually migrating the view layer created by rails to Ember and form a single page app.
I have used the following code, which works in 1.5.0 but throws the deprecation warning (and therefore breaks in 1.8) . Will appreciate any help to get this working in 1.8.0:

Sbcx.MaterialsListComponent = Ember.Component.extend({
  layoutName: 'components/materials-list'
  materialList: null

  actions: {
    remove: (m)->
      console.log('removed ' + m.get('name'))
      m.destroyRecord()
  }
})


$(document).ready ->

  Sbcx.store.find("material").then (result) ->
    $(".component-placeholder").each ->
      # Build the component & stuff in any pre-existing value
      component = Sbcx.MaterialsListComponent.create(materialList: result)

      # Gut out the container div & replace with the component
      component.replaceIn this
@yanni4night

This comment has been minimized.

Copy link

commented Dec 9, 2014

This is really confused,I am going to skip this page guide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.