In Ember.js, a service is a singleton object that holds state. In other words, it can be shared throughout an Ember application and doesn't change. For example, session data, APIs that talk to a server, and WebSockets are good candidates for services.
In this recipe, we'll create and inject a service into a component.
Dependency injection
Services and dependency injection go hand in hand. Dependency Injection (DI) occurs when we take objects and inject them into other objects during instantiation. This means that we take a service and inject it into our routes, controllers, and components. This is an important framework concept and should not be overused. Having too many injected services would break the separation of concerns design principle.
$ ember g service start $ ember g component comp-info $ ember g initializer init
These files will be used to create our application. The service will hold a property and method that returns data.
start.js
service:// app/services/start.js import Ember from 'ember'; export default Ember.Service.extend({ isOn: false, importantInfo(){ return "Important Info is " + this.get('isOn'); } });
This is the services
file. It has an isOn
property and a method called importantInfo
that returns a string. In this example, we want access to this information in our component, comp-info
, so that it can be displayed.
comp-info.js
file and add a new action that uses the start
services information:// app/components/comp-info.js import Ember from 'ember'; export default Ember.Component.extend({ start: Ember.inject.service(), message: null, actions: { pressMe() { this.start.toggleProperty('isOn'); this.set('message',this.start.importantInfo()); console.log(this.start.isOn); } } });
The most important thing in the component is the start
property. We can inject the start
service into the component using Ember.inject.service()
. By convention, the name of the property must match the name of the service being injected. In our example, the start
service will be injected.
The pressMe
action toggles the isOn
property of the start
service. We then set
the text returned from the importantInfo
method in the message
property so that it can be displayed in the template.
button
to the template information for the component:// app/templates/components/comp-info.hbs <button {{action "pressMe"}}>push me</button><br> {{message}}
In the component, all we are doing is adding an action to the button and displaying a message.
comp-info
component to the application template file:<h2 id="title">Welcome to Ember</h2> {{outlet}} {{comp-info}}
Now the template will display the component that was just created.
Pressing the button will toggle the isOn
property. As you can see from this example, the service information was accessed by the component and displayed to the template.
initializer
that injects the service into all the components:// app/initializer/init export function initialize(app) { app.inject('component', 'start', 'service:start'); } export default { name: 'init', initialize };
Ember.js initializers are created when the application is started. It's a good place to preload data or set up the application state. The app
argument, in the initialize
function, is also known as Ember.Application
. It serves as a registry for dependency declaration. Factories (classes) can be registered and injected into the application. The service:start
is the key for the start
service that we created earlier. Once a factory is registered, it can be injected anywhere in the application. As the start
service has already been created, there is no need to register it.
The app.inject
takes three arguments. The first is the type to be injected. The second is the name
of the service, start
. Finally, the service:start
factory is created.
start
service as it's already available via the dependency injection:// app/components/comp-info.js … export default Ember.Component.extend({ //start: Ember.inject.service(), message: null, …
The start
service is commented out so it's no longer available. The rest of the component remains the same as the service can still be retrieved using this.get('start')
. This is due to the fact that we injected it into all the components in the initializer.
Services are long-lived Ember objects that can be used in different parts of your application. They are good to use with sessions, WebSockets, geolocation, logging, and more. They can be made available to the rest of the application using Ember.inject.service
, which is a method that can retrieve services and make them available.
DI can be used to inject services into many different parts of the Ember application. Ember's architecture uses factories that are registered by Ember.Application
. We can inject into all routes, components, and controllers using the Application.inject
method.