Skip to content

Commit

Permalink
Add currentView property to Ember.ContainerView
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Dale committed May 3, 2012
1 parent 3e9dd6c commit 00b8940
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 4 deletions.
45 changes: 43 additions & 2 deletions packages/ember-views/lib/views/container_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,34 @@ var childViewsProperty = Ember.computed(function() {
And the `Ember.View` instance stored in `aContainer.aView` will be removed from `aContainer`'s
`childViews` array.
## Templates and Layout
A `template`, `templateName`, `defaultTemplate`, `layout`, `layoutName` or `defaultLayout`
property on a container view will not result in the template or layout being rendered.
The HTML contents of a `Ember.ContainerView`'s DOM representation will only be the rendered HTML
of its child views.
## Binding a View to Display
If you would like to display a single view in your ContainerView, you can set its `currentView`
property. When the `currentView` property is set to a view instance, it will be added to the
ContainerView's `childViews` array. If the `currentView` property is later changed to a
different view, the new view will replace the old view. If `currentView` is set to `null`, the
last `currentView` will be removed.
This functionality is useful for cases where you want to bind the display of a ContainerView to
a controller or state manager. For example, you can bind the `currentView` of a container to
a controller like this:
// Controller
App.appController = Ember.Object.create({
view: Ember.View.create({
templateName: 'person_template'
})
});
// Handlebars template
{{view Ember.ContainerView currentViewBinding="App.appController.view"}}
@extends Ember.View

This comment has been minimized.

Copy link
@trek

trek May 3, 2012

Member

👍 doc writing.

*/

Expand Down Expand Up @@ -319,7 +340,27 @@ Ember.ContainerView = Ember.View.extend({
} else {
this.domManager.prepend(this, view);
}
}
},

currentView: null,

_currentViewWillChange: Ember.beforeObserver(function() {
var childViews = get(this, 'childViews'),
currentView = get(this, 'currentView');

if (currentView) {
childViews.removeObject(currentView);
}
}, 'currentView'),

_currentViewDidChange: Ember.observer(function() {
var childViews = get(this, 'childViews'),
currentView = get(this, 'currentView');

if (currentView) {
childViews.pushObject(currentView);
}
}, 'currentView')
});

// Ember.ContainerView extends the default view states to provide different
Expand Down
140 changes: 138 additions & 2 deletions packages/ember-views/tests/views/container_view_test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
var get = Ember.get, getPath = Ember.getPath;
var get = Ember.get, getPath = Ember.getPath, set = Ember.set;

module("ember-views/views/container_view_test");

test("should be able to insert views after the DOM representation is created", function() {
var container = Ember.ContainerView.create({
classNameBindings: ['name'],

name: 'foo'
});

Expand Down Expand Up @@ -112,3 +111,140 @@ test("views that are removed from a ContainerView should have their child views
});
equal(getPath(view, 'childViews.length'), 0, "child views are cleared when removed from container view");
});

test("if a ContainerView starts with an empy currentView, nothing is displayed", function() {
var container = Ember.ContainerView.create();

Ember.run(function() {
container.appendTo('#qunit-fixture');
});

equal(container.$().text(), '', "has a empty contents");
equal(getPath(container, 'childViews.length'), 0, "should not have any child views");
});

test("if a ContainerView starts with a currentView, it is rendered as a child view", function() {
var container = Ember.ContainerView.create();
var mainView = Ember.View.create({
template: function() {
return "This is the main view.";
}
});

set(container, 'currentView', mainView);

Ember.run(function() {
container.appendTo('#qunit-fixture');
});

equal(container.$().text(), "This is the main view.", "should render its child");
equal(getPath(container, 'childViews.length'), 1, "should have one child view");
equal(getPath(container, 'childViews').objectAt(0), mainView, "should have the currentView as the only child view");
});

test("if a ContainerView starts with no currentView and then one is set, the ContainerView is updated", function() {
var container = Ember.ContainerView.create();
var mainView = Ember.View.create({
template: function() {
return "This is the main view.";
}
});

Ember.run(function() {
container.appendTo('#qunit-fixture');
});

equal(container.$().text(), '', "has a empty contents");
equal(getPath(container, 'childViews.length'), 0, "should not have any child views");

Ember.run(function() {
set(container, 'currentView', mainView);
});

equal(container.$().text(), "This is the main view.", "should render its child");
equal(getPath(container, 'childViews.length'), 1, "should have one child view");
equal(getPath(container, 'childViews').objectAt(0), mainView, "should have the currentView as the only child view");
});

test("if a ContainerView starts with a currentView and then is set to null, the ContainerView is updated", function() {
var container = Ember.ContainerView.create();
var mainView = Ember.View.create({
template: function() {
return "This is the main view.";
}
});
container.set('currentView', mainView);

Ember.run(function() {
container.appendTo('#qunit-fixture');
});

equal(container.$().text(), "This is the main view.", "should render its child");
equal(getPath(container, 'childViews.length'), 1, "should have one child view");
equal(getPath(container, 'childViews').objectAt(0), mainView, "should have the currentView as the only child view");

Ember.run(function() {
set(container, 'currentView', null);
});

equal(container.$().text(), '', "has a empty contents");
equal(getPath(container, 'childViews.length'), 0, "should not have any child views");
});

test("if a ContainerView starts with a currentView and then is set to null, the ContainerView is updated", function() {
var container = Ember.ContainerView.create();
var mainView = Ember.View.create({
template: function() {
return "This is the main view.";
}
});
container.set('currentView', mainView);

Ember.run(function() {
container.appendTo('#qunit-fixture');
});

equal(container.$().text(), "This is the main view.", "should render its child");
equal(getPath(container, 'childViews.length'), 1, "should have one child view");
equal(getPath(container, 'childViews').objectAt(0), mainView, "should have the currentView as the only child view");

Ember.run(function() {
set(container, 'currentView', null);
});

equal(container.$().text(), '', "has a empty contents");
equal(getPath(container, 'childViews.length'), 0, "should not have any child views");
});

test("if a ContainerView starts with a currentView and then a different currentView is set, the old view is removed and the new one is added", function() {
var container = Ember.ContainerView.create();
var mainView = Ember.View.create({
template: function() {
return "This is the main view.";
}
});

var secondaryView = Ember.View.create({
template: function() {
return "This is the secondary view.";
}
});

container.set('currentView', mainView);

Ember.run(function() {
container.appendTo('#qunit-fixture');
});

equal(container.$().text(), "This is the main view.", "should render its child");
equal(getPath(container, 'childViews.length'), 1, "should have one child view");
equal(getPath(container, 'childViews').objectAt(0), mainView, "should have the currentView as the only child view");

Ember.run(function() {
set(container, 'currentView', secondaryView);
});

equal(container.$().text(), "This is the secondary view.", "should render its child");
equal(getPath(container, 'childViews.length'), 1, "should have one child view");
equal(getPath(container, 'childViews').objectAt(0), secondaryView, "should have the currentView as the only child view");
});

2 comments on commit 00b8940

@ppcano
Copy link
Contributor

@ppcano ppcano commented on 00b8940 May 3, 2012

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tomdale, perhaps, it could be useful to extend the feature to be able to pass an extended view. I have many view definitions like the one below:

Em.ContainerView.extend({
    childViews: ['child'],
    child: Em.View.extend({
         ....
    })
});

@tomdale
Copy link
Member

@tomdale tomdale commented on 00b8940 May 6, 2012

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ppcano Yep, we discussed doing that, as well as the ability to provide the currentView as a string.

Please sign in to comment.