emberjs/ember.js — pull request #2490 by sebastianseilund (2013-04-18 05:26:40+00:00)
Title: Implemented Ember.control

This is a concrete implementation proposal of the `Ember.control` feature I suggested in the [Modal Views - can we agree on a best practice?](http://discuss.emberjs.com/t/modal-views-can-we-agree-on-a-best-practice/707/6) post on discuss.emberjs.com.

I think this is a very vital feature, which is missing in Ember right now. It makes it so elegant to programmatically create for example modal views. Something that requires a lot of boilerplate code to do today if you want your modal view to be controlled by a controller.

## Description

`Ember.control` lets you instantiate a controller + view pair that is not part of your normal routing flow.

This is very useful for programmatically creating views such as modals and popover menus that you want to use controller logic for, but don't represent a route.

You can call `this.control` from within controllers and routes.

Here is an example of using `this.control` from within a controller:

```javascript
App.PostsShowController = Ember.ObjectController.extend({
edit: function() {
var controller = this.control('posts.edit', this.get('model'));
}
});
```

Ember will, based on the `name` parameter, create a controller from the class `App.PostsEditController` (not a singleton),
a view from the class `App.PostsEditView`, and use the template `posts.edit` (normalized to `posts/edit`).
The naming convention works just like everything else in Ember, e.g. route names.

The second argument to `Ember.control` is an optional `model`. This will be set as the `model` property on your controller.

`Ember.control` returns the created controller. You can access the view through the controller with
`controller.get('view')`.

In the above example the modal controller and view could be defined like this:

```javascript
App.PostsEditController = Ember.ObjectController.extend({
save: function() {
//...commit model, and close when successful
this.close();
},
cancel: function() {
//...rollback any changes
this.close();
},
close: function() {
this.get('view').destroy(); //Or fade it out first, if you're really fancy
this.destroy();
}
});

App.PostsEditView = Ember.View.extend({
classNames: ['modal']
});
```

And the `posts/edit` template:

```handlebars

Edit post

{{input valueBinding="title"}}

Save Cancel
```

`Ember.control` also supports specifying an object with `controllerClass`, `viewClass`, `template` and `templateName` properties instead of a string in the `name` parameter. You can use this feature if your controller or view don't adhere to the naming conventions (which they should!). The following is equivalent to our example above:

```javascript
App.PostsShowController = Ember.ObjectController.extend({
edit: function() {
var controller = this.control({
controllerClass: App.PostsEditController,
viewClass: App.PostsEditView,
templateName: 'posts/edit',
template: Ember.Handlebars.compile('...')
}, this.get('model');
}
});
```

`controllerClass` is required. Either `viewClass` or one of `templateName` and `template` is required. If `viewClass`
is not set, a simple `Ember.View` will be used. You should only specify either `templateName` (the name of a template)
or `template` (a compiled template). If you don't set a template, the `viewClass`' template will be used.

From within the instantiated controller you can call `transitionToRoute`, use `needs` and anything else that a normal
controller supports.

-------------

Let's do this! What do people think?