How to "eagerly" inject a service


#1

I’m facing the problem where I bind directly to a property of a service from within my template. This won’t work if no JS code has accessed the service before. As a workaround I have to “fake access” the service in my component’s init function.

Is there a way to always load the service without having to explicitly access it first? Or is something like this planned?


#2

It seems odd, does that happen from a component? Can you show your code?


#3

Oh sorry, I haven’t described the problem correctly. When observing a property of a service without accessing its value the observer isn’t notified of property changes.

https://ember-twiddle.com/e6aebd6d44e5c49f8c3e


#4

I see. It is not because it is a service. This is because, more generally speaking, observers are lazy. That is, they are not actually set up until the property they observe is read at least once.

In your component1, nothing ever reads myService, so the computed property (which loads the service, but any other type of computed property would behave the same) is never computed. So the observer is never setup.

Most of the time it does not matter because you read the property somewhere anyway. But when it happens, it is enough to simply read the property once. For instance, you can fix component1 by adding this:

init: function () {
  this._super();
  this.get('myService');   // read the computed property to force its setup
},

[edited thanks to workmanw’s and rwjblue’s suggestions below]


#5

@spectras

Are you sure this works? You use to have to “kick” the property after the this._super();.

init: function () {
  this.get('myService');   // read the computed property to force its setup
  this._super();
}

#6

You should generally call this._super before touching this (this is required in class constructors for example).


#7

@workmanw> I am sure it works, I tested it on his twiddle.

Does not mean it’s good, and I would definitely trust rwjblue on this issue and invert the two lines. Actually, I’ll edit my post right now.


#8

@spectras Thanks for the explanation! Accessing it in init was the workaround I described in my original post. So there is no other way? Like a parameter for the observer? Or for the “computed property”?


#9

Not that I know of. It is a known limitation of computed property/observer interactions : as long as nothing computes the property, it does not actually change so there is nothing to observe.

There is a big advantage to this approach : you can define convenience computed properties, they cost nothing until they are actually used.


#10

Knockout had the deferEvaluation option for this and later introduced “pure” computed properties that somehow detect whether they are observed or not.

Alternatively why not have an observer implicitly access the computed property once? It is obvious for Ember that an observer is interested in the computed property so why optimize?


#11

Unfortunately I’m just a random Ember user, I cannot answer that one, but maybe someone from Ember team will shed some light on your question ^^