4
votes

https://github.com/emberjs/ember.js/blob/5fd2d035b30aa9ebfe73de824b3b283ec8e589cc/packages/ember-runtime/lib/system/service.js#L31

In the line I reference above the ember-core team imports this createInjectionHelper and uses it to add a clean/simple api for injecting services like so

App.ApplicationRoute = Ember.Route.extend({
  authManager: Ember.inject.service('auth'),
  model: function() {
    return this.get('authManager').findCurrentUser();
  }
});

How can I create something like this myself for a non service?

2

2 Answers

6
votes

Your example usage will change slightly from what you have above. We will cover what the injectRepositories does in a little bit.

import injectRepositories from 'app/utils/inject';

export default Ember.Route.extend({
    repository: injectRepositories('person'),
    model: function() {
    var repository = this.get('repository');
        return repository.find();
    }
});

The initializer can be improved with the following changes:

import registerWithContainer from "ember-cli-auto-register/register";

export function initialize(_, application) {
    registerWithContainer("repositories", application);
    application.inject("repositories", "store", "store:main");
}

export default {
    name: "repositories",
    after: "store",
    initialize: initialize
};

Let's break down what is happening in each line.

registerWithContainer("repositories", application);

In the line above, we are deferring to the ember-addon ember-cli-auto-register. This addon will take a directory, in this situation, the repositories directory and register each object into the Ember container to able to be accessed via a lookup. They will be inserted as if doing the following:

application.register("repositories:person", PersonRepository);

Then we add a function to do the injection using the ember-addon ember-cli-injection:

// app/utils/inject.js
import inject from "ember-cli-injection/inject";

var injectRepositories = inject("repositories");

export default injectRepositories;

This then allows us the opportunity to use the newly created function above to access these objects with the code below:

import injectRepositories from 'app/utils/inject';

export default Ember.Route.extend({
    repository: injectRepositories('person'),
    model: function() {
    var repository = this.get('repository');
        return repository.find();
    }
});

Since each object is now in the container, we can look it up and inject at runtime instead of during the initialization of the application. We register the repositories key in the function and this then returns a computed property (see code below from ember-cli-injection). We do this as a computed property to allow lazy loading. The object is not fetched from the container until the property is accessed.

import Ember from 'ember';

var injection = function(key) {
    return function(name) {
        return Ember.computed(function(propertyName) {
            var objectName = name || propertyName;
            return this.container.lookup(key + ':' + objectName);
        });
    };
};

export default injection;

We also allow for a name to passed to the repositories function, for example repository: injectRepositories('person'). This allows you to name your object whatever you would like when injecting it.

If you would like to just name the object the same as the name of the repository injected into the container you can alternatively do person: injectRepositories(). This will pass the person key to the computed property as the propertyName and since the name was left null when injecting, the objectName will instead be person. This matches the API produces similar results but is not the same as that of the Ember.inject.service and Ember.inject.controller API that is available as of Ember 1.10.

0
votes

I don't think it's their intention for you to use it this way. The standard way is to use App.inject() if you're using plain ember, or do this in an initializer if you're using ember-cli.

In your case:

// Register the service
App.register('service:auth', {
  findCurrentUser: function() {
    // Do your magic
  }
}, { instantiate: false });

App.inject('route', 'auth', 'service:auth');

Then in your model hook you can use this.auth.findCurrentUser();. You can also inject this into controllers and components if you need. Also note, to keep it clean, that you might want to include a separate module instead of defining your auth module in the service registration.

More info here:

http://emberjs.com/guides/understanding-ember/dependency-injection-and-service-lookup/#toc_dependency-injection-with-code-register-inject-code

NOTE

A service is also not a "special" thing. You can inject anything you want into pretty much anything you want using this method.