containers & dependency in ember.js

87
Hi. I’m Matthew.

Upload: mixonic

Post on 08-Sep-2014

50 views

Category:

Technology


7 download

DESCRIPTION

Ember applications are built around an MVC model that prescribes Models, Views, Controllers, and Routes for managing persistence, DOM, application state, and URLs. In an ambitious enough app, that model may fail to cover the whole problem space. Fear not, for in this presentation you will learn how to use Ember’s container and dependency features to move beyond MVC, as well as learning how they tie Ember internals together. Video: http://www.youtube.com/watch?v=iCZUKFNXA0k&feature=youtu.be&t=1h45m59s

TRANSCRIPT

Page 1: Containers & Dependency in Ember.js

Hi. I’m Matthew.

Page 3: Containers & Dependency in Ember.js

201 Created

We build õ-age apps with Ember.js. We take teams from £ to • in no time flat.

Page 4: Containers & Dependency in Ember.js

http://bit.ly/ember-nyc-edge

Page 5: Containers & Dependency in Ember.js

WHAT IS EMBER MADE OF?

Page 6: Containers & Dependency in Ember.js

• MVC FRamework

Page 7: Containers & Dependency in Ember.js

• Models • Views • Controllers

• MVC FRamework

Page 8: Containers & Dependency in Ember.js

• MVC FRamework

• Models • Views • Controllers

• Components • ROUTES • Router • templates

Page 9: Containers & Dependency in Ember.js

• Components • ROUTES • Router • templates

• MVC FRamework

• Models • Views • Controllers

• Store • Serializers • adapters

Page 10: Containers & Dependency in Ember.js

SO MANY THINGS

Page 11: Containers & Dependency in Ember.js

What makes arouter different from a template?

Page 12: Containers & Dependency in Ember.js

What makes arouter different from a template?

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

Page 13: Containers & Dependency in Ember.js

What makes arouter 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

Page 14: Containers & Dependency in Ember.js

What makes things similar?

Page 15: Containers & Dependency in Ember.js

What makes things similar?

• Shared Interface

Page 16: Containers & Dependency in Ember.js

1 App.IndexView = Ember.Object.extend({ 2 click: function(){ alert('click!'); }, 3 appendTo: function(){ /* ... */ }, 4 render: function(){ /* ... */ }, 5 rerender: function(){ /* ... */ } 6 // ... 7 });

Page 17: Containers & Dependency in Ember.js

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 });

Page 18: Containers & Dependency in Ember.js

1 App.IndexView = Ember.View.extend({ 2 click: function(){ alert('click!'); } 3 });

1 App.WidgetView = Ember.View.extend({ 2 click: function(){ alert('widget!'); } 3 });

1 Ember.View = Ember.Object.extend({ 2 appendTo: function(){ /* ... */ }, 3 render: function(){ /* ... */ }, 4 rerender: function(){ /* ... */ } 5 });

Page 19: Containers & Dependency in Ember.js

What makes things similar?

• Shared Interface (superclass?)App.IndexView = Ember.View.extend({ // ...

Page 20: Containers & Dependency in Ember.js

What makes things similar?

• Shared Interface (superclass?)

• SHARED DEPENDENCIES

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

Page 21: Containers & Dependency in Ember.js

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 });

Page 22: Containers & Dependency in Ember.js

What makes things similar?

• Shared Interface (superclass?)

• SHARED DEPENDENCIESthis.get('router'); // In a route

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

Page 23: Containers & Dependency in Ember.js

What makes things similar?

• Shared Interface (superclass?)

• SHARED DEPENDENCIES

• SHAREd USAGEthis.get('router'); // In a route

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

Page 24: Containers & Dependency in Ember.js

Ember.Component.extend({ !!Ember.Controller.extend({ !!Ember.Handlebars.compile(" !

Page 25: Containers & Dependency in Ember.js

Ember.Component.extend({ !!Ember.Controller.extend({ !!Ember.Handlebars.compile(" !

Is A !!Class !!Class !!Function

Page 26: Containers & Dependency in Ember.js

Ember.Component.extend({ !!Ember.Controller.extend({ !!Ember.Handlebars.compile(" !

Is A !!Class !!Class !!Function

Instantiate? !!!!!!!!!

✓✓✗

Page 27: Containers & Dependency in Ember.js

Ember.Component.extend({ !!Ember.Controller.extend({ !!Ember.Handlebars.compile(" !

Is A !!Class !!Class !!Function

Instantiate? !!!!!!!!!

New every time? !!!!!!!!!

✓✓✗ ✗

Page 28: Containers & Dependency in Ember.js

What makes things similar?

• Shared Interface (superclass?)

• SHARED DEPENDENCIES

• SHAREd USAGEthis.get('router'); // In a route

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

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

Page 29: Containers & Dependency in Ember.js

What makes things similar?

• Shared Interface (superclass?)

• SHARED DEPENDENCIES

• SHAREd USAGE

• SHARED DISCOVERY

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

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

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

Page 30: Containers & Dependency in Ember.js

What makes things similar?

• Shared Interface (superclass?)

• SHARED DEPENDENCIES

• SHAREd USAGE

• SHARED DISCOVERY

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

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

App.ColorPickerComponent Ember.TEMPLATES['index'] App.Car

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

Page 31: Containers & Dependency in Ember.js

What makes things similar?

• Shared Interface (superclass?)

• SHARED DEPENDENCIES

• SHAREd USAGE

• SHARED DISCOVERY

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

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

App.ColorPickerComponent Ember.TEMPLATES['index'] App.Car

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

Page 32: Containers & Dependency in Ember.js

What makes things similar?

• Shared Interface (superclass?)

• SHARED DEPENDENCIES

• SHAREd USAGE

• SHARED DISCOVERY

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

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

App.ColorPickerComponent Ember.TEMPLATES['index'] App.Car

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

Page 33: Containers & Dependency in Ember.js

CONTAINERS

Page 34: Containers & Dependency in Ember.js

The container organizes Ember’s building blocks.

Page 35: Containers & Dependency in Ember.js

The container re-organizes Ember’s building blocks.

Page 36: Containers & Dependency in Ember.js

The container organizes new building blocks.

Page 37: Containers & Dependency in Ember.js

register/lookup

Page 38: Containers & Dependency in Ember.js

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

register a factory into a container

Page 39: Containers & Dependency in Ember.js

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

register a factory into a container

singleton (always the same instance)

Page 40: Containers & Dependency in Ember.js

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

register like factories into a container

Page 41: Containers & Dependency in Ember.js

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

register like factories into a container

Page 42: Containers & Dependency in Ember.js

register non-singleton factories into a container

1 var Worker = Ember.Object.extend({ 2 run: function(){ /* run a job */ } 3 }); 4 5 var container = new Ember.Container(); 6 7 container.register('worker:sync', Worker, {singleton: false}); 8 9 container.lookup('worker:sync'); // -> Instance of Worker 10 container.lookup('worker:sync'); // -> New instance of Worker 11 container.lookup('worker:sync'); // -> New instance of Worker!

Page 43: Containers & Dependency in Ember.js

register non-class factories into a container

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

Page 44: Containers & Dependency in Ember.js

injection + dependency lookup

Page 45: Containers & Dependency in Ember.js

a wild dependency appears

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

Page 46: Containers & Dependency in Ember.js

a wild dependency appears

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

Need a logger

Page 47: Containers & Dependency in Ember.js

Inject a dependency on a factory

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

Page 48: Containers & Dependency in Ember.js

Inject a dependency on a factory

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

Page 49: Containers & Dependency in Ember.js

Inject a dependency on a factory

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

control over the dependency

Page 50: Containers & Dependency in Ember.js

Inject a dependency on a type

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

Page 51: Containers & Dependency in Ember.js

Inject a dependency on a type

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

Page 52: Containers & Dependency in Ember.js

Inject a dependency on a type

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

control over the dependency

Page 53: Containers & Dependency in Ember.js

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

Need worker

a wild dependency appears

Page 54: Containers & Dependency in Ember.js

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

Page 55: Containers & Dependency in Ember.js

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

Page 56: Containers & Dependency in Ember.js

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

control over the dependency

Page 57: Containers & Dependency in Ember.js

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

Page 58: Containers & Dependency in Ember.js

Injection places control outside the target, lookup

makes it internal.

Page 59: Containers & Dependency in Ember.js

resolving factories

Page 60: Containers & Dependency in Ember.js

resolve to namespace

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

Page 61: Containers & Dependency in Ember.js

resolve to AMD module

1 define('workers/sync', function(){ 2 return Ember.Object.extend({ 3 run: function(){ /* run a job */ } 4 }); 5 }); 6 7 var container = new Ember.Container(); 8 container.resolve = function(name){ 9 var parts = name.split(':'), 10 moduleName = parts[0]+'s/'+parts[1]; 11 return require(moduleName); 12 } 13 14 var worker = container.lookup('worker:sync', {instantiate: false});

Page 62: Containers & Dependency in Ember.js

THE application CONTAINER

Page 63: Containers & Dependency in Ember.js

Ember applications use a single container.

Page 64: Containers & Dependency in Ember.js

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 });

Page 65: Containers & Dependency in Ember.js

Several ways to access it

• Everything from a container has this.container

• App.register, App.Injectrouter: function(){ return this.container.lookup('router:main'); }.property()!

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

Page 66: Containers & Dependency in Ember.js

Several ways to access it

• Everything from a container has this.container

• App.register, App.Inject

• In Initializers

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

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

App.initializer({ name: 'analytics', /* before: 'optionallyBeforeThis' */ initialize: function(container, application){ application.register('analytics:google', App.GoogleAnalytics); container.injection('controller', 'analytics', 'analytics:google'); } })

Page 67: Containers & Dependency in Ember.js

Several ways to access it

• Everything from a container has this.container

• App.register, App.Inject

• In Initializers

• needs

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

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

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

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

Page 68: Containers & Dependency in Ember.js

Several ways to access it

• Everything from a container has this.container

• App.register, App.Inject

• In Initializers

• needs

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

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

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

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

Page 69: Containers & Dependency in Ember.js

…and one unsafe way.

// Never, ever use this in application code App.__container__

Page 70: Containers & Dependency in Ember.js

how the container powers ember

Page 71: Containers & Dependency in Ember.js

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('.') === -1); 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

Page 72: Containers & Dependency in Ember.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

Page 73: Containers & Dependency in Ember.js

ember decides to generate a controller

route.js

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 // ...

Page 74: Containers & Dependency in Ember.js

1 Ember.generateControllerFactory = function(container, controllerName, context) {! 2 var Factory, fullName, instance, name, factoryName, controllerType;! 3 ! 4 if (context && Ember.isArray(context)) {! 5 controllerType = 'array';! 6 } else if (context) {! 7 controllerType = 'object';! 8 } else {! 9 controllerType = 'basic';!10 }!11 !12 factoryName = 'controller:' + controllerType;!13 !14 Factory = container.lookupFactory(factoryName).extend({!15 isGenerated: true,!16 toString: function() {!17 return "(generated " + controllerName + " controller)";!18 }!19 });!20 !21 fullName = 'controller:' + controllerName;!22 !23 container.register(fullName, Factory);!24 !25 return Factory;!26 };!

ember decides to generate a controller

controller_for.js

Page 75: Containers & Dependency in Ember.js

ember data injects a store

initializers.js

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 });

Page 76: Containers & Dependency in Ember.js

How to re-organzie types

Page 77: Containers & Dependency in Ember.js

Make an li tag active for sub routes (bootstrap nav)

http://emberjs.jsbin.com/iFEvATE/2/edit?html,js,output

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 });

Page 78: Containers & Dependency in Ember.js

Isolate tests with a container

http://emberjs.jsbin.com/aGILoru/1/edit?js,output

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 });!

Page 79: Containers & Dependency in Ember.js

1 App.AudioPlayerController = Ember.Controller.extend({ 2 play: function(track){ 3 this.set('currentTrack', play); 4 this.set('isPlaying', true); 5 }, 6 // ... 7 }); 8 9 App.FieldElementController = Ember.Controller.extend({ 10 needs: ['audio_player'], 11 player: Ember.computed.alias('controllers.audio_player'), 12 actions: { 13 start: function(){ 14 var player = this.get('player'), 15 track = this.get('model.track'); 16 player.play(track); 17 } 18 } 19 });

Create services with needs

1 {{! application.hbs }} 2 {{render “audio_player"}} 3 {{outlet}}

http://to.be/fields/cG8QrM

Page 80: Containers & Dependency in Ember.js

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 });

Page 81: Containers & Dependency in Ember.js

make new types

Page 82: Containers & Dependency in Ember.js

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 });

deferred queue uploader

http://to.be/fields/iJYzt-

Page 83: Containers & Dependency in Ember.js

1 Ember.Application.initializer({ 2 name: 'adapter', 3 before: 'authentication', 4 initialize: function(container, app){ 5 6 import FirebaseAdapter from 'appkit/adapters/firebase'; 7 container.register('adapter:firebase', FirebaseAdapter); 8 app.inject('controller', 'firebase', 'adapter:firebase'); 9 app.inject('route', 'firebase', 'adapter:firebase'); 10 } 11 }); 12 Ember.Application.initializer({ 13 name: 'authentication', 14 initialize: function(container, app){ 15 16 import Session from 'appkit/controllers/session'; 17 container.register('session:main', Session); 18 app.inject('controller', 'session', 'session:main'); 19 app.inject('route', 'session', 'session:main'); 20 21 import FirebaseAuth from 'appkit/models/firebase_auth'; 22 container.register('session:adapter', FirebaseAuth); 23 app.inject('session:adapter', 'firebase', 'adapter:firebase'); 24 app.inject('session:main', 'adapter', 'session:adapter'); 25 } 26 });

auth

https://github.com/mixonic/grimvisage

Page 84: Containers & Dependency in Ember.js

auth

session.js

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;

Page 85: Containers & Dependency in Ember.js

Containers allow the definition of patterns

beyond MVC.

Page 86: Containers & Dependency in Ember.js

The resolver and container power Ember’s

module-filled-future.

Page 87: Containers & Dependency in Ember.js

Thanks!

@mixonic

httP://madhatted.com

[email protected]