SlideShare uma empresa Scribd logo
1 de 87
Baixar para ler offline
Hi. I’m Matthew.
@mixonic
httP://madhatted.com
matt.beale@madhatted.com
201 Created
We build õ-age apps with Ember.js. We take
teams from £ to • in no time flat.
http://bit.ly/ember-nyc-edge
WHAT IS EMBER MADE OF?
• MVC FRamework
• MVC FRamework
• Models
• Views
• Controllers
• MVC FRamework
• Models
• Views
• Controllers
• Components
• ROUTES
• Router
• templates
• MVC FRamework
• Models
• Views
• Controllers
• Components • Store
• Serializers
• ROUTES
• adapters
• Router
• templates
SO MANY THINGS
What makes a

router different from a template?
What makes a

router different from a template?
• maps routes to states
• only one router
• instance of a class
• App.Router
• Has access to store (ED)
What makes a

router different from a template?
• maps routes to states
• only one router
• instance of a class
• App.Router
• Has access to store (ED)

• presents html
• many templates
• just functions
• on Ember.templates
What makes things similar?
What makes things similar?
• Shared Interface
1 App.IndexView = Ember.Object.extend({
2
click: function(){ alert('click!'); },
3
appendTo: function(){ /* ... */ },
4
render: function(){ /* ... */ },
5
rerender: function(){ /* ... */ }
6
// ...
7 });
1 App.IndexView = Ember.Object.extend({
2
click: function(){ alert('click!'); },
3
appendTo: function(){ /* ... */ },
4
render: function(){ /* ... */ },
5
rerender: function(){ /* ... */ }
6
// ...
7 });
1 App.WidgetView = Ember.Object.extend({
2
click: function(){ alert('widget!'); },
3
appendTo: function(){ /* ... */ },
4
render: function(){ /* ... */ },
5
rerender: function(){ /* ... */ }
6
// ...
7 });
1 Ember.View = Ember.Object.extend({
2
appendTo: function(){ /* ... */ },
3
render: function(){ /* ... */ },
4
rerender: function(){ /* ... */ }
5 });
1 App.IndexView = Ember.View.extend({
2
click: function(){ alert('click!'); }
3 });
1 App.WidgetView = Ember.View.extend({
2
click: function(){ alert('widget!'); }
3 });
What makes things similar?
• Shared Interface (superclass?)
App.IndexView = Ember.View.extend({ // ...
What makes things similar?
• Shared Interface (superclass?)

App.IndexView = Ember.View.extend({ // ...

• SHARED DEPENDENCIES
1 App.IndexRoute = Ember.Route.extend({
2
actions: {
3
didTransition: function(){
4
Ember.run.once(this, function(){
5
trackAnalytics(this.get('router.url'));
6
});
7
}
8
}
9 });
What makes things similar?
• Shared Interface (superclass?)

App.IndexView = Ember.View.extend({ // ...

• SHARED DEPENDENCIES
this.get('router'); // In a route
What makes things similar?
• Shared Interface (superclass?)

App.IndexView = Ember.View.extend({ // ...

• SHARED DEPENDENCIES

this.get('router'); // In a route

• SHAREd USAGE

Ember.Component.extend({

!
!
Ember.Controller.extend({

!
!
Ember.Handlebars.compile("

!
Is A

Ember.Component.extend({

!
!
Ember.Controller.extend({

!
!
Ember.Handlebars.compile("

!

!
!
Class

!
!
Class

!
!
Function
Is A

Ember.Component.extend({

!
!
Ember.Controller.extend({

!
!
Ember.Handlebars.compile("

!

Instantiate?

!
!

!
!
!
!
!
!
!
!
!

Class

!
!
Class

!
!
Function

✓
✓
✗
Is A

Ember.Component.extend({

!
!
Ember.Controller.extend({

!
!
Ember.Handlebars.compile("

!

Instantiate?

New every time?

!
!

!
!
!
!
!
!
!
!
!

!
!
!
!
!
!
!
!
!

Class

!
!
Class

!
!
Function

✓
✓
✗

✓
✗
✗
What makes things similar?
• Shared Interface (superclass?)

App.IndexView = Ember.View.extend({ // ...

• SHARED DEPENDENCIES

this.get('router'); // In a route

• SHAREd USAGE

Instantiate all the controllers, but return the same one each time
What makes things similar?
• Shared Interface (superclass?)

App.IndexView = Ember.View.extend({ // ...

• SHARED DEPENDENCIES

this.get('router'); // In a route

• SHAREd USAGE

Instantiate all the controllers, but return the same one each time

• SHARED DISCOVERY
What makes things similar?
• Shared Interface (superclass?)

App.IndexView = Ember.View.extend({ // ...

• SHARED DEPENDENCIES

this.get('router'); // In a route

• SHAREd USAGE

Instantiate all the controllers, but return the same one each time

• SHARED DISCOVERY
App.ColorPickerComponent

Ember.TEMPLATES['index']

App.Car
What makes things similar?
• Shared Interface (superclass?)

App.IndexView = Ember.View.extend({ // ...

• SHARED DEPENDENCIES

this.get('router'); // In a route

• SHAREd USAGE

Instantiate all the controllers, but return the same one each time

• SHARED DISCOVERY
App.ColorPickerComponent

Ember.TEMPLATES['index']

App.Car
What makes things similar?
• Shared Interface (superclass?)

App.IndexView = Ember.View.extend({ // ...

• SHARED DEPENDENCIES

this.get('router'); // In a route

• SHAREd USAGE

Instantiate all the controllers, but return the same one each time

• SHARED DISCOVERY
App.ColorPickerComponent

Ember.TEMPLATES['index']

App.Car
CONTAINERS
The container organizes
Ember’s building blocks.
The container re-organizes
Ember’s building blocks.
The container organizes new
building blocks.
register/lookup
register a factory into a container
1
2
3
4
5
6
7
8
9
10
11
12

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: /* take a job and run it, add workers if needed */
});
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.lookup('workerPool:main'); // -> Instance of WorkerPool
container.lookup('workerPool:main'); // -> Same instance of WorkerPool
register a factory into a container
1
2
3
4
5
6
7
8
9
10
11
12

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: /* take a job and run it, add workers if needed */
});
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.lookup('workerPool:main'); // -> Instance of WorkerPool
container.lookup('workerPool:main'); // -> Same instance of WorkerPool

singleton (always the same instance)
register like factories into a container
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: /* take a job and run it, add workers if needed */
});
var BigPool = WorkerPool.extend({ limit: 10 });
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('workerPool:big', BigPool);
container.lookup('workerPool:main'); // -> Instance of WorkerPool
container.lookup('workerPool:big'); // -> Instance of BigPool
register like factories into a container
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: /* take a job and run it, add workers if needed */
});
var BigPool = WorkerPool.extend({ limit: 10 });
var container = new Ember.Container();
container.register('workerPool:main', BigPool);
container.register('workerPool:big', BigPool);
container.lookup('workerPool:main'); // -> Instance of BigPool
container.lookup('workerPool:big'); // -> Different instance of BigPool
register non-singleton factories into a container

1
2
3
4
5
6
7
8
9
10
11

var Worker = Ember.Object.extend({
run: function(){ /* run a job */ }
});
var container = new Ember.Container();
container.register('worker:sync', Worker, {singleton: false});
container.lookup('worker:sync'); // -> Instance of Worker
container.lookup('worker:sync'); // -> New instance of Worker
container.lookup('worker:sync'); // -> New instance of Worker!
register non-class factories into a container

1
2
3
4
5
6
7
8
9
10
11

var container = new Ember.Container();
container.register('logger:alert', window.alert, {instantiate: false});
container.register('logger:console', function(msg){
window.console.log(msg);
}, {instantiate: false});
container.lookup('logger:alert'); // -> alert function
container.lookup('logger:console'); // -> console.log function
container.lookup('logger:console')('Howdy!'); // -> "Howdy!"
injection + dependency lookup
a wild dependency appears
1
2
3
4
5
6
7
8
9
10
11
12
13
14

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: function(job){
this.get('logger')('Began job.')
/* take a job and run it, add workers if needed */
}
});
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
var pool = container.lookup('workerPool:main');
pool.submitJob(job);
a wild dependency appears
1
2
3
4
5
6
7
8
9
10
11
12
13
14

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: function(job){
this.get('logger')('Began job.')
/* take a job and run it, add workers if needed */
}
});

Need a logger

var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
var pool = container.lookup('workerPool:main');
pool.submitJob(job);
Inject a dependency on a factory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: function(job){
this.get('logger')('Began job.')
/* take a job and run it, add workers if needed */
}
});
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('logger:alert', window.alert, {instantiate: false});
container.injection('workerPool:main', 'logger', 'logger:alert');
var pool = container.lookup('workerPool:main');
pool.submitJob(job);
Inject a dependency on a factory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: function(job){
this.get('logger')('Began job.')
/* take a job and run it, add workers if needed */
}
});
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('logger:alert', window.alert, {instantiate: false});
container.injection('workerPool:main', 'logger', 'logger:alert');
var pool = container.lookup('workerPool:main');
pool.submitJob(job);
Inject a dependency on a factory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: function(job){
this.get('logger')('Began job.')
/* take a job and run it, add workers if needed */
}
});
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('logger:alert', window.alert, {instantiate: false});
container.injection('workerPool:main', 'logger', 'logger:alert');
var pool = container.lookup('workerPool:main');
pool.submitJob(job);

control over the dependency
Inject a dependency on a type
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: function(job){
this.get('logger')('Began job.')
/* take a job and run it, add workers if needed */
}
});
var BigPool = WorkerPool.extend({ limit: 10 });
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('workerPool:big', BigPool);
container.register('logger:alert', window.alert, {instantiate: false});
container.injection('workerPool', 'logger', 'logger:alert');
var pool = container.lookup('workerPool:big');
pool.submitJob(job);
Inject a dependency on a type
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: function(job){
this.get('logger')('Began job.')
/* take a job and run it, add workers if needed */
}
});
var BigPool = WorkerPool.extend({ limit: 10 });
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('workerPool:big', BigPool);
container.register('logger:alert', window.alert, {instantiate: false});
container.injection('workerPool', 'logger', 'logger:alert');
var pool = container.lookup('workerPool:big');
pool.submitJob(job);
Inject a dependency on a type
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: function(job){
this.get('logger')('Began job.')
/* take a job and run it, add workers if needed */
}
});
var BigPool = WorkerPool.extend({ limit: 10 });
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('workerPool:big', BigPool);
container.register('logger:alert', window.alert, {instantiate: false});
container.injection('workerPool', 'logger', 'logger:alert');
var pool = container.lookup('workerPool:big');
pool.submitJob(job);

control over the dependency
a wild dependency appears
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
limit: 3,
submitJob: function(job){
this.get('logger')('Began job.')
/* take a job and run it, add workers if needed */
}
});

Need worker

var BigPool = WorkerPool.extend({ limit: 10 });
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('workerPool:big', BigPool);
container.register('logger:alert', window.alert, {instantiate: false});
container.injection('workerPool', 'logger', 'logger:alert');
var pool = container.lookup('workerPool:big');
pool.submitJob(job);
Lookup a dependency
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

var Worker = Ember.Object.extend({
run: function(){ /* run a job */ }
});
var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
noWorkerAvailable: /* check for a free worker */,
limit: 3,
submitJob: function(job){
if (this.get('noWorkerAvailable')) {
var worker = this.container.lookup('worker:sync');
worker.run(job);
this.get('workers').pushObject(worker);
} // else find a free worker in the pool and run
}
});
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('worker:sync', Worker, {singleton: false});
var pool = container.lookup('workerPool:main');
pool.submitJob(job);
Lookup a dependency
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

var Worker = Ember.Object.extend({
run: function(){ /* run a job */ }
});
var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
noWorkerAvailable: /* check for a free worker */,
limit: 3,
submitJob: function(job){
if (this.get('noWorkerAvailable')) {
var worker = this.container.lookup('worker:sync');
worker.run(job);
this.get('workers').pushObject(worker);
} // else find a free worker in the pool and run
}
});
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('worker:sync', Worker, {singleton: false});
var pool = container.lookup('workerPool:main');
pool.submitJob(job);
Lookup a dependency
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

var Worker = Ember.Object.extend({
run: function(){ /* run a job */ }
});
var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
noWorkerAvailable: /* check for a free worker */,
limit: 3,
submitJob: function(job){
if (this.get('noWorkerAvailable')) {
var worker = this.container.lookup('worker:sync');
worker.run(job);
this.get('workers').pushObject(worker);
} // else find a free worker in the pool and run
}
});

control over the dependency

var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('worker:sync', Worker, {singleton: false});
var pool = container.lookup('workerPool:main');
pool.submitJob(job);
dynamically Lookup a dependency
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

var WorkerPool = Ember.Object.extend({
workers: /* an array of workers */,
noWorkerAvailable: /* check for a free worker */,
limit: 3,
submitJob: function(job){
if (this.get('noWorkerAvailable')) {
var worker = this.container.lookup(
'worker:'+(job.get('isAsync') ? 'async' : 'sync')
);
worker.run(job);
this.get('workers').pushObject(worker);
} // else find a free worker in the pool and run
}
});
var container = new Ember.Container();
container.register('workerPool:main', WorkerPool);
container.register('worker:sync', Worker, {singleton: false});
container.register('worker:async', AsyncWorker, {singleton: false});
var pool = container.lookup('workerPool:main');
pool.submitJob(job);
Injection places control
outside the target, lookup
makes it internal.
resolving factories
resolve to namespace
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

function capitalize(str){
return str.charAt(0).toUpperCase() + str.slice(1);
}
var MyScope = {};
MyScope.SyncWorker = Ember.Object.extend({
run: function(){ /* run a job */ }
});
var container = new Ember.Container();
container.resolve = function(name){
var parts = name.split(':'),
className = capitalize(parts[1])+capitalize(parts[0]);
return MyScope[className];
}
var worker = container.lookup('worker:sync', {instantiate: false});
resolve to AMD module
1
2
3
4
5
6
7
8
9
10
11
12
13
14

define('workers/sync', function(){
return Ember.Object.extend({
run: function(){ /* run a job */ }
});
});
var container = new Ember.Container();
container.resolve = function(name){
var parts = name.split(':'),
moduleName = parts[0]+'s/'+parts[1];
return require(moduleName);
}
var worker = container.lookup('worker:sync', {instantiate: false});
THE application CONTAINER
Ember applications use a
single container.
Several ways to access it
• Everything from a container has this.container

1 App.IndexView = Ember.View.extend({
2
router: function(){
3
return this.container.lookup('router:main');
4
}.property()
5 });
Several ways to access it
• Everything from a container has this.container


router: function(){ return this.container.lookup('router:main'); }.property()!

• App.register, App.Inject


App.register('analytics:google', App.GoogleAnalytics);!
App.inject('controller', 'analytics', 'analytics:google');!
Several ways to access it
• Everything from a container has this.container


router: function(){ return this.container.lookup('router:main'); }.property()!

• App.register, App.Inject


App.register('analytics:google', App.GoogleAnalytics);!
App.inject('controller', 'analytics', 'analytics:google');!

• In Initializers

App.initializer({
name: 'analytics',
/* before: 'optionallyBeforeThis' */
initialize: function(container, application){
application.register('analytics:google', App.GoogleAnalytics);
container.injection('controller', 'analytics', 'analytics:google');
}
})
Several ways to access it
• Everything from a container has this.container


router: function(){ return this.container.lookup('router:main'); }.property()!

• App.register, App.Inject


App.register('analytics:google', App.GoogleAnalytics);!
App.inject('controller', 'analytics', 'analytics:google');!

• In Initializers


App.initializer({ initialize: function(container, application){ // ...

• needs

App.AnalyticsController = Ember.Controller.extend();
App.IndexController = Ember.Controller.extend({
needs: ['analytics'],
analytics: Ember.computed.alias('controllers.analytics')
});

!
Several ways to access it
• Everything from a container has this.container


router: function(){ return this.container.lookup('router:main'); }.property()!

• App.register, App.Inject


App.register('analytics:google', App.GoogleAnalytics);!
App.inject('controller', 'analytics', 'analytics:google');!

• In Initializers


App.initializer({ initialize: function(container, application){ // ...

• needs

App.AnalyticsController = Ember.Controller.extend();
App.IndexController = Ember.Controller.extend({
needs: ['analytics'],
analytics: Ember.computed.alias('controllers.analytics')
});

!
…and one unsafe way.
// Never, ever use this in application code
App.__container__
how the container
powers ember
ember Finds a template

1 Ember.View = Ember.CoreView.extend({
2
3
templateForName: function(name, type) {
4
if (!name) { return; }
5
Ember.assert("templateNames are not allowed to contain periods: "+name, name.indexOf('.') ==
6
7
// the defaultContainer is deprecated
8
var container = this.container || (Ember.Container && Ember.Container.defaultContainer);
9
return container && container.lookup('template:' + name);
10
},
11
// ...
12 });

view.js
ember Finds a template
1 Ember.DefaultResolver = Ember.Object.extend({
2
3
resolveTemplate: function(parsedName) {
4
var templateName = parsedName.fullNameWithoutType.replace(/./g, '/');
5
6
if (Ember.TEMPLATES[templateName]) {
7
return Ember.TEMPLATES[templateName];
8
}
9
10
templateName = decamelize(templateName);
11
if (Ember.TEMPLATES[templateName]) {
12
return Ember.TEMPLATES[templateName];
13
}
14
},
15
// ...
16 });

resolver.js
ember decides to generate a controller

1 Ember.Route = Ember.Object.extend(Ember.ActionHandler, {
2
3
setup: function(context, transition) {
4
var controllerName = this.controllerName || this.routeName,
5
controller = this.controllerFor(controllerName, true);
6
if (!controller) {
7
controller = this.generateController(controllerName, context);
8
}
9
10
// ...

route.js
ember decides to generate a controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

Ember.generateControllerFactory = function(container, controllerName, context) {!
var Factory, fullName, instance, name, factoryName, controllerType;!
!
if (context && Ember.isArray(context)) {!
controllerType = 'array';!
} else if (context) {!
controllerType = 'object';!
} else {!
controllerType = 'basic';!
}!
!
factoryName = 'controller:' + controllerType;!
!
Factory = container.lookupFactory(factoryName).extend({!
isGenerated: true,!
toString: function() {!
return "(generated " + controllerName + " controller)";!
}!
});!
!
fullName = 'controller:' + controllerName;!
!
container.register(fullName, Factory);!
!
return Factory;!
};!
controller_for.js
ember data injects a store
1 Ember.onLoad('Ember.Application', function(Application) {
2
3
// ... adapters, serializers, transforms, etc
4
5
Application.initializer({
6
name: "injectStore",
7
before: "store",
8
9
initialize: function(container, application) {
10
application.inject('controller', 'store', 'store:main');
11
application.inject('route', 'store', 'store:main');
12
application.inject('serializer', 'store', 'store:main');
13
application.inject('dataAdapter', 'store', 'store:main');
14
}
15
});
16
17 });
initializers.js
How to re-organzie types
Make an li tag active for sub routes (bootstrap nav)
1 App.ActiveLiComponent = Ember.Component.extend({
2
tagName: 'li',
3
classNameBindings: ['isActive:active:inactive'],
4
5
router: function(){
6
return this.container.lookup('router:main');
7
}.property(),
8
9
isActive: function(){
10
var currentWhen = this.get('currentWhen');
11
return this.get('router').isActive(currentWhen);
12
}.property('router.url', 'currentWhen')
13 });

http://emberjs.jsbin.com/iFEvATE/2/edit?html,js,output
Isolate tests with a container
1 var container, component, router;!
2 module("ActiveLiComponent tests", {!
3
setup: function(){!
4
container = new Ember.Container();!
5
container.register('component:active-li', App.ActiveLiComponent);!
6
container.register('router:main', Ember.Object.create({!
7
url: '/',!
8
isActive: function(){}!
9
}), {instantiate: false});!
10
component = container.lookup('component:active-li');!
11
router = container.lookup('router:main');!
12
},!
13
teardown: function() {!
14
Ember.run(container, 'destroy');!
15
}!
16 });!

http://emberjs.jsbin.com/aGILoru/1/edit?js,output
Create services with needs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

App.AudioPlayerController = Ember.Controller.extend({
play: function(track){
this.set('currentTrack', play);
1 {{! application.hbs }}
this.set('isPlaying', true);
2 {{render “audio_player"}}
},
3 {{outlet}}
// ...
});
App.FieldElementController = Ember.Controller.extend({
needs: ['audio_player'],
player: Ember.computed.alias('controllers.audio_player'),
actions: {
start: function(){
var player = this.get('player'),
track = this.get('model.track');
player.play(track);
}
}
});
http://to.be/fields/cG8QrM
Isolate tests with a container
1 var container, controller, player;
2 module("FieldElementController tests", {
3
setup: function(){
4
container = new Ember.Container();
5
container.register('controller:field_element', App.FieldElement);
6
container.register('controller:audio_player', Ember.Object.extend({
7
play: function(){}
8
}));
9
controller = container.lookup('controller:field_element');
10
player = container.lookup('controller:audio_player');
11
},
12
teardown: function() {
13
Ember.run(container, 'destroy');
14
}
15 });
make new types
deferred queue uploader
1 ToBe.initializer({
2
name: 'fieldElementUpdater',
3
4
initialize: function(container, application){
5
6
// Register the fieldElementUpdater to the controllers, models, views, routes.
7
container.optionsForType('fieldElementUpdater', {singleton: true});
8
container.register('fieldElementUpdater:main', ToBe.FieldElementUpdater);
9
container.injection('controller', 'fieldElementUpdater', 'fieldElementUpdater:main');
10
container.injection('model',
'fieldElementUpdater', 'fieldElementUpdater:main');
11
container.injection('route',
'fieldElementUpdater', 'fieldElementUpdater:main');
12
13
// Legacy, non-Ember code
14
application.set('fieldElementUpdater', container.lookup('fieldElementUpdater:main'));
15
16
}
17 });
http://to.be/fields/iJYzt-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

Ember.Application.initializer({
name: 'adapter',
before: 'authentication',
initialize: function(container, app){
import FirebaseAdapter from 'appkit/adapters/firebase';
container.register('adapter:firebase', FirebaseAdapter);
app.inject('controller', 'firebase', 'adapter:firebase');
app.inject('route',
'firebase', 'adapter:firebase');
}
});
Ember.Application.initializer({
name: 'authentication',
initialize: function(container, app){
import Session from 'appkit/controllers/session';
container.register('session:main', Session);
app.inject('controller', 'session', 'session:main');
app.inject('route',
'session', 'session:main');
import FirebaseAuth from 'appkit/models/firebase_auth';
container.register('session:adapter', FirebaseAuth);
app.inject('session:adapter', 'firebase', 'adapter:firebase');
app.inject('session:main',
'adapter', 'session:adapter');
}
});

https://github.com/mixonic/grimvisage

auth
1 var SessionController = Ember.Object.extend({
2
isAuthenticated: false,
3
currentUser: null,
4
afterRedirect: null,
5
6
open: function(credentials){
7
var session = this;
8
return this.get('adapter').open(credentials, this)
9
.then(function(user){
10
session.set('isAuthenticated', true);
11
session.set('currentUser', user);
12
return user;
13
}, Ember.RSVP.reject);
14
},
15
16
fetch: function(){
17
var session = this;
18
return this.get('adapter').fetch(this)
19
.then(function(user){
20
session.set('isAuthenticated', true);
21
session.set('currentUser', user);
22
return user;
23
}, Ember.RSVP.reject);
24
},
25
26
close: function(){
27
var session = this;
28
return this.get('adapter').close(this)
29
.then(function(ref){
30
session.set('isAuthenticated', false);
31
session.set('currentUser', null);
32
return ref;
33
}, Ember.RSVP.reject);
34
}
35 });
36
37 export default SessionController;

session.js

auth
Containers allow the
definition of patterns
beyond MVC.
The resolver and container
power Ember’s

module-filled-future.
Thanks!
@mixonic
httP://madhatted.com
matt.beale@madhatted.com

Mais conteúdo relacionado

Mais procurados

Europython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & CeleryEuropython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & Celery
Mauro Rocco
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Paulo Ragonha
 

Mais procurados (20)

Workshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptWorkshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScript
 
Intro to Ember.JS 2016
Intro to Ember.JS 2016Intro to Ember.JS 2016
Intro to Ember.JS 2016
 
JavaScript Promise
JavaScript PromiseJavaScript Promise
JavaScript Promise
 
An Introduction to Celery
An Introduction to CeleryAn Introduction to Celery
An Introduction to Celery
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 
Avoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promisesAvoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promises
 
Testing Javascript with Jasmine
Testing Javascript with JasmineTesting Javascript with Jasmine
Testing Javascript with Jasmine
 
The road to Ember.js 2.0
The road to Ember.js 2.0The road to Ember.js 2.0
The road to Ember.js 2.0
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testing
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.js
 
Europython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & CeleryEuropython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & Celery
 
Jasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishyJasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishy
 
Practical Celery
Practical CeleryPractical Celery
Practical Celery
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScript
 
Automated Testing in EmberJS
Automated Testing in EmberJSAutomated Testing in EmberJS
Automated Testing in EmberJS
 
Test like a pro with Ember.js
Test like a pro with Ember.jsTest like a pro with Ember.js
Test like a pro with Ember.js
 
Workshop 26: React Native - The Native Side
Workshop 26: React Native - The Native SideWorkshop 26: React Native - The Native Side
Workshop 26: React Native - The Native Side
 
Promise pattern
Promise patternPromise pattern
Promise pattern
 
Why Task Queues - ComoRichWeb
Why Task Queues - ComoRichWebWhy Task Queues - ComoRichWeb
Why Task Queues - ComoRichWeb
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 

Semelhante a Containers & Dependency in Ember.js

How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
Ben Lin
 

Semelhante a Containers & Dependency in Ember.js (20)

Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications
 
ParisJS #10 : RequireJS
ParisJS #10 : RequireJSParisJS #10 : RequireJS
ParisJS #10 : RequireJS
 
EmberJS BucharestJS
EmberJS BucharestJSEmberJS BucharestJS
EmberJS BucharestJS
 
Creating your own framework on top of Symfony2 Components
Creating your own framework on top of Symfony2 ComponentsCreating your own framework on top of Symfony2 Components
Creating your own framework on top of Symfony2 Components
 
Building Isomorphic Apps (JSConf.Asia 2014)
Building Isomorphic Apps (JSConf.Asia 2014)Building Isomorphic Apps (JSConf.Asia 2014)
Building Isomorphic Apps (JSConf.Asia 2014)
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - Introduction
 
A Story about AngularJS modularization development
A Story about AngularJS modularization developmentA Story about AngularJS modularization development
A Story about AngularJS modularization development
 
Reactive application using meteor
Reactive application using meteorReactive application using meteor
Reactive application using meteor
 
JavaScript
JavaScriptJavaScript
JavaScript
 
Building an angular application -1 ( API: Golang, Database: Postgres) v1.0
Building an angular application -1 ( API: Golang, Database: Postgres) v1.0Building an angular application -1 ( API: Golang, Database: Postgres) v1.0
Building an angular application -1 ( API: Golang, Database: Postgres) v1.0
 
React Development with the MERN Stack
React Development with the MERN StackReact Development with the MERN Stack
React Development with the MERN Stack
 
[2015/2016] JavaScript
[2015/2016] JavaScript[2015/2016] JavaScript
[2015/2016] JavaScript
 
E2E testing Single Page Apps and APIs with Cucumber.js and Puppeteer
E2E testing Single Page Apps and APIs with Cucumber.js and PuppeteerE2E testing Single Page Apps and APIs with Cucumber.js and Puppeteer
E2E testing Single Page Apps and APIs with Cucumber.js and Puppeteer
 
Testing Legacy Rails Apps
Testing Legacy Rails AppsTesting Legacy Rails Apps
Testing Legacy Rails Apps
 
Building a dashboard using AngularJS
Building a dashboard using AngularJSBuilding a dashboard using AngularJS
Building a dashboard using AngularJS
 
Micro Front-Ends
Micro Front-EndsMicro Front-Ends
Micro Front-Ends
 
From MEAN to the MERN Stack
From MEAN to the MERN StackFrom MEAN to the MERN Stack
From MEAN to the MERN Stack
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
 
End-to-end web-testing in ruby ecosystem
End-to-end web-testing in ruby ecosystemEnd-to-end web-testing in ruby ecosystem
End-to-end web-testing in ruby ecosystem
 

Mais de Matthew Beale

Scalable vector ember
Scalable vector emberScalable vector ember
Scalable vector ember
Matthew Beale
 

Mais de Matthew Beale (12)

Ember.js Module Loading
Ember.js Module LoadingEmber.js Module Loading
Ember.js Module Loading
 
LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017
 
Interoperable Component Patterns
Interoperable Component PatternsInteroperable Component Patterns
Interoperable Component Patterns
 
Ember Community 2016 - Be the Bark
Ember Community 2016 - Be the BarkEmber Community 2016 - Be the Bark
Ember Community 2016 - Be the Bark
 
Attribute actions
Attribute actionsAttribute actions
Attribute actions
 
The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)
The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)
The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)
 
Aligning Ember.js with Web Standards
Aligning Ember.js with Web StandardsAligning Ember.js with Web Standards
Aligning Ember.js with Web Standards
 
New Component Patterns in Ember.js
New Component Patterns in Ember.jsNew Component Patterns in Ember.js
New Component Patterns in Ember.js
 
Scalable vector ember
Scalable vector emberScalable vector ember
Scalable vector ember
 
Parse Apps with Ember.js
Parse Apps with Ember.jsParse Apps with Ember.js
Parse Apps with Ember.js
 
Snappy Means Happy: Performance in Ember Apps
Snappy Means Happy: Performance in Ember AppsSnappy Means Happy: Performance in Ember Apps
Snappy Means Happy: Performance in Ember Apps
 
Client-side Auth with Ember.js
Client-side Auth with Ember.jsClient-side Auth with Ember.js
Client-side Auth with Ember.js
 

Último

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Último (20)

Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 

Containers & Dependency in Ember.js

  • 3. 201 Created We build õ-age apps with Ember.js. We take teams from £ to • in no time flat.
  • 5. WHAT IS EMBER MADE OF?
  • 7. • MVC FRamework • Models • Views • Controllers
  • 8. • MVC FRamework • Models • Views • Controllers • Components • ROUTES • Router • templates
  • 9. • MVC FRamework • Models • Views • Controllers • Components • Store • Serializers • ROUTES • adapters • Router • templates
  • 11. What makes a
 router different from a template?
  • 12. What makes a
 router different from a template? • maps routes to states • only one router • instance of a class • App.Router • Has access to store (ED)
  • 13. What makes a
 router different from a template? • maps routes to states • only one router • instance of a class • App.Router • Has access to store (ED) • presents html • many templates • just functions • on Ember.templates
  • 14. What makes things similar?
  • 15. What makes things similar? • Shared Interface
  • 16. 1 App.IndexView = Ember.Object.extend({ 2 click: function(){ alert('click!'); }, 3 appendTo: function(){ /* ... */ }, 4 render: function(){ /* ... */ }, 5 rerender: function(){ /* ... */ } 6 // ... 7 });
  • 17. 1 App.IndexView = Ember.Object.extend({ 2 click: function(){ alert('click!'); }, 3 appendTo: function(){ /* ... */ }, 4 render: function(){ /* ... */ }, 5 rerender: function(){ /* ... */ } 6 // ... 7 }); 1 App.WidgetView = Ember.Object.extend({ 2 click: function(){ alert('widget!'); }, 3 appendTo: function(){ /* ... */ }, 4 render: function(){ /* ... */ }, 5 rerender: function(){ /* ... */ } 6 // ... 7 });
  • 18. 1 Ember.View = Ember.Object.extend({ 2 appendTo: function(){ /* ... */ }, 3 render: function(){ /* ... */ }, 4 rerender: function(){ /* ... */ } 5 }); 1 App.IndexView = Ember.View.extend({ 2 click: function(){ alert('click!'); } 3 }); 1 App.WidgetView = Ember.View.extend({ 2 click: function(){ alert('widget!'); } 3 });
  • 19. What makes things similar? • Shared Interface (superclass?) App.IndexView = Ember.View.extend({ // ...
  • 20. What makes things similar? • Shared Interface (superclass?)
 App.IndexView = Ember.View.extend({ // ... • SHARED DEPENDENCIES
  • 21. 1 App.IndexRoute = Ember.Route.extend({ 2 actions: { 3 didTransition: function(){ 4 Ember.run.once(this, function(){ 5 trackAnalytics(this.get('router.url')); 6 }); 7 } 8 } 9 });
  • 22. What makes things similar? • Shared Interface (superclass?)
 App.IndexView = Ember.View.extend({ // ... • SHARED DEPENDENCIES this.get('router'); // In a route
  • 23. What makes things similar? • Shared Interface (superclass?)
 App.IndexView = Ember.View.extend({ // ... • SHARED DEPENDENCIES
 this.get('router'); // In a route • SHAREd USAGE

  • 27. Is A Ember.Component.extend({ ! ! Ember.Controller.extend({ ! ! Ember.Handlebars.compile(" ! Instantiate? New every time? ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! Class ! ! Class ! ! Function ✓ ✓ ✗ ✓ ✗ ✗
  • 28. What makes things similar? • Shared Interface (superclass?)
 App.IndexView = Ember.View.extend({ // ... • SHARED DEPENDENCIES
 this.get('router'); // In a route • SHAREd USAGE
 Instantiate all the controllers, but return the same one each time
  • 29. What makes things similar? • Shared Interface (superclass?)
 App.IndexView = Ember.View.extend({ // ... • SHARED DEPENDENCIES
 this.get('router'); // In a route • SHAREd USAGE
 Instantiate all the controllers, but return the same one each time • SHARED DISCOVERY
  • 30. What makes things similar? • Shared Interface (superclass?)
 App.IndexView = Ember.View.extend({ // ... • SHARED DEPENDENCIES
 this.get('router'); // In a route • SHAREd USAGE
 Instantiate all the controllers, but return the same one each time • SHARED DISCOVERY App.ColorPickerComponent Ember.TEMPLATES['index'] App.Car
  • 31. What makes things similar? • Shared Interface (superclass?)
 App.IndexView = Ember.View.extend({ // ... • SHARED DEPENDENCIES
 this.get('router'); // In a route • SHAREd USAGE
 Instantiate all the controllers, but return the same one each time • SHARED DISCOVERY App.ColorPickerComponent Ember.TEMPLATES['index'] App.Car
  • 32. What makes things similar? • Shared Interface (superclass?)
 App.IndexView = Ember.View.extend({ // ... • SHARED DEPENDENCIES
 this.get('router'); // In a route • SHAREd USAGE
 Instantiate all the controllers, but return the same one each time • SHARED DISCOVERY App.ColorPickerComponent Ember.TEMPLATES['index'] App.Car
  • 36. The container organizes new building blocks.
  • 38. register a factory into a container 1 2 3 4 5 6 7 8 9 10 11 12 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: /* take a job and run it, add workers if needed */ }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.lookup('workerPool:main'); // -> Instance of WorkerPool container.lookup('workerPool:main'); // -> Same instance of WorkerPool
  • 39. register a factory into a container 1 2 3 4 5 6 7 8 9 10 11 12 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: /* take a job and run it, add workers if needed */ }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.lookup('workerPool:main'); // -> Instance of WorkerPool container.lookup('workerPool:main'); // -> Same instance of WorkerPool singleton (always the same instance)
  • 40. register like factories into a container 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: /* take a job and run it, add workers if needed */ }); var BigPool = WorkerPool.extend({ limit: 10 }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('workerPool:big', BigPool); container.lookup('workerPool:main'); // -> Instance of WorkerPool container.lookup('workerPool:big'); // -> Instance of BigPool
  • 41. register like factories into a container 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: /* take a job and run it, add workers if needed */ }); var BigPool = WorkerPool.extend({ limit: 10 }); var container = new Ember.Container(); container.register('workerPool:main', BigPool); container.register('workerPool:big', BigPool); container.lookup('workerPool:main'); // -> Instance of BigPool container.lookup('workerPool:big'); // -> Different instance of BigPool
  • 42. register non-singleton factories into a container 1 2 3 4 5 6 7 8 9 10 11 var Worker = Ember.Object.extend({ run: function(){ /* run a job */ } }); var container = new Ember.Container(); container.register('worker:sync', Worker, {singleton: false}); container.lookup('worker:sync'); // -> Instance of Worker container.lookup('worker:sync'); // -> New instance of Worker container.lookup('worker:sync'); // -> New instance of Worker!
  • 43. register non-class factories into a container 1 2 3 4 5 6 7 8 9 10 11 var container = new Ember.Container(); container.register('logger:alert', window.alert, {instantiate: false}); container.register('logger:console', function(msg){ window.console.log(msg); }, {instantiate: false}); container.lookup('logger:alert'); // -> alert function container.lookup('logger:console'); // -> console.log function container.lookup('logger:console')('Howdy!'); // -> "Howdy!"
  • 45. a wild dependency appears 1 2 3 4 5 6 7 8 9 10 11 12 13 14 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: function(job){ this.get('logger')('Began job.') /* take a job and run it, add workers if needed */ } }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); var pool = container.lookup('workerPool:main'); pool.submitJob(job);
  • 46. a wild dependency appears 1 2 3 4 5 6 7 8 9 10 11 12 13 14 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: function(job){ this.get('logger')('Began job.') /* take a job and run it, add workers if needed */ } }); Need a logger var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); var pool = container.lookup('workerPool:main'); pool.submitJob(job);
  • 47. Inject a dependency on a factory 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: function(job){ this.get('logger')('Began job.') /* take a job and run it, add workers if needed */ } }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('logger:alert', window.alert, {instantiate: false}); container.injection('workerPool:main', 'logger', 'logger:alert'); var pool = container.lookup('workerPool:main'); pool.submitJob(job);
  • 48. Inject a dependency on a factory 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: function(job){ this.get('logger')('Began job.') /* take a job and run it, add workers if needed */ } }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('logger:alert', window.alert, {instantiate: false}); container.injection('workerPool:main', 'logger', 'logger:alert'); var pool = container.lookup('workerPool:main'); pool.submitJob(job);
  • 49. Inject a dependency on a factory 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: function(job){ this.get('logger')('Began job.') /* take a job and run it, add workers if needed */ } }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('logger:alert', window.alert, {instantiate: false}); container.injection('workerPool:main', 'logger', 'logger:alert'); var pool = container.lookup('workerPool:main'); pool.submitJob(job); control over the dependency
  • 50. Inject a dependency on a type 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: function(job){ this.get('logger')('Began job.') /* take a job and run it, add workers if needed */ } }); var BigPool = WorkerPool.extend({ limit: 10 }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('workerPool:big', BigPool); container.register('logger:alert', window.alert, {instantiate: false}); container.injection('workerPool', 'logger', 'logger:alert'); var pool = container.lookup('workerPool:big'); pool.submitJob(job);
  • 51. Inject a dependency on a type 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: function(job){ this.get('logger')('Began job.') /* take a job and run it, add workers if needed */ } }); var BigPool = WorkerPool.extend({ limit: 10 }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('workerPool:big', BigPool); container.register('logger:alert', window.alert, {instantiate: false}); container.injection('workerPool', 'logger', 'logger:alert'); var pool = container.lookup('workerPool:big'); pool.submitJob(job);
  • 52. Inject a dependency on a type 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: function(job){ this.get('logger')('Began job.') /* take a job and run it, add workers if needed */ } }); var BigPool = WorkerPool.extend({ limit: 10 }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('workerPool:big', BigPool); container.register('logger:alert', window.alert, {instantiate: false}); container.injection('workerPool', 'logger', 'logger:alert'); var pool = container.lookup('workerPool:big'); pool.submitJob(job); control over the dependency
  • 53. a wild dependency appears 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, limit: 3, submitJob: function(job){ this.get('logger')('Began job.') /* take a job and run it, add workers if needed */ } }); Need worker var BigPool = WorkerPool.extend({ limit: 10 }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('workerPool:big', BigPool); container.register('logger:alert', window.alert, {instantiate: false}); container.injection('workerPool', 'logger', 'logger:alert'); var pool = container.lookup('workerPool:big'); pool.submitJob(job);
  • 54. Lookup a dependency 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var Worker = Ember.Object.extend({ run: function(){ /* run a job */ } }); var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, noWorkerAvailable: /* check for a free worker */, limit: 3, submitJob: function(job){ if (this.get('noWorkerAvailable')) { var worker = this.container.lookup('worker:sync'); worker.run(job); this.get('workers').pushObject(worker); } // else find a free worker in the pool and run } }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('worker:sync', Worker, {singleton: false}); var pool = container.lookup('workerPool:main'); pool.submitJob(job);
  • 55. Lookup a dependency 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var Worker = Ember.Object.extend({ run: function(){ /* run a job */ } }); var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, noWorkerAvailable: /* check for a free worker */, limit: 3, submitJob: function(job){ if (this.get('noWorkerAvailable')) { var worker = this.container.lookup('worker:sync'); worker.run(job); this.get('workers').pushObject(worker); } // else find a free worker in the pool and run } }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('worker:sync', Worker, {singleton: false}); var pool = container.lookup('workerPool:main'); pool.submitJob(job);
  • 56. Lookup a dependency 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var Worker = Ember.Object.extend({ run: function(){ /* run a job */ } }); var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, noWorkerAvailable: /* check for a free worker */, limit: 3, submitJob: function(job){ if (this.get('noWorkerAvailable')) { var worker = this.container.lookup('worker:sync'); worker.run(job); this.get('workers').pushObject(worker); } // else find a free worker in the pool and run } }); control over the dependency var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('worker:sync', Worker, {singleton: false}); var pool = container.lookup('workerPool:main'); pool.submitJob(job);
  • 57. dynamically Lookup a dependency 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var WorkerPool = Ember.Object.extend({ workers: /* an array of workers */, noWorkerAvailable: /* check for a free worker */, limit: 3, submitJob: function(job){ if (this.get('noWorkerAvailable')) { var worker = this.container.lookup( 'worker:'+(job.get('isAsync') ? 'async' : 'sync') ); worker.run(job); this.get('workers').pushObject(worker); } // else find a free worker in the pool and run } }); var container = new Ember.Container(); container.register('workerPool:main', WorkerPool); container.register('worker:sync', Worker, {singleton: false}); container.register('worker:async', AsyncWorker, {singleton: false}); var pool = container.lookup('workerPool:main'); pool.submitJob(job);
  • 58. Injection places control outside the target, lookup makes it internal.
  • 60. resolve to namespace 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function capitalize(str){ return str.charAt(0).toUpperCase() + str.slice(1); } var MyScope = {}; MyScope.SyncWorker = Ember.Object.extend({ run: function(){ /* run a job */ } }); var container = new Ember.Container(); container.resolve = function(name){ var parts = name.split(':'), className = capitalize(parts[1])+capitalize(parts[0]); return MyScope[className]; } var worker = container.lookup('worker:sync', {instantiate: false});
  • 61. resolve to AMD module 1 2 3 4 5 6 7 8 9 10 11 12 13 14 define('workers/sync', function(){ return Ember.Object.extend({ run: function(){ /* run a job */ } }); }); var container = new Ember.Container(); container.resolve = function(name){ var parts = name.split(':'), moduleName = parts[0]+'s/'+parts[1]; return require(moduleName); } var worker = container.lookup('worker:sync', {instantiate: false});
  • 63. Ember applications use a single container.
  • 64. Several ways to access it • Everything from a container has this.container
 1 App.IndexView = Ember.View.extend({ 2 router: function(){ 3 return this.container.lookup('router:main'); 4 }.property() 5 });
  • 65. Several ways to access it • Everything from a container has this.container
 router: function(){ return this.container.lookup('router:main'); }.property()! • App.register, App.Inject
 App.register('analytics:google', App.GoogleAnalytics);! App.inject('controller', 'analytics', 'analytics:google');!
  • 66. Several ways to access it • Everything from a container has this.container
 router: function(){ return this.container.lookup('router:main'); }.property()! • App.register, App.Inject
 App.register('analytics:google', App.GoogleAnalytics);! App.inject('controller', 'analytics', 'analytics:google');! • In Initializers App.initializer({ name: 'analytics', /* before: 'optionallyBeforeThis' */ initialize: function(container, application){ application.register('analytics:google', App.GoogleAnalytics); container.injection('controller', 'analytics', 'analytics:google'); } })
  • 67. Several ways to access it • Everything from a container has this.container
 router: function(){ return this.container.lookup('router:main'); }.property()! • App.register, App.Inject
 App.register('analytics:google', App.GoogleAnalytics);! App.inject('controller', 'analytics', 'analytics:google');! • In Initializers
 App.initializer({ initialize: function(container, application){ // ... • needs App.AnalyticsController = Ember.Controller.extend(); App.IndexController = Ember.Controller.extend({ needs: ['analytics'], analytics: Ember.computed.alias('controllers.analytics') }); !
  • 68. Several ways to access it • Everything from a container has this.container
 router: function(){ return this.container.lookup('router:main'); }.property()! • App.register, App.Inject
 App.register('analytics:google', App.GoogleAnalytics);! App.inject('controller', 'analytics', 'analytics:google');! • In Initializers
 App.initializer({ initialize: function(container, application){ // ... • needs App.AnalyticsController = Ember.Controller.extend(); App.IndexController = Ember.Controller.extend({ needs: ['analytics'], analytics: Ember.computed.alias('controllers.analytics') }); !
  • 69. …and one unsafe way. // Never, ever use this in application code App.__container__
  • 71. ember Finds a template 1 Ember.View = Ember.CoreView.extend({ 2 3 templateForName: function(name, type) { 4 if (!name) { return; } 5 Ember.assert("templateNames are not allowed to contain periods: "+name, name.indexOf('.') == 6 7 // the defaultContainer is deprecated 8 var container = this.container || (Ember.Container && Ember.Container.defaultContainer); 9 return container && container.lookup('template:' + name); 10 }, 11 // ... 12 }); view.js
  • 72. ember Finds a template 1 Ember.DefaultResolver = Ember.Object.extend({ 2 3 resolveTemplate: function(parsedName) { 4 var templateName = parsedName.fullNameWithoutType.replace(/./g, '/'); 5 6 if (Ember.TEMPLATES[templateName]) { 7 return Ember.TEMPLATES[templateName]; 8 } 9 10 templateName = decamelize(templateName); 11 if (Ember.TEMPLATES[templateName]) { 12 return Ember.TEMPLATES[templateName]; 13 } 14 }, 15 // ... 16 }); resolver.js
  • 73. ember decides to generate a controller 1 Ember.Route = Ember.Object.extend(Ember.ActionHandler, { 2 3 setup: function(context, transition) { 4 var controllerName = this.controllerName || this.routeName, 5 controller = this.controllerFor(controllerName, true); 6 if (!controller) { 7 controller = this.generateController(controllerName, context); 8 } 9 10 // ... route.js
  • 74. ember decides to generate a controller 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Ember.generateControllerFactory = function(container, controllerName, context) {! var Factory, fullName, instance, name, factoryName, controllerType;! ! if (context && Ember.isArray(context)) {! controllerType = 'array';! } else if (context) {! controllerType = 'object';! } else {! controllerType = 'basic';! }! ! factoryName = 'controller:' + controllerType;! ! Factory = container.lookupFactory(factoryName).extend({! isGenerated: true,! toString: function() {! return "(generated " + controllerName + " controller)";! }! });! ! fullName = 'controller:' + controllerName;! ! container.register(fullName, Factory);! ! return Factory;! };! controller_for.js
  • 75. ember data injects a store 1 Ember.onLoad('Ember.Application', function(Application) { 2 3 // ... adapters, serializers, transforms, etc 4 5 Application.initializer({ 6 name: "injectStore", 7 before: "store", 8 9 initialize: function(container, application) { 10 application.inject('controller', 'store', 'store:main'); 11 application.inject('route', 'store', 'store:main'); 12 application.inject('serializer', 'store', 'store:main'); 13 application.inject('dataAdapter', 'store', 'store:main'); 14 } 15 }); 16 17 }); initializers.js
  • 77. Make an li tag active for sub routes (bootstrap nav) 1 App.ActiveLiComponent = Ember.Component.extend({ 2 tagName: 'li', 3 classNameBindings: ['isActive:active:inactive'], 4 5 router: function(){ 6 return this.container.lookup('router:main'); 7 }.property(), 8 9 isActive: function(){ 10 var currentWhen = this.get('currentWhen'); 11 return this.get('router').isActive(currentWhen); 12 }.property('router.url', 'currentWhen') 13 }); http://emberjs.jsbin.com/iFEvATE/2/edit?html,js,output
  • 78. Isolate tests with a container 1 var container, component, router;! 2 module("ActiveLiComponent tests", {! 3 setup: function(){! 4 container = new Ember.Container();! 5 container.register('component:active-li', App.ActiveLiComponent);! 6 container.register('router:main', Ember.Object.create({! 7 url: '/',! 8 isActive: function(){}! 9 }), {instantiate: false});! 10 component = container.lookup('component:active-li');! 11 router = container.lookup('router:main');! 12 },! 13 teardown: function() {! 14 Ember.run(container, 'destroy');! 15 }! 16 });! http://emberjs.jsbin.com/aGILoru/1/edit?js,output
  • 79. Create services with needs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 App.AudioPlayerController = Ember.Controller.extend({ play: function(track){ this.set('currentTrack', play); 1 {{! application.hbs }} this.set('isPlaying', true); 2 {{render “audio_player"}} }, 3 {{outlet}} // ... }); App.FieldElementController = Ember.Controller.extend({ needs: ['audio_player'], player: Ember.computed.alias('controllers.audio_player'), actions: { start: function(){ var player = this.get('player'), track = this.get('model.track'); player.play(track); } } }); http://to.be/fields/cG8QrM
  • 80. Isolate tests with a container 1 var container, controller, player; 2 module("FieldElementController tests", { 3 setup: function(){ 4 container = new Ember.Container(); 5 container.register('controller:field_element', App.FieldElement); 6 container.register('controller:audio_player', Ember.Object.extend({ 7 play: function(){} 8 })); 9 controller = container.lookup('controller:field_element'); 10 player = container.lookup('controller:audio_player'); 11 }, 12 teardown: function() { 13 Ember.run(container, 'destroy'); 14 } 15 });
  • 82. deferred queue uploader 1 ToBe.initializer({ 2 name: 'fieldElementUpdater', 3 4 initialize: function(container, application){ 5 6 // Register the fieldElementUpdater to the controllers, models, views, routes. 7 container.optionsForType('fieldElementUpdater', {singleton: true}); 8 container.register('fieldElementUpdater:main', ToBe.FieldElementUpdater); 9 container.injection('controller', 'fieldElementUpdater', 'fieldElementUpdater:main'); 10 container.injection('model', 'fieldElementUpdater', 'fieldElementUpdater:main'); 11 container.injection('route', 'fieldElementUpdater', 'fieldElementUpdater:main'); 12 13 // Legacy, non-Ember code 14 application.set('fieldElementUpdater', container.lookup('fieldElementUpdater:main')); 15 16 } 17 }); http://to.be/fields/iJYzt-
  • 83. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Ember.Application.initializer({ name: 'adapter', before: 'authentication', initialize: function(container, app){ import FirebaseAdapter from 'appkit/adapters/firebase'; container.register('adapter:firebase', FirebaseAdapter); app.inject('controller', 'firebase', 'adapter:firebase'); app.inject('route', 'firebase', 'adapter:firebase'); } }); Ember.Application.initializer({ name: 'authentication', initialize: function(container, app){ import Session from 'appkit/controllers/session'; container.register('session:main', Session); app.inject('controller', 'session', 'session:main'); app.inject('route', 'session', 'session:main'); import FirebaseAuth from 'appkit/models/firebase_auth'; container.register('session:adapter', FirebaseAuth); app.inject('session:adapter', 'firebase', 'adapter:firebase'); app.inject('session:main', 'adapter', 'session:adapter'); } }); https://github.com/mixonic/grimvisage auth
  • 84. 1 var SessionController = Ember.Object.extend({ 2 isAuthenticated: false, 3 currentUser: null, 4 afterRedirect: null, 5 6 open: function(credentials){ 7 var session = this; 8 return this.get('adapter').open(credentials, this) 9 .then(function(user){ 10 session.set('isAuthenticated', true); 11 session.set('currentUser', user); 12 return user; 13 }, Ember.RSVP.reject); 14 }, 15 16 fetch: function(){ 17 var session = this; 18 return this.get('adapter').fetch(this) 19 .then(function(user){ 20 session.set('isAuthenticated', true); 21 session.set('currentUser', user); 22 return user; 23 }, Ember.RSVP.reject); 24 }, 25 26 close: function(){ 27 var session = this; 28 return this.get('adapter').close(this) 29 .then(function(ref){ 30 session.set('isAuthenticated', false); 31 session.set('currentUser', null); 32 return ref; 33 }, Ember.RSVP.reject); 34 } 35 }); 36 37 export default SessionController; session.js auth
  • 85. Containers allow the definition of patterns beyond MVC.
  • 86. The resolver and container power Ember’s
 module-filled-future.