I like @darthdeus’ approach number 1 the most. That is, creating the modal programmaticaly. A modal often doesn’t have its own state in the router, and it’s self-contained, so blending it in with outlets seems a little weird.
The modal should consist of a view and a controller though. And it should be trivial to connect the two. Preferrably Ember should do it for you.
Proposal: Ember.control(name, model, properties)
I think a really good solution would be to make it possible to programmatically do what the {{control}} handler does for templates.
This could be done by adding a new method to Ember. It could be named Ember.control, and should take three arguments:
name: Which, just like with routes,{{render}}, and{{control}}infers which controller, view and template should be used.name = 'deleteUser', would useApp.DeleteUserController,App.DeleteUserViewand the view’stemplateNamewill default todelete_user.model: An optional object, which will be set as themodelproperty on the controller.propertiesAn optional hash of extra properties to be set on the controller.
When Ember.control is invoked, Ember should do the following:
- Instantiate a controller and a view of the classes determined by the general naming convention and
name. The controller is not a singleton, just like with{{control}}, as we might want to have multiple modals with the same controller class, but different models. - Set the
modelobject as the controller’smodelproperty. - Set the view as the controller’s
viewproperty. - Apply each key in
propertiesto the controller. They should not be set on the view, because all logic and data storage belongs in controllers. - Return the controller. The controller should be returned, because:
- There is no reason to create another object to be returned.
- If the app needs access to the view, it can do so through the controller’s
viewproperty.
A use case for Ember.control can be seen here:
//This is the /users route's controller, whose template has a button with an action that calls `showDeleteConfirmationModal`
App.UsersIndexController = Ember.Controller.extend({
showDeleteConfirmationModal: function(user) {
//This is how you instantiate a control, just like {{control}} would do it in a template
var deleteUserController = Ember.control('deleteUser', user, {
something: 111 //These properties goes on the controller
});
//`deleteUserController` would normally be self-contained, so normally you don't need to manipulate it, but you get the controller instance here in case you need to close it programmatically from somewhere else.
});
//In this app we have modals, where the controller should implement this mixin to support closing the window
App.ModalControllerMixin = Ember.Mixin.create({
close: function() {
this.willClose();
this.get('view').destroy();
this.destroy();
},
willClose: Em.K
});
//Specific modal views should extend this, so they get wrapped in a div, gets a close button etc.
App.ModalView = Ember.View.extend({
layout: 'modal',
classNames: ['modal'],
init: function() {
this._super();
this.append();
//Should probably check with some manager instance what zindex it should have, create mask element, etc.
}
})
//This is a concrete modal controller.
//We can put all logic in a controller, where it belongs
App.DeleteUserController = Ember.ObjectController.extend(App.ModalControllerMixin, {
isDeletable: function() {
return this.get('model.organizations.length') == 0;
}
});
//This is a concrete modal view
//We can put view events in the view, where they belong
App.DeleteUserView = App.ModalView.extend({
});
I think this is a very clean solution. I only need to define the generic behavior of modals in my app once. From there on all I need to do to implement a new concrete modal is to define a controller, a view, and a template, and call Ember.control('someName', someObject). And any of the controller, view and template are optional, just like they are with routes.
Ember.control would be useful for anything that’s not part of the common route handling, and has “it’s own life”. Popover menus, dropdown menus, combobox selector panels, etc.
The implementation of Ember.control would be rather simple. I would love to make a pull request to the repo, if people agree with me that this is a nice design.
What do people think?
I would like to include @wycats and @tom in this discussion as I think this would be a vital feature of Ember.