INJECTABLE中文简体翻译:剑桥词典

Sometimes you want multiple instances of a service at the same level of the component hierarchy. That would result in a different instance of the service, living in a different injector. You can limit the scope of an injected service to a branch of the application hierarchy by providing that service at the sub-root component for that branch. So a particular service can be provided and created at any component level and multiple times if provided in multiple components. Service classes can act as their own providers which is why defining them in the @Injectable decorator is all the registration you need. Angular sets the injection parameter to null instead. The @Optional decorator tells Angular to continue when it can't find the dependency. But sometimes you need to limit the search and/or accommodate a missing dependency. The useClass provider creates and returns new instance of the specified class. You can use an InjectionToken for any kind of provider but it's particular helpful when the dependency is a simple value like a string, a number, or a function. But not every dependency can be satisfied by creating a new instance of a class. It's that simple because the most common injected service is an instance of a class. Another alternative is to mention the class in the providers array of the @NgModule and you're done. The provide object literal takes a token and a definition object. You need other ways to deliver dependency values and that means you need other ways to specify a provider. You usually let Angular handle this transaction by specifying a constructor parameter and its type. Angular sets the constructor's el parameter to the injected ElementRef, which is a wrapper around that DOM element. Angular would throw an error if you hadn't also decorated the property with the @Optional() function.

Why MinimalLogger is a class and not a TypeScript interfacelink

Parent is the provider's class-interface token. The parent must cooperate by providing an alias to itself in the name of a class-interface token. You can find a parent component with a class-interface. This example is examining whether a component can inject its parent via the parent's base class. You must provide the HeroService again for this component, then pass it down to the base class inside the constructor.

Inject into a derived classlink

Take care when writing a component that inherits from another component. The token description is another developer aid. You encountered them twice in the Hero of the Month example, in the title value provider and in the runnersUp factory provider. Look again at the TypeScript MinimalLogger class to confirm that it has no implementation. Imagine a HeroBiosComponent that presents three instances of the HeroBioComponent. This much Dependency Injection knowledge may be all that many Angular developers ever need to build their applications. The @Injectable decorator indicates that the Angular DI system is used to create one or more instances of UserContextService. 该网站需要浏览器支持 JavaScript

Cannot find a parent by its base classlink

This isn't usually a problem, especially if you adhere to the recommended one class per file rule. You can't refer directly to a class until it's been defined. The order of class declaration matters in TypeScript. It doesn't in this example only to demonstrate that the code will compile and run without the interface It's identical to Carol's constructor except for the additional @SkipSelf decorator. If you're going to keep writing alias providers like this you should create a helper function. Recall that Angular always adds a component instance to its own injector; that's why you could inject Alex into Cathy earlier. You cannot inject a parent by its base class.
  • At each step, the consumer of dependencies simply declares what it requires in its constructor and the framework takes over.
  • What if you don't know the concrete parent component class?
  • That would result in a different instance of the service, living in a different injector.
  • The Angular forwardRef() function creates an indirect reference that Angular can resolve later.
  • Using a class as an interface gives you the characteristics of an interface in a real JavaScript object.
  • The application might have a variety of parent types, each with its own class-interface token.
  • Barry's providers array looks just like Alex's.
  • This rule makes the component safe to construct under test without fear that it will do something dramatic like talk to the server.
If the search is futile, the injector throws an error—unless the request was optional. If it doesn't, it may be able to make one with the help of a provider. Its nativeElement property exposes the DOM element for the directive to manipulate.
Find the parent in a tree of parents with @SkipSelf()link
Notice the @Injectable()decorator on the UserContextService class. You simply declare what is needed in the constructor (LoggerService and UserContextService) and the framework does the rest. The beauty of dependency injection is that AppComponent doesn't care about any of this. The UserService has no dependencies so the dependency injection framework can just use new to instantiate one. There is no public API for acquiring a parent reference. Obtaining a component reference is a bit tricky in Angular. But sometimes it makes sense for one component to have a direct reference to another component perhaps to access values or call methods on that component. More loosely coupled techniques such as data binding and service sharing are preferable.
useFactory—the factory providerlink
  • After some undisclosed work, the function returns the string of names and Angular injects it into the runnersUp parameter of the HeroOfTheMonthComponent.
  • The consumer of an injected service does not know how to create that service.
  • But Angular calls the derived class's ngOnInit before calling the base class's ngOnInit so you'd be sorting the heroes array before they arrived.
  • It demands its own instance of the HeroService to get heroes and displays them in the order they arrive from the database.
  • You can use a value provider in a unit test to replace a production service with a fake or mock.
  • To minimize memory cost, the class should have no implementation.
The alternative could implement a different strategy, extend the default class, or fake the behavior of the real class in a test case. Use this technique to substitute an alternative implementation for a common or default class. The value of a value provider must be defined now. It's a special kind of provider lookup key called an InjectionToken. Use this technique to provide runtime configuration constants such as website base addresses and feature flags. At each step, the consumer of dependencies simply declares what it requires in its constructor and the framework takes over. Sometimes a service depends on other services, which may depend on yet other services. The consumer of an injected service does not know how to create that service. Services that are provided this way are automatically made available to the entire application and don't need to be listed in any module.

Defining providerslink

A re-usable component might be a child of multiple components. Application components often need to share information. Overriding the base class's afterGetHeroes() method solves the problem. Now that you've registered these services, Angular can inject them into the constructor of any component or service, anywhere in the application. Angular creates a service instance from a class provider by using new. Register providers for dependencies used throughout the application in the @Injectable() decorator of the service itself. The provide object literallink ProvidedIn here tells Angular that the root injector is responsible for creating an instance of the HeroService. The following example shows how a service class is properly marked so that a supporting service can be injected upon creation. The Parent Finder sample is full of circular class references that are impossible to break. The Angular forwardRef() function creates an indirect reference that Angular can resolve later. You're in a bind when class 'A' refers to class 'B' and 'B' refers to 'A'. They'd be competing with each other to determine which hero to cache. Clearly the three instances of the HeroBioComponent can't share the same HeroCacheService. A HeroBioComponent relies on a HeroCacheService to fetch, cache, and perform other persistence operations on that hero. Each HeroBioComponent can edit a single hero's biography. Narrowing an API through an aliasing interface is one important use case for this technique. Components outside the tree continue to receive the original LoggerService instance. When this component requests the LoggerService, it receives the DateLoggerService instead. The second provider substitutes the DateLoggerService for the LoggerService. The definition object has a required property that specifies how to create the singleton instance of the service. When a component requests a dependency, Angular starts with that component's injector and walks up the injector tree until it finds the first suitable provider. Each of these components has its own HeroService instance managing its own independent collection of heroes. Barry's providers array looks just like Alex's. That means he must both inject the Parent class-interface to get Alice and provide a Parent to satisfy Carol. Both Alice and Barry implement the Parent class-interface. The CraigComponent tries to inject Base into its alex constructor parameter and reports if it succeeded.
  • The Hero provider token is a class which makes sense because the value is a Hero and the consumer of the injected hero would want the type information.
  • You encountered them twice in the Hero of the Month example, in the title value provider and in the runnersUp factory provider.
  • Use this technique to create a dependency object with a factory function whose inputs are some combination of injected services and local state.
  • When Angular creates the HeroesBaseComponent, it also creates a new instance of HeroService that is visible only to the component and its children, if any.
  • Each HeroBioComponent gets its own HeroCacheService instance by listing the HeroCacheService in its metadata providers array.
  • It never grows no matter how many members you add to the class as long as those members are typed but not implemented.
Marking a class with @Injectable ensures that the compiler will generate the necessary metadata to create the class's dependencies when the class is injected.
  • But sometimes you need to limit the search and/or accommodate a missing dependency.
  • The getter for the hero property pulls the cached hero from the service.
  • The order of class declaration matters in TypeScript.
  • That means he must both inject the Parent class-interface to get Alice and provide a Parent to satisfy Carol.
  • Register providers for dependencies used throughout the application in the @Injectable() decorator of the service itself.
  • The only LoggerService instance in the app is provided at the AppComponent level.
  • But because every component instance is added to an injector's container, you can use Angular dependency injection to reach a parent component.
  • It's identical to Carol's constructor except for the additional @SkipSelf decorator.
Unfortunately, Angular cannot inject the HeroService directly into the base class. The type parameter, while optional, conveys the dependency's type to developers and tooling. Dependency objects can be simple values like dates, numbers and strings, or shapeless objects like arrays and functions. Such a narrowing interface helps decouple the concrete class from its consumers. A class-interface should define only the members that its consumers are allowed to call. When you use a class this way, it's called a class-interface. The MinimalLogger is used exclusively as a dependency injection token. But no class in this application inherits from MinimalLogger. The parent HeroBiosComponent binds a value to the heroId. Each service has its own work-state, isolated from the service-and-state of a different component. You could also provide the HeroService to a different component elsewhere in the application. The host HeroBioComponent doesn't have its own LoggerService provider. The only LoggerService instance in the app is provided at the AppComponent level. The @Host decorator stops the upward search at the host component.
  • You can use an InjectionToken for any kind of provider but it's particular helpful when the dependency is a simple value like a string, a number, or a function.
  • The Parent class-interface defines a name property with a type declaration but no implementation.
  • Parent is the provider's class-interface token.
  • The second provider substitutes the DateLoggerService for the LoggerService.
  • Such a narrowing interface helps decouple the concrete class from its consumers.
  • The function retrieves candidate heroes from the HeroService, takes 2 of them to be the runners-up, and returns their concatenated names.
  • The dependency object doesn't have to be a class instance.
  • Here's a revised version that defaults to parent but also accepts an optional second parameter for a different parent class-interface.
  • Narrowing an API through an aliasing interface is one important use case for this technique.
  • The @Injectable decorator indicates that the Angular DI system is used to create one or more instances of UserContextService.
Use this technique to create a dependency object with a factory function whose inputs are some combination of injected services and local state. The useFactory provider creates a dependency object by calling a factory function as in this example. The Hero provider token is a class which makes sense because the value is a Hero and the consumer of the injected hero would want the type information. Angular throws an error if it can't find the dependency during that walk. As you now know, dependencies can be registered at any level in the component hierarchy. And the template displays this data-bound property. Each HeroBioComponent gets its own HeroCacheService instance by listing the HeroCacheService in its metadata providers array. This is called sandboxing because each service and component instance has its own sandbox to play in. You need a separate instance of the service for each component. A good example is a service that holds state for its companion component instance. On occasion you might need to access a component's corresponding DOM element. The logger logic kicks in and the hero display updates with the gratuitous "!!!", indicating that the logger was found. If you comment out the @Host() decorator, Angular now walks up the injector ancestor tree until it finds the logger at the AppComponent level. Thanks to @Optional(), Angular sets the loggerService to null and the rest of the component adapts. This section demonstrates how to write providers that deliver dependent services. Angular throws an error if the parent lacks that service, even if a component higher in the component tree happens to have it. The getter for the hero property pulls the cached hero from the service.
  • The other providers create their values lazily when they're needed for injection.
  • The local state is the number 2, the number of runners-up this component should show.
  • On occasion you might need to access a component's corresponding DOM element.
  • The token description is another developer aid.
  • Sometimes a service depends on other services, which may depend on yet other services.
  • The parent must cooperate by providing an alias to itself in the name of a class-interface token.
  • The Parent Finder sample is full of circular class references that are impossible to break.
useValue—the value providerlink
Such a narrow interface helps decouple the child component class from its parent components. But because every component instance is added to an injector's container, you can use Angular dependency injection to reach a parent component. The @Host() function decorating the heroCache property ensures that you get a reference to the cache service from the parent HeroBioComponent. Here's a revised version that defaults to parent but also accepts an optional second parameter for a different parent class-interface. Looking back, you see that the Alex component extends (inherits) from a class named Base. If you're lucky, they all implement the same base class whose API your NewsComponent understands. The app probably defines more than a dozen financial instrument components. For business reasons, this news component makes frequent calls directly into its parent instrument as changing market data streams by. The HeroOfTheMonthComponent example has two value providers. You can use a value provider in a unit test to replace a production service with a fake or mock. The token is usually a class but it doesn't have to be.
  • Angular would throw an error if you hadn't also decorated the property with the @Optional() function.
  • For business reasons, this news component makes frequent calls directly into its parent instrument as changing market data streams by.
  • All injected service dependencies are singletons meaning that, for a given dependency injector, there is only one instance of service.
  • But when this component is projected into a parent component, that parent component becomes the host.
  • They could have implemented it instead in the manner of an interface.
  • The app probably defines more than a dozen financial instrument components.
  • You need other ways to deliver dependency values and that means you need other ways to specify a provider.

@Injectable() and nested service dependencieslink

It's the dependency injection's job to create and cache that service. Read more about providers in the Dependency Injection guide. A provider is something that can create or deliver a service. Angular supplies these arguments from injected values identified by the two tokens in the deps array. That returned function takes a winning Hero and a HeroService as arguments. The local state is the number 2, the number of runners-up this component should show. Imagine that the LoggerService had a large API, much larger than the actual three methods and a property. The runnersUpFactory itself isn't the provider factory function. In this example, the dependency object is a string of the names of the runners-up to the "Hero of the Month" contest. The useExisting provider maps one token to another. The other providers create their values lazily when they're needed for injection. Such objects don't have application interfaces and therefore aren't well represented by a class. You can't use an interface as a provider token because interfaces are not JavaScript objects. The dependency object doesn't have to be a class instance. @Injectable()link But an Angular application has multiple dependency injectors, arranged in a tree hierarchy that parallels the component tree. All injected service dependencies are singletons meaning that, for a given dependency injector, there is only one instance of service. Generally, register providers in the NgModule rather than in the root application component. Set the useValue property to a fixed value that the provider can return as the service instance (AKA, the "dependency object"). The providers array is a property of the @Component decorator function which must appear above the class definition. The application might have a variety of parent types, each with its own class-interface token. You face this dilemma when a class makes a reference to itself as does the AlexComponent in its providers array. The current version of the helper function can only alias the Parent class-interface. The name property is the only member of a parent component that a child component can call. The Parent class-interface defines a name property with a type declaration but no implementation. You learned earlier that a class-interface is an abstract class used as an interface rather than as a base class. These complications argue for avoiding component inheritance. Users want to see the heroes in alphabetical order. That's why you call the HeroService from within the ngOnInit rather than the constructor. This rule makes the component safe to construct under test without fear that it will do something dramatic like talk to the server. In this contrived example, SortedHeroesComponent inherits from HeroesBaseComponent to display a sorted list of heroes. Looking for components that implement an interface would be better. What if you don't know the concrete parent component class? You use standard class injection to acquire a parent component whose type you know. Although an Angular application is a tree of components, there is no public API for inspecting and traversing that tree. But Angular calls the derived class's ngOnInit before calling the base class's ngOnInit so you'd be sorting the heroes array before they arrived. The SortedHeroesComponent lets the base class fetch the heroes. Rather than modify the original component, sub-class it and create a SortedHeroesComponent that sorts the heroes before presenting them. It demands its own instance of the HeroService to get heroes and displays them in the order they arrive from the database. Using a class as an interface gives you the characteristics of an interface in a real JavaScript object. The previous Hero of the Month example used the MinimalLogger class as the token for a provider of a LoggerService. But the token doesn't have to be a class and even when it is a class, it doesn't have to be the same type as the returned object. The two deps values are tokens that the injector uses to provide these factory function dependencies. This component and its tree of child components receive the DateLoggerService instance. A second @Host() function decorates the loggerService property. But when this component is projected into a parent component, that parent component becomes the host. The host component is typically the component requesting the dependency. Find this example inlive codeand confirm that the three HeroBioComponent instances have their own cached hero data. The ngOnInit passes that id to the service, which fetches and caches the hero. The simple way of defining providers in the @Injectable decorator of the class is recommended. Angular initializes the injectors it creates with some providers it cares about. Angular passes this token to the injector and assigns the result to the parameter. The parameter type serves as the injector lookup token. He needs to reach his parent, Alice, and also be a parent to Carol. Theconfirms that the alex parameter is null. That's not possible because TypeScript interfaces disappear from the transpiled JavaScript, which doesn't support interfaces. Imagine a component for rendering breaking news about a financial instrument. Notice that even though the @Optional qualifier is there for safety, theconfirms that the alex parameter is set. It never grows no matter how many members you add to the class as long as those members are typed but not implemented. To minimize memory cost, the class should have no implementation. They could have implemented it instead in the manner of an interface. You usually inherit from an abstract class. The function retrieves candidate heroes from the HeroService, takes 2 of them to be the runners-up, and returns their concatenated names. After some undisclosed work, the function returns the string of names and Angular injects it into the runnersUp parameter of the HeroOfTheMonthComponent. The true provider factory function is the function that runnersUpFactory returns. When Angular creates the HeroesBaseComponent, it also creates a new instance of HeroService that is visible only to the component and its children, if any. This example shows how similar providing a service to a sub-root component is to providing a service in the root AppComponent. Sometimes you want to restrict service availability to a particular region of the application. Accordingly, dependencies provided in the root AppComponent can be injected into any component anywhere in the application. When Angular creates the AppComponent, the dependency injection framework creates an instance of the LoggerService and starts to create the UserContextService.