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]


Top Related