How to inject data into a controller?

I have a rails view that needs to supply data to a controller before the app is running. It seems the inject/intializer calls would be appropriate for this. Unfortunately, the current methods seem really cumbersome for what I want to do (or the docs are hard to grok). The best example I’ve found so far might be this post about introducing a currentUser variable to every controller:

https://gist.github.com/ivanvanderbyl/4560416

What I want is simpler. And, I think should be super easy for everyone to do as a new user. Say you a controller and you want to introduce the variable “awesomeData” to it in a script tag on the page hosting/rending your ember app (this is a common paradigm if you are using Ember apps as “partials” on otherwise normal HTML/js pages. You might imagine something like:

  MyApplication.injection('controller:first, 'awesomeData');

Mind you, I don’t really understand the current syntax or what ‘controller:firstController’ or 'data:awesome" would or should even do (injectionName? factoryName?!?), but I do know I’d like the call to be as simple as this. Then, when my firstController is active, I’d have:

  MyApplication.FirstController = Ember.Controller.extend({
    
    someProperty: function() {
       return this.get('awesomeData');
    }
  });

Is it already this simple? Can it be so?! Thanks!

After reading most of the Ember.Container code and mucking with some samples, I found the answer. In layman terms:

  • register a factory for your data/object
  • inject an instance from a factory into an parent factory object, at a given name/property, using a registered factory.

In code, this looks like this:

var data = {name: "John Doe", location: "London"};
App.register('data:sample', data, { instantiate: false, singleton: true } );
App.inject('controller:first', 'the_data_i_want', 'puddle:sample');

// in your controller
this.get('the_data_i_want')

In the example above, first, register the variable “data” as a factory named “data:sample.” Usually, this is an object that can be instantiated with Ember.create(). However, if you pass instantiate: false, then when the container is asked to instantiate an object using “data:sample” it will actually just return the factory object registered. In this case, just a simple JS hash of data. If singleton is true (the default?) then the object created/returned is cached for future demands on the factory.

Second, we ask the app to inject the object returned by the factory “puddle:sample” into the object returned by the factory “controller:first” as the property “the_data_i_want” - that is, set a property on firstController (a singleton, like all controllers, by default) using the value registered with the factory-name “data:sample”.

To me, the naming of the parameters for inject() in RC5 were confusing (I expected the opposite order), but the first param (aka, factoryNameOrType) is to be the recipient of the injection and the last param (injectionName) is the source of the injection object.

As for factory names, you can choose whatever you want, so long as it has 1 colon in the name (as of the current release). Ember, of course, by convention uses certain patterns for the common types of controller, router, template, etc. Adding to the confusion is the feature that not all “factories” are configured to create things. The container’s registry just doubles as a list of global registry, albeit only searchable (aka, lookup) by the container itself.

2 Likes

Thank you for the follow up on your own question.

I’m trying to understand the difference between instantiate and singleton.

What’s the difference between

{ instantiate: true, singleton: true }

and

{ instantiate: false, singleton: true }

?

I think I figured it out.

Value of singleton only matters when instantiate: true because when instantiate is false lookup() returns the factory object.

For anyone else looking to understand this subject, there is a good answer going over injection in response to this question on StackOverflow.