Having multiple classes in the same file is confusing and best avoided. You can call get() with a second parameter, which is the value to return if the service
covered shortly. The definition looks like this: Register the dependency provider using the OpaqueToken object: Now you can inject the configuration object into any constructor that needs it, with Unlike EvenBetterLogger, you can't inject the UserService into the HeroService. or after navigating to a component with the router.
to return a BetterLogger when something asks for the Logger.
You could give it a provider that calls a logger factory function. When you can't control the dependencies, a class becomes difficult to test. There are many ways to create dependency values just as there are many ways to write a recipe. When you need a Car, you simply ask the injector to get it for you and you're good to go. The Logger and UserService classes serve as tokens for their own class providers. You can either register a provider within an NgModule or in application components. It's a small change: Adding a parameter to the constructor isn't all that's happening here. When you write tests for Car you're at the mercy of its hidden dependencies. It just consumes them. You do have to configure the injector by registering the providers This is important in general, but not in this example. Change the Car constructor to a version with DI: See what happened? That may suffice in the early stages of development, but it's far from ideal. the compiler adds the metadata to the generated JavaScript But it's not the only way. Imagine writing the following code: The Car class creates everything it needs inside its constructor. You learned the basics of Angular dependency injection in this page. system, which means that nested injectors can create their own service instances. You don't have to create an Angular injector. The solution: alias with the useExisting option. But what about that poor consumer? Only authorized users should see secret heroes.
You'd apply the same constructor injection pattern,
OldLogger has the same interface as the NewLogger, but for some reason Listing dependencies as constructor parameters may be all you need to test application parts effectively. which is also injected at the application level. That means that every provider asynchronous, perhaps returning a Promise. You don't have a gigantic factory class to maintain. For example, you can create a new HeroListComponent with a mock service that you can manipulate registered in the AppModule @NgModule providers array. This Car lacks the flexibility a logger? You register some classes with this injector, and it figures out how to create them. If the app were actually getting data from a remote server, the API would have to be If you You can pass in any kind of engine or tires you like, as long as they But why flirt with trouble? If the emitDecoratorMetadata compiler option is true What if it reported its activities through a logging service? That authorization can change during the course of a single application session, the very specific classes Engine and Tires. Earlier you registered the Logger service in the providers array of the metadata for the AppModule like this: There are many ways to provide something that looks and behaves like a Logger. Note that the services themselves are not injected into the component. There is no AppConfig class. Not every JavaScript class has metadata. What if you want to put a different brand of tires on your Car? so put it in the project's app folder and It needed that provider to create a Logger to inject into a new
The TypeScript compiler discards metadata by default. create all three parts: the Car, Engine, and Tires. Also see "Should I add app-wide providers to the root AppModule or in order to inject a Logger.
An interface is a TypeScript design-time artifact. Now, if someone extends the Engine class, that is not Car's problem. The second is a provider definition object, separate concern, It isn't necessary because the This Car needs an engine and tires. It doesn't have any dependencies of its own.
Car class inflexible. in this blog post. when it creates components for youwhether through HTML markup, as in
That makes the This is where the dependency injection framework comes into play. which displays a list of heroes. defined in another file. The consumer must update the car creation code to This page covers what DI is, why it's so useful, decorator class (like @Directive and @Pipe, which you learn about later) is not found. service associated with that HeroService class token: This is especially convenient when you consider that most dependency values are provided by classes. identify a class as a target for instantiation by an injector. The Car class shed its problems at the consumer's expense. constructor, as discussed earlier. the HeroesComponent in the same file, It could acquire services from any ancestor component, not just its own. Per the dependency injection pattern, the component must ask for the service in its You could create such an injector You'd also have to rewrite the way components consume the service. in its providers array. Keep them happy. Unfortunately, you This is actually a shorthand expression for a provider registration
Because the HeroService is used only within the HeroesComponent
Here's a revised HeroesComponent that registers the HeroService in its providers array. The component then asks the injected injector for the services it wants. like HeroesComponent. Framework developers may take this approach when they In this sample, you need it only in the HeroesComponent, The Engine constructor parameters weren't even a consideration when you first wrote Car. Earlier you saw that designing a class for dependency injection makes the class easier to test.
to define and use an OpaqueToken. explicitly: You won't find code like that in the Tour of Heroes or any of the other something like this: The critical point is this: the Car class did not have to change. You're locked into whatever brand the Tires class creates. Maybe an EvenBetterLogger could display the user name in the log message. Here is the revision compared to the original. You can tell Angular that the dependency is optional by annotating the The dependency injector should inject that singleton instance during each test: You just learned what dependency injection is. Providers are the subject of the next section. If you let Angular do its job, you'll enjoy the benefits of automated dependency injection. service locator pattern. and the parent's providers information combine to tell the What if the dependency value isn't a class? The HeroService requires a Logger, but what if it could get by without Angular's dependency injection system creates and delivers dependent services "just-in-time". The definition of the dependencies are using a provider object literal with two properties: The first is the token that serves as the key for both locating a dependency value You certainly do not want two different NewLogger instances in your app. What does Engine depend upon? Right now each new car gets its own engine. Notice that you captured the factory provider in an exported variable, heroServiceProvider. the help of an @Inject decorator: Although the AppConfig interface plays no role in dependency injection, But maintaining it will be hairy as the application grows. You certainly don't want that going on during tests.
It's a coding pattern in which a class receives its dependencies from external That makes Car brittle. of its dependencies. where it replaces the previous HeroService registration in the metadata providers array. That would break the Car class and it would stay broken until you rewrote it along the lines of Angular knows to inject the As soon as you try to test this component or want to get your heroes data from a remote server, Given that the service is a It's difficult to explain, understand, and test. You need it because Angular requires constructor parameter metadata
Here, the APP_CONFIG service needs to be available all across the application, so it's the HeroListComponent class has an @Component decorator
and, therefore, do not technically require it. Here's why: Injectors are also responsible for instantiating components This extra step makes the factory provider reusable. Note that the constructor parameter has the type HeroService, and that has providers information for HeroService. is a subtype of @Injectable(). The consumer knows nothing about creating a Car. You call that property within the getHeroes() method when anyone asks for heroes. (as it should be in the tsconfig.json), When you define a constructor parameter with the HeroService class type,
and let the injector pass them along to the factory function: The useFactory field tells Angular that the provider is a factory function cannot use a TypeScript interface as a token: That seems strange if you're used to dependency injection in strongly typed languages, where fact @Injectable() decorators that asked for a dependency. This is what a dependency injection framework is all about.
But you must have it now that the service has an injected dependency.
Unfortunately, that's what you get if you try to alias OldLogger to NewLogger with useClass. @Injectable()?
error when trying to instantiate a class that is not marked as Instead, the HeroService constructor takes a boolean flag to control display of secret heroes. It can't share an engine with other cars. Now you can create a car by passing the engine and tires to the constructor.
They are retrieved by calling injector.get(). It's better to make a service that hides how the app gets hero data.
The TypeScript interface disappears from the generated JavaScript. The injector maintains an internal token-provider map that it references when the HeroService must hide secret heroes from normal users.
The HERO_DI_CONFIG constant has an interface, AppConfig. This stripped down version has only one child, HeroListComponent,
To understand why dependency injection is so important, consider an example without it.
The application will fail mysteriously if you forget the parentheses. Everyone wins.
The @Injectable() decorator above the service class is
To illustrate the point, add a new business requirement:
Always write @Injectable(), not just @Injectable.
which you can think of as a recipe for creating the dependency value. You need something that takes care of assembling these parts. having to define which dependency gets injected into what? This logger gets the user from the injected UserService, You saw how to use an injector to create a new You'll have to take over the creation of new instances of this HeroService with a factory provider. You could write a giant class to do that: It's not so bad now with only three creation methods. create and inject into a new HeroListComponent.
Right now HeroListComponent gets heroes from HEROES, an in-memory collection Wouldn't it be nice if you could simply list the things you want to build without The following code tells the injector conform to the general API requirements of an engine or tires.
JavaScript doesn't have interfaces. You can register various kinds of providers, You inject both the Logger and the UserService into the factory provider value of logger to null. that the injector injects into components and other services. A service is nothing more than a class in Angular. You could provide a substitute class. Here's the AppModule that registers two providers, UserService and an APP_CONFIG provider, The Logger class itself is an obvious and natural provider. documentation samples. The technique is an example of the constructor argument with @Optional(): When using @Optional(), your code must be prepared for a null value. If you define the component before the service, Angular can't find the service if it's not registered with this or any ancestor injector. Angular injector to inject an instance of Here you see the new and the old implementation side-by-side: When you register a provider with an injector, you associate that provider with a dependency injection token.
The consumer of Car has the problem. You actually can define the component first with the help of the forwardRef() method as explained The HeroListComponent should get heroes from the injected HeroService. adding a parameter to a constructor. An Injector is itself an injectable service. now in the constructor. this.engine = new Engine(theNewParameter). It governs all the child components of this area. Cool!
At runtime, injectors can read class metadata in the transpiled JavaScript code you'd like the singleton instance of NewLogger to handle it instead. Will a new instance of Engine make an asynchronous call to the server?
based on information you won't have until the last possible moment. in the NgModule FAQ. You could write code that explicitly creates an injector if you had to, One solution to choosing a provider token for non-class dependencies is You must register a service provider with the injector, or it won't know how to create the service. On the other hand, a provider registered in an application component is available only on The deps property is an array of provider tokens. (scroll up to confirm that fact). HeroService whenever it creates a new HeroListComponent. Consider adding @Injectable() to every service class, even those that don't have dependencies Also recall that the parent component (HeroesComponent) The Car knows nothing about creating an Engine or Tires. What's the problem? and how to use it in an Angular app. start with a simplified version of the HeroesComponent It remains nothing more than a class until you register it with an Angular injector. The injector resolves these tokens and injects the corresponding services into the matching factory function parameters. whose implementation is the heroServiceFactory.
Then you register a provider with the useValue option, It is in you can't update the old component to use it. Suppose also that the injectable service has no independent access to the source of this information.