Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamp the audio demo #2

Merged
merged 2 commits into from
Mar 31, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,7 @@ App.AnotherController = Ember.Controller.extend({
});
```

For more information about aliased property, see the API docs for
For more information about dependecy injection and `needs` in Ember.js,
see the [dependency injection guide](/guides/understanding-ember/dependency-injection).
For more information about aliases, see the API docs for
[aliased properties](http://emberjs.com/api/#method_computed_alias).
116 changes: 46 additions & 70 deletions source/guides/understanding-ember/dependency-injection.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
Dependency Injection is a big part of what Ember provides as a framework. For
example, all routes can access the router of an application. When using Ember-Data
there is a `store` property made available on all controllers and routes. Ember
uses dependency injection and lookup to allow the layers of its MVC architecture
to communicate. At the same time, the dependency injection tools provided by Ember
make it easy to create custom dependency rules.
Ember.js provides a complete dependency injection and service lookup toolset via
containers. Internally, Ember applications use a container to organize basic
framework components. For example, all route objects have the property `router`
set on them upon instantiation. When using Ember-Data, there is a `store` property
made available on all controller and route objects. Ember uses dependency injection
and service lookup to allow the layers of its MVC architecture to communicate.

Though direct use of the container API is discouaged, Ember provides you with several
other ways to use dependency injection in your application.

#### How does dependency injection work?

Expand All @@ -16,9 +19,9 @@ factory, it uses a resolver to discover that factory (in a variable like
dependencies to the requested factory, the factory is cached and returned.

To accomplish most of your goals, using the container directly should not be necessary.
Instead Ember provides a set of high-level APIs on top of the container itself.
Instead Ember provides a set of high-level APIs on top of the container.

There are two APIs we will consider here:
There two APIs suggested for application use:

* `needs`, a way to inject controllers onto other controllers
* `App.register/inject`, an API for arbitrary factory registration and dependency
Expand Down Expand Up @@ -50,87 +53,60 @@ be disregarded for this explanation), so if an instance is already available it
returned. If not the controller is resolved, instantiated, and cached before being
returned from the container. This instance is then added to the `controllers` object.

##### In Practice: A Service for Audio Playback

Here, we will create an audioservice that is defined once but can be used by many
other controllers to play audio. A controller object can be defined as -
##### Exmample Use of Needs: An Audio Playback Service

```javascript
App.AudioController = Ember.Controller.extend({
play:function(trackSrc){
this.set('trackSrc', trackSrc);
this.set('playnow', true);
},
trackSrc:"defaultTrack.mp3"
});
```
To demonstrate how `needs` can create light-weight services, let's build a controller
that manages audio playback an make it available to another controller.

This object can be injected into any other controller as below -
HTML5 audio tags provide an easy way to play audio on the web. In the application
template, we will use `{{render` to render a template containing the audio tag.
`{{render` backs its template with a controller of the same name.

```javascript
App.IndexController = Ember.Controller.extend({
needs:['audio'],
first:'Sound1.mp3',
second:"Sound2.mp3",
actions:{
play:function(songUrl){
this.get('controllers.audio').play(songUrl);
}
}
});
```hbs
{{! application.hbs }}
{{render "audio"}}
{{outlet}}
```

When the index controller is created by Ember, it notes that there is a `needs`
dependency and looksup/creates an instance of AudioController. This object is made
available in a list called `controllers`

`needs:['audio']` leads to the audio controller being available in
`this.get('controllers.audio')`

A view and template are defined to create the audio html tag.

```hbs
<audio id='audio' controls loop>
<source {{bind-attr src=trackSrc}} type='audio/mpeg'></source>
{{! audio.hbs }}
<audio id="audio" controls loop>
<source {{bind-attr src=currentSrc}} type="audio/mpeg"></source>
</audio>
<div> Now Playing - {{trackSrc}} </div>
<div>{{currentSrc}}</div>
```

The `trackSrc` is a binding to the controller variable. The view picks up the
element in the dom and plays the audio.
Th controller itself will maintain `currentSrc` property:

```javascript
App.AudioView = Ember.View.extend({
templateName:'audio',
playAudio:function(){
if(this.get('controller.playnow')){
Ember.run.schedule('afterRender', function(){
//Play the audio after the src in audio tag has been updated.
});
this.set('controller.playnow', false);
}
}.observes('controller.playnow')
App.AudioController = Ember.Controller.extend({
currentSrc: null,
play: function(src){
this.set('currentSrc', src);
}
});
```

A template is created for users to play songs.

```hbs
<div class='link' {{action 'play' first}}>First Song</div>
<div class='link' {{action 'play' second}}>Second Song</div>
```

Only one instance of this audio service can be defined in the application template
using
This `AudioController` can be referenced by other controllers via
`needs`:

```javascript
{{render 'audio'}}
App.IndexController = Ember.Controller.extend({
needs: ['audio'],
actions: {
selectSrc: function(src){
this.get('controllers.audio').play(src);
}
}
});
```

This now enables us to play audio from any other controller by `needs:['audio']`
and `this.get('controllers.audio').play(trackUrl);`
In this same manner, any other controller could access the `audio` controller
instance.

A functional version of this demo is provided below:

<a class="jsbin-embed" href="http://emberjs.jsbin.com/mayul/4/embed?html,js,output">Ember Starter Kit</a><script src="http://static.jsbin.com/js/embed.js"></script>
<a class="jsbin-embed" href="http://emberjs.jsbin.com/depar/1/embed?js,output">Ember Starter Kit</a><script src="http://static.jsbin.com/js/embed.js"></script>

##### Defining New Framework Components

Expand Down