SlideShare una empresa de Scribd logo
1 de 87
Descargar para leer sin conexión
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

Más contenido relacionado

La actualidad más candente

Workshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptWorkshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptVisual Engineering
 
An Introduction to Celery
An Introduction to CeleryAn Introduction to Celery
An Introduction to CeleryIdan Gazit
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingVisual Engineering
 
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 promisesAnkit Agarwal
 
Testing Javascript with Jasmine
Testing Javascript with JasmineTesting Javascript with Jasmine
Testing Javascript with JasmineTim Tyrrell
 
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.0Codemotion
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testingVisual Engineering
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jscacois
 
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 & CeleryMauro Rocco
 
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 fishyIgor Napierala
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptjnewmanux
 
Automated Testing in EmberJS
Automated Testing in EmberJSAutomated Testing in EmberJS
Automated Testing in EmberJSBen Limmer
 
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.jsMike North
 
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 SideVisual Engineering
 
Why Task Queues - ComoRichWeb
Why Task Queues - ComoRichWebWhy Task Queues - ComoRichWeb
Why Task Queues - ComoRichWebBryan Helmig
 
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 JasminePaulo Ragonha
 

La actualidad más candente (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
 

Similar a Containers & Dependency in Ember.js

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 Juliana Lucena
 
EmberJS BucharestJS
EmberJS BucharestJSEmberJS BucharestJS
EmberJS BucharestJSRemus Rusanu
 
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 ComponentsDeepak Chandani
 
Building Isomorphic Apps (JSConf.Asia 2014)
Building Isomorphic Apps (JSConf.Asia 2014)Building Isomorphic Apps (JSConf.Asia 2014)
Building Isomorphic Apps (JSConf.Asia 2014)Spike Brehm
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - IntroductionVagmi Mudumbai
 
A Story about AngularJS modularization development
A Story about AngularJS modularization developmentA Story about AngularJS modularization development
A Story about AngularJS modularization developmentJohannes Weber
 
Reactive application using meteor
Reactive application using meteorReactive application using meteor
Reactive application using meteorSapna Upreti
 
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.0Frost
 
React Development with the MERN Stack
React Development with the MERN StackReact Development with the MERN Stack
React Development with the MERN StackTroy Miles
 
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 PuppeteerPaul Jensen
 
Testing Legacy Rails Apps
Testing Legacy Rails AppsTesting Legacy Rails Apps
Testing Legacy Rails AppsRabble .
 
Building a dashboard using AngularJS
Building a dashboard using AngularJSBuilding a dashboard using AngularJS
Building a dashboard using AngularJSRajthilakMCA
 
Micro Front-Ends
Micro Front-EndsMicro Front-Ends
Micro Front-EndsOri Calvo
 
From MEAN to the MERN Stack
From MEAN to the MERN StackFrom MEAN to the MERN Stack
From MEAN to the MERN StackTroy Miles
 
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 frameworkBen Lin
 
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'sAntônio Roberto Silva
 
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 ecosystemAlex Mikitenko
 

Similar 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
 

Más de Matthew Beale

Ember.js Module Loading
Ember.js Module LoadingEmber.js Module Loading
Ember.js Module LoadingMatthew Beale
 
LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017Matthew Beale
 
Interoperable Component Patterns
Interoperable Component PatternsInteroperable Component Patterns
Interoperable Component PatternsMatthew Beale
 
Ember Community 2016 - Be the Bark
Ember Community 2016 - Be the BarkEmber Community 2016 - Be the Bark
Ember Community 2016 - Be the BarkMatthew Beale
 
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)Matthew Beale
 
Aligning Ember.js with Web Standards
Aligning Ember.js with Web StandardsAligning Ember.js with Web Standards
Aligning Ember.js with Web StandardsMatthew Beale
 
New Component Patterns in Ember.js
New Component Patterns in Ember.jsNew Component Patterns in Ember.js
New Component Patterns in Ember.jsMatthew Beale
 
Scalable vector ember
Scalable vector emberScalable vector ember
Scalable vector emberMatthew Beale
 
Parse Apps with Ember.js
Parse Apps with Ember.jsParse Apps with Ember.js
Parse Apps with Ember.jsMatthew Beale
 
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 AppsMatthew Beale
 
Client-side Auth with Ember.js
Client-side Auth with Ember.jsClient-side Auth with Ember.js
Client-side Auth with Ember.jsMatthew Beale
 

Más 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

Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontologyjohnbeverley2021
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Zilliz
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
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...apidays
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Orbitshub
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
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 DiscoveryTrustArc
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
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)Zilliz
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...apidays
 
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 Takeoffsammart93
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamUiPathCommunity
 
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 DevelopersWSO2
 
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 FresherRemote DBA Services
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 

Último (20)

Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
+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...
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
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...
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
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
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
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 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
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
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
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
 
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
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 

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.