Hi! I’m trying to determine the differences, advantages/disadvantages of services, initializers and utils? When should I use one or another? Thanks!
-
utils
are stateless. They’re usually utility functions, but sometimes you put constants and enums in there too. -
services
are likeutils
but are allowed to hold states. They are singleton objects. In early versions of Ember, you create special controllers that holds state and inject these controllers into other controllers associated to routes. This way you can achieve cross-outlet communication.services
were introduced to formalize these special controllers as standard practice. -
initializers
allows you to operate on theEmber.Application
instance before your application boots. You can configure dependency injection and defer application boot during this time. They are sometimes used to do things that’s not standard to usual Ember applications, like reopening Ember’s classes to patch them for varies reasons. In other words, you use it to do things that Ember doesn’t usually let you do. If Ember’s opinionated nature has a rulebook, these is where you break the rules. But first, you need to learn the rules.
Thank you!
I’ve been reading about services and factories, and I have doubts about them. What is the difference between injecting a factory and injecting a service? Could you please explain more about this? I couldn’t see a real world difference here.
From a public API standpoint, there are no factory concepts. All factory related APIs are private to Ember internals. For beginners, it is best to pretend they don’t exist.
There are only two things you can inject, controllers and services. Services are just special controllers anyway. So you’re really only injecting controllers.
@lightblade the register
on the application is public.
And @IAmJulianAcosta all services are automatically injected as a factory. Ember.inject.service()
later allows you to inject this factory. Its identical to App.inject()
but can be done from within anything that gets initialized by the DI container.
Its identical to lookup the dependency manually with Ember.getOwner(this).lookup('service:foo')
.
Usually use initializers to:
- Inject a service into a factory type. For example inject a specific service into all controllers.
- Register service-like non ember stuff.
- Do work before your application loads. I for example fetch my translations with an initializer, or initialize twitter bootstrap tooltips.
Services are to hold global application state. The current user is the best example, but it could also be a backend.
Utils is easy for stateless functions of all kind.
I see many people say services in Ember are meant for state. Does Ember discourage the use of services for anything that’s not state? To me, I think it would be beneficial to add methods (for example, methods that perform business logic) that utilize dependency injection but that would mean adding services that only have methods and not state. But I don’t see this talked about so I’m wondering what Ember’s take on that is. Are there any disadvantages or reasons not to do this?
I think services are a great place to put methods depending on what they do. Generally business logic involves manipulating some state. If that state isn’t owned by the service or by something the service is wrapping (a third party library for example) you may have a less-than-ideal pattern on your hands. But it really depends. Could you describe what you mean in a little more detail?
The project I’m on has this pattern where, if a component gets really really big, people will naturally want to extract some logic out into other files. Some of the developers on this project are use to things like React where DI isn’t as much of a thing so instead of using services, they create what they call a util file and put the logic there. Really, that util file is just extra logic behind component and it seems like they use the util name because what else would you call that kind of file.
To me, these could go in services… cause I have always viewed services as just classes that are dependency injected and not necessarily tied to any specific use case. That way, you could also make use of other dependency injection too or have access to Embers ecosystem.
The solution back in the day was usually mixins. However those have been discouraged for a number of reasons for a long time, and aren’t supported with glimmer components. If the method is more of a “pure functional” method and doesn’t mutate state you can easily put it in a util function and import that anywhere. Obviously if the method is mutating component state you wouldn’t want to keep it in a service as a service reaching into a component is pretty weird. IMO there’s nothing wrong per-se with putting things like this on a service, but it doesn’t make sense unless they’re related and it makes sense to treat them as a singleton class. In many cases that will involve global state, though I wouldn’t say it does as a rule. If they’re just methods you want to share or abstract out though a util probably makes more sense.
For another great thread about replacing mixins (which is related to this topic) see here
If it’s simple JS business logic fairly untied to anything Ember specific then this can be a nice pattern. If you need a lot of access to Ember specific things such as other services though then keeping the logic in a service may be nicer