5. • Namespaces are good. Less globals, less conflicts.
• Files map to modules. Could be useful!
• Manage dependencies in JS. Better/simpler build pipeline
and re-usability.
Oh, maybe we should use modules….
Modules for JS
Friday, July 12, 13
9. • When do you declare an object un-used?
• What about nested collections of objects?
• How do you reset singletons during tests?
Oh, maybe we should use an Inversion of Control
Container….
Herding objects is hard.
Friday, July 12, 13
11. • Namespaces are good. Less globals, less conflicts.
App.everythingIsNotASolution
• Often, it will be useful to attach a dependency based on
type.
• Knowing and possibly stubbing dependencies in tests
would be nice.
Oh, maybe we should use Dependency Injection….
Dependencies between objects
Friday, July 12, 13
14. • Factories receive instance variables.
• Resolvers find factories.
• Containers manage injections.
Three Components
Friday, July 12, 13
15. 1 var Factory = Ember.Object.extend();
2
3 // Receives instance variables as a new instance.
4 Factory.create(injections);
5
6 // Can receive injections for future instances.
7 Factory.extend(injections);
8
9
10 // Today in Ember, injections are only sent to instances.
11 // Don't worry yourself about this too much, it may change.
Ember Factories
Friday, July 12, 13
16. Ember Resolvers
1 Ember.DefaultResolver = Ember.Object.extend({
2 namespace: null,
3
4 resolve: function(fullName) {
5 var parsedName = this.parseName(fullName);
6
7 // Some magic for specific types, but usually getting to:
8 return this.resolveOther(parsedName);
9 },
10
11 resolveOther: function(parsedName) {
12 var className = classify(parsedName.name) + classify(parsedName.type),
13 factory = get(parsedName.root, className);
14 if (factory) { return factory; }
15 }
16 })
Resolves fullNames like controller:application
Must provide `resolve`
Friday, July 12, 13
17. Ember Containers
1 var container = new Ember.Container();
2
3 container.register('worker:uploader', MyUploader);
4 container.injection('controller', 'uploader', 'worker:uploader');
5
6 container.resolve('worker:uploader'); //=> MyUploader
7 container.lookup('worker:uploader'); //=> instance of MyUploader
8
9 container.lookup('controller:application').get('uploader');
10 //=> same instance of MyUploader
11
12 container.reset();
Friday, July 12, 13
19. In your own app
Thus, `worker` is available on FilePickerController instances
1 var App = Ember.Application.create();
2
3 App.register('worker:uploader', MyUploader);
4 App.inject('controller:filePicker', 'worker', 'worker:uploader');
5
6 // Ah, so simple.
Friday, July 12, 13
20. In Ember Data
1 Ember.onLoad('Ember.Application', function(Application) {
2 Application.initializer({
3 name: "store",
4
5 initialize: function(container, application) {
6 application.register('store:main', application.Store);
7
8 // Eagerly generate the store so defaultStore is populated.
9 // TODO: Do this in a finisher hook
10 container.lookup('store:main');
11 }
12 });
13
14 Application.initializer({
15 name: "injectStore",
16
17 initialize: function(container, application) {
18 application.inject('controller', 'store', 'store:main');
19 application.inject('route', 'store', 'store:main');
20 }
21 });
22 });
Thus, `store` is available on controllers and routes
Friday, July 12, 13
24. In your own app
Thus, `worker` is available on FilePickerController instances
1 var App = Ember.Application.create();
2
3 App.register('worker:uploader', MyUploader);
4 App.inject('controller:filePicker', 'worker', 'worker:uploader');
5
6 // Ah, so simple.
GLOBAL
Flashback to…
Friday, July 12, 13
25. • Namespaces are good. Less globals, less conflicts.
• Files map to modules. Could be useful!
• Manage dependencies in JS. Better/simpler build pipeline
and re-usability.
Oh, maybe we should use modules….
Modules for JS
Flashback to…
Friday, July 12, 13
29. Ember Resolvers
1 Ember.DefaultResolver = Ember.Object.extend({
2 namespace: null,
3
4 resolve: function(fullName) {
5 var parsedName = this.parseName(fullName);
6
7 // Some magic for specific types, but usually getting to:
8 return this.resolveOther(parsedName);
9 },
10
11 resolveOther: function(parsedName) {
12 var className = classify(parsedName.name) + classify(parsedName.type),
13 factory = get(parsedName.root, className);
14 if (factory) { return factory; }
15 }
16 })
Resolves fullNames like controller:application
Must provide `resolve`
Flashback to...
IM
PLIES
APP.SOM
ETHING
Friday, July 12, 13
30. 1 module "appkit/app" {
2 var App = Ember.Application.create();
3
4 import applicationTemplate from "appkit/templates/application";
5 Em.TEMPLATES['application'] = applicationTemplate;
6
7 export default App;
8 // <script type="text/javascript">import App from “appkit/app”;</script>
9 }
10
11 module "appkit/templates/application" {
12 var template = Ember.Handlebars.compile("Howdy Washington!");
13 export default template;
14 }
Quick fix...
But do that for everything? No way.
Friday, July 12, 13
31. • Factories receive instance variables.
• Resolvers find factories.
• Containers manage injections.
Three Components
Flashback to…
OH
HAI
Friday, July 12, 13
32. 80 function resolveOther(parsedName) {
81 var prefix = this.namespace.modulePrefix;
82 Ember.assert('module prefix must be defined', prefix);
83
84 var pluralizedType = typeMap[parsedName.type] || parsedName.type;
85 var name = parsedName.fullNameWithoutType;
86
87 var moduleName = prefix + '/' + pluralizedType + '/' + underscore(name);
88 var module;
89
90 if (define.registry[moduleName]) {
91 module = requireModule(moduleName);
92
93 if (typeof module.create !== 'function') {
94 module = classFactory(module);
95 }
96
97 if (Ember.ENV.LOG_MODULE_RESOLVER){
98 Ember.logger.info('hit', moduleName);
99 }
100
101 return module;
102 } else {
103 if (Ember.ENV.LOG_MODULE_RESOLVER){
104 Ember.logger.info('miss', moduleName);
105 }
106
107 return this._super(parsedName);
108 }
109 }
/vendor/loader.js
Friday, July 12, 13
33. 1 module "appkit/app" {
2 var App = Ember.Application.create();
3 export default App;
4 // <script type="text/javascript">import App from “appkit/app”;</script>
5 }
6
7 module "appkit/templates/application" {
8 var template = Ember.Handlebars.compile("Howdy Washington!");
9 export default template;
10 }
Ember & ES6 modules, no hacks
Friday, July 12, 13
34. • Views
• Controllers
• Templates
• Routes
Today, works with...
Yay, good-guy classes are fetched via containers
Friday, July 12, 13
35. • Some Views
• Models
• Helpers
Today, busted with...
Boo, Scumbag classes are not referenced via the container
Friday, July 12, 13
36. • Subcontainers. Flush only part of the app.
• Singleton controllers live forever. Problem? Feature?
• Ember.Container could become a micro-lib. Uses no
Ember internally.
The future
Friday, July 12, 13