SlideShare a Scribd company logo
1 of 87
Download to read 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

More Related Content

What's hot

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
 

What's hot (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 to 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 to 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
 

More from 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
 

More from 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
 

Recently uploaded

Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...panagenda
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 

Recently uploaded (20)

Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 

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.