5 lines
24 KiB
JSON
5 lines
24 KiB
JSON
{
|
|
"id": "guide/dependency-injection-providers",
|
|
"title": "Dependency providers",
|
|
"contents": "\n\n\n<div class=\"github-links\">\n <a href=\"https://github.com/angular/angular/edit/master/aio/content/guide/dependency-injection-providers.md?message=docs%3A%20describe%20your%20change...\" aria-label=\"Suggest Edits\" title=\"Suggest Edits\"><i class=\"material-icons\" aria-hidden=\"true\" role=\"img\">mode_edit</i></a>\n</div>\n\n\n<div class=\"content\">\n <h1 id=\"dependency-providers\">Dependency providers<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#dependency-providers\"><i class=\"material-icons\">link</i></a></h1>\n<p>By configuring providers, you can make services available to the parts of your application that need them.</p>\n<p>A dependency <a href=\"guide/glossary#provider\">provider</a> configures an injector with a <a href=\"guide/glossary#di-token\">DI token</a>, which that injector uses to provide the runtime version of a dependency value.</p>\n<h2 id=\"specifying-a-provider-token\">Specifying a provider token<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#specifying-a-provider-token\"><i class=\"material-icons\">link</i></a></h2>\n<p>If you specify the service class as the provider token, the default behavior is for the injector to instantiate that class with <code>new</code>.</p>\n<p>In the following example, the <code>Logger</code> class provides a <code>Logger</code> instance.</p>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" region=\"providers-logger\">\nproviders: [Logger]\n\n</code-example>\n<p>You can, however, configure an injector with an alternative provider in order to deliver some other object that provides the needed logging functionality.</p>\n<p>You can configure an injector with a service class, you can provide a substitute class, an object, or a factory function.</p>\n<a id=\"token\"></a>\n<a id=\"injection-token\"></a>\n<h2 id=\"dependency-injection-tokens\">Dependency injection tokens<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#dependency-injection-tokens\"><i class=\"material-icons\">link</i></a></h2>\n<p>When you configure an <a href=\"guide/glossary#injector\">injector</a> with a <a href=\"guide/glossary#provider\">provider</a>, you are associating that provider with a <a href=\"guide/glossary#di-token\">dependency injection token</a>, or DI token.\nThe injector allows Angular create a map of any internal dependencies.\nThe DI token acts as a key to that map.</p>\n<p>The dependency value is an instance, and the class type serves as a lookup key.\nHere, the injector uses the <code>HeroService</code> type as the token for looking up <code>heroService</code>.</p>\n<code-example path=\"dependency-injection/src/app/injector.component.ts\" region=\"get-hero-service\" header=\"src/app/injector.component.ts\">\nheroService: HeroService;\n\n</code-example>\n<p>When you define a constructor parameter with the <code>HeroService</code> class type, Angular knows to inject the service associated with that <code>HeroService</code> class token:</p>\n<code-example path=\"dependency-injection/src/app/heroes/hero-list.component.ts\" region=\"ctor-signature\" header=\"src/app/heroes/hero-list.component.ts\">\nconstructor(heroService: HeroService)\n\n</code-example>\n<p>Though classes provide many dependency values, the expanded <code>provide</code> object lets you associate different kinds of providers with a DI token.</p>\n<a id=\"provide\"></a>\n<h2 id=\"defining-providers\">Defining providers<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#defining-providers\"><i class=\"material-icons\">link</i></a></h2>\n<p>The class provider syntax is a shorthand expression that expands into a provider configuration, defined by the <a href=\"api/core/Provider\"><code>Provider</code> interface</a>.\nThe following example is the class provider syntax for providing a <code>Logger</code> class in the <code>providers</code> array.</p>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" region=\"providers-logger\">\nproviders: [Logger]\n\n</code-example>\n<p>Angular expands the <code>providers</code> value into a full provider object as follows.</p>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" region=\"providers-3\">\n[{ provide: Logger, useClass: Logger }]\n\n</code-example>\n<p>The expanded provider configuration is an object literal with two properties.</p>\n<ul>\n<li>\n<p>The <code>provide</code> property holds the <a href=\"guide/dependency-injection-providers#token\">token</a>\nthat serves as the key for both locating a dependency value and configuring the injector.</p>\n</li>\n<li>\n<p>The second property is a provider definition object, which tells the injector how to create the dependency value.\nThe provider-definition key can be <code>useClass</code>, as in the example.\nIt can also be <code>useExisting</code>, <code>useValue</code>, or <code>useFactory</code>.\nEach of these keys provides a different type of dependency, as discussed below.</p>\n</li>\n</ul>\n<a id=\"class-provider\"></a>\n<h2 id=\"specifying-an-alternative-class-provider\">Specifying an alternative class provider<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#specifying-an-alternative-class-provider\"><i class=\"material-icons\">link</i></a></h2>\n<p>Different classes can provide the same service.\nFor example, the following code tells the injector to return a <code>BetterLogger</code> instance when the component asks for a logger using the <code>Logger</code> token.</p>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" region=\"providers-4\">\n[{ provide: Logger, useClass: BetterLogger }]\n\n</code-example>\n<a id=\"class-provider-dependencies\"></a>\n<h3 id=\"configuring-class-providers-with-dependencies\">Configuring class providers with dependencies<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#configuring-class-providers-with-dependencies\"><i class=\"material-icons\">link</i></a></h3>\n<p>If the alternative class providers have their own dependencies, specify both providers in the <code>providers</code> metadata property of the parent module or component.</p>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" region=\"providers-5\">\n[ UserService,\n { provide: Logger, useClass: EvenBetterLogger }]\n\n</code-example>\n<p>In this example, <code>EvenBetterLogger</code> displays the user name in the log message.\nThis logger gets the user from an injected <code>UserService</code> instance.</p>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" region=\"EvenBetterLogger\">\n@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a>()\nexport class EvenBetterLogger extends Logger {\n constructor(private userService: UserService) { super(); }\n\n log(message: string) {\n const name = this.userService.user.name;\n super.log(`Message to ${name}: ${message}`);\n }\n}\n\n</code-example>\n<p>The injector needs providers for both this new logging service and its dependent <code>UserService</code>.</p>\n<a id=\"aliased-class-providers\"></a>\n<h3 id=\"aliasing-class-providers\">Aliasing class providers<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#aliasing-class-providers\"><i class=\"material-icons\">link</i></a></h3>\n<p>To alias a class provider, specify the alias and the class provider in the <code>providers</code> array with the <code>useExisting</code> property.</p>\n<p>In the following example, the injector injects the singleton instance of <code>NewLogger</code> when the component asks for either the new or the old logger.\nIn this way, <code>OldLogger</code> is an alias for <code>NewLogger</code>.</p>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" region=\"providers-6b\">\n[ NewLogger,\n // Alias OldLogger w/ reference to NewLogger\n { provide: OldLogger, useExisting: NewLogger}]\n\n</code-example>\n<p>Be sure you don't alias <code>OldLogger</code> to <code>NewLogger</code> with <code>useClass</code>, as this creates two different <code>NewLogger</code> instances.</p>\n<a id=\"provideparent\"></a>\n<h2 id=\"aliasing-a-class-interface\">Aliasing a class interface<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#aliasing-a-class-interface\"><i class=\"material-icons\">link</i></a></h2>\n<p>Generally, writing variations of the same parent alias provider uses <a href=\"guide/dependency-injection-in-action#forwardref\">forwardRef</a> as follows.</p>\n<code-example path=\"dependency-injection-in-action/src/app/parent-finder.component.ts\" region=\"alex-providers\" header=\"dependency-injection-in-action/src/app/parent-finder.component.ts\">\nproviders: [{ provide: Parent, useExisting: <a href=\"api/core/forwardRef\" class=\"code-anchor\">forwardRef</a>(() => AlexComponent) }],\n\n</code-example>\n<p>To streamline your code, you can extract that logic into a helper function using the <code>provideParent()</code> helper function.</p>\n<code-example path=\"dependency-injection-in-action/src/app/parent-finder.component.ts\" region=\"provide-the-parent\" header=\"dependency-injection-in-action/src/app/parent-finder.component.ts\">\n// Helper method to provide the current component instance in the name of a `parentType`.\nexport function provideParent\n (component: any) {\n return { provide: Parent, useExisting: <a href=\"api/core/forwardRef\" class=\"code-anchor\">forwardRef</a>(() => component) };\n }\n\n</code-example>\n<p>Now you can add a parent provider to your components that's easier to read and understand.</p>\n<code-example path=\"dependency-injection-in-action/src/app/parent-finder.component.ts\" region=\"alice-providers\" header=\"dependency-injection-in-action/src/app/parent-finder.component.ts\">\nproviders: [ provideParent(AliceComponent) ]\n\n</code-example>\n<h3 id=\"aliasing-multiple-class-interfaces\">Aliasing multiple class interfaces<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#aliasing-multiple-class-interfaces\"><i class=\"material-icons\">link</i></a></h3>\n<p>To alias multiple parent types, each with its own class interface token, configure <code>provideParent()</code> to accept more arguments.</p>\n<p>Here's a revised version that defaults to <code>parent</code> but also accepts an optional second parameter for a different parent class interface.</p>\n<code-example path=\"dependency-injection-in-action/src/app/parent-finder.component.ts\" region=\"provide-parent\" header=\"dependency-injection-in-action/src/app/parent-finder.component.ts\">\n// Helper method to provide the current component instance in the name of a `parentType`.\n// The `parentType` defaults to `Parent` when omitting the second parameter.\nexport function provideParent\n (component: any, parentType?: any) {\n return { provide: parentType || Parent, useExisting: <a href=\"api/core/forwardRef\" class=\"code-anchor\">forwardRef</a>(() => component) };\n }\n\n</code-example>\n<p>Next, to use <code>provideParent()</code> with a different parent type, provide a second argument, here <code>DifferentParent</code>.</p>\n<code-example path=\"dependency-injection-in-action/src/app/parent-finder.component.ts\" region=\"beth-providers\" header=\"dependency-injection-in-action/src/app/parent-finder.component.ts\">\nproviders: [ provideParent(BethComponent, DifferentParent) ]\n\n</code-example>\n<a id=\"value-provider\"></a>\n<h2 id=\"injecting-an-object\">Injecting an object<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#injecting-an-object\"><i class=\"material-icons\">link</i></a></h2>\n<p>To inject an object, configure the injector with the <code>useValue</code> option.\nThe following provider object uses the <code>useValue</code> key to associate the variable with the <code>Logger</code> token.</p>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" region=\"providers-7\">\n[{ provide: Logger, useValue: SilentLogger }]\n\n</code-example>\n<p>In this example, <code>SilentLogger</code> is an object that fulfills the logger role.</p>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" region=\"silent-logger\">\n// An object in the shape of the logger service\nfunction silentLoggerFn() {}\n\nexport const SilentLogger = {\n logs: ['Silent logger says \"Shhhhh!\". Provided via \"useValue\"'],\n log: silentLoggerFn\n};\n\n</code-example>\n<a id=\"non-class-dependencies\"></a>\n<h3 id=\"injecting-a-configuration-object\">Injecting a configuration object<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#injecting-a-configuration-object\"><i class=\"material-icons\">link</i></a></h3>\n<p>A common use case for object literals is a configuration object.\nThe following configuration object includes the title of the application and the address of a web API endpoint.</p>\n<code-example path=\"dependency-injection/src/app/app.config.ts\" region=\"config\" header=\"src/app/app.config.ts (excerpt)\">\nexport const HERO_DI_CONFIG: AppConfig = {\n apiEndpoint: 'api.heroes.com',\n title: 'Dependency Injection'\n};\n\n\n</code-example>\n<p>To provide and inject the configuration object, specify the object in the <code>@<a href=\"api/core/NgModule\" class=\"code-anchor\">NgModule</a>()</code> <code>providers</code> array.</p>\n<code-example path=\"dependency-injection/src/app/app.module.ts\" region=\"providers\" header=\"src/app/app.module.ts (providers)\">\nproviders: [\n UserService,\n { provide: APP_CONFIG, useValue: HERO_DI_CONFIG }\n],\n\n</code-example>\n<a id=\"injectiontoken\"></a>\n<h3 id=\"using-an-injectiontoken-object\">Using an <code><a href=\"api/core/InjectionToken\" class=\"code-anchor\">InjectionToken</a></code> object<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#using-an-injectiontoken-object\"><i class=\"material-icons\">link</i></a></h3>\n<p>You can define and use an <code><a href=\"api/core/InjectionToken\" class=\"code-anchor\">InjectionToken</a></code> object for choosing a provider token for non-class dependencies.\nThe following example defines a token, <code>APP_CONFIG</code> of the type <code><a href=\"api/core/InjectionToken\" class=\"code-anchor\">InjectionToken</a></code>.</p>\n<code-example path=\"dependency-injection/src/app/app.config.ts\" region=\"token\" header=\"src/app/app.config.ts\">\nimport { <a href=\"api/core/InjectionToken\" class=\"code-anchor\">InjectionToken</a> } from '@angular/core';\n\nexport const APP_CONFIG = new <a href=\"api/core/InjectionToken\" class=\"code-anchor\">InjectionToken</a><AppConfig>('app.config');\n\n</code-example>\n<p>The optional type parameter, <code><AppConfig></code>, and the token description, <code>app.config</code>, specify the token's purpose.</p>\n<p>Next, register the dependency provider in the component using the <code><a href=\"api/core/InjectionToken\" class=\"code-anchor\">InjectionToken</a></code> object of <code>APP_CONFIG</code>.</p>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" header=\"src/app/providers.component.ts\" region=\"providers-9\">\nproviders: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }]\n\n</code-example>\n<p>Now you can inject the configuration object into the constructor with <code>@<a href=\"api/core/Inject\" class=\"code-anchor\">Inject</a>()</code> parameter decorator.</p>\n<code-example path=\"dependency-injection/src/app/app.component.2.ts\" region=\"ctor\" header=\"src/app/app.component.ts\">\nconstructor(@<a href=\"api/core/Inject\" class=\"code-anchor\">Inject</a>(APP_CONFIG) config: AppConfig) {\n this.title = config.title;\n}\n\n</code-example>\n<a id=\"di-and-interfaces\"></a>\n<h4 id=\"interfaces-and-dependency-injection\">Interfaces and dependency injection<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#interfaces-and-dependency-injection\"><i class=\"material-icons\">link</i></a></h4>\n<p>Though the TypeScript <code>AppConfig</code> interface supports typing within the class, the <code>AppConfig</code> interface plays no role in dependency injection.\nIn TypeScript, an interface is a design-time artifact, and doesn't have a runtime representation, or token, that the DI framework can use.</p>\n<p>When the transpiler changes TypeScript to JavaScript, the interface disappears because JavaScript doesn't have interfaces.</p>\n<p>Since there is no interface for Angular to find at runtime, the interface cannot be a token, nor can you inject it.</p>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" region=\"providers-9-interface\">\n// Can't use interface as provider token\n[{ provide: AppConfig, useValue: HERO_DI_CONFIG })]\n\n</code-example>\n<code-example path=\"dependency-injection/src/app/providers.component.ts\" region=\"provider-9-ctor-interface\">\n// Can't inject using the interface as the parameter type\nconstructor(private config: AppConfig){ }\n\n</code-example>\n<a id=\"factory-provider\"></a>\n<a id=\"factory-providers\"></a>\n<h2 id=\"using-factory-providers\">Using factory providers<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dependency-injection-providers#using-factory-providers\"><i class=\"material-icons\">link</i></a></h2>\n<p>To create a changeable, dependent value based on information unavailable before run time, you can use a factory provider.</p>\n<p>In the following example, only authorized users should see secret heroes in the <code>HeroService</code>.\nAuthorization can change during the course of a single application session, as when a different user logs in .</p>\n<p>To keep security-sensitive information in <code>UserService</code> and out of <code>HeroService</code>, give the <code>HeroService</code> constructor a boolean flag to control display of secret heroes.</p>\n<code-example path=\"dependency-injection/src/app/heroes/hero.service.ts\" region=\"internals\" header=\"src/app/heroes/hero.service.ts (excerpt)\">\nconstructor(\n private logger: Logger,\n private isAuthorized: boolean) { }\n\ngetHeroes() {\n const auth = this.isAuthorized ? 'authorized ' : 'unauthorized';\n this.logger.log(`Getting heroes for ${auth} user.`);\n return HEROES.filter(hero => this.isAuthorized || !hero.isSecret);\n}\n\n</code-example>\n<p>To implement the <code>isAuthorized</code> flag, use a factory provider to create a new logger instance for <code>HeroService</code>.</p>\n<code-example path=\"dependency-injection/src/app/heroes/hero.service.provider.ts\" region=\"factory\" header=\"src/app/heroes/hero.service.provider.ts (excerpt)\">\nconst heroServiceFactory = (logger: Logger, userService: UserService) => {\n return new HeroService(logger, userService.user.isAuthorized);\n};\n\n</code-example>\n<p>The factory function has access to <code>UserService</code>.\nYou inject both <code>Logger</code> and <code>UserService</code> into the factory provider so the injector can pass them along to the factory function.</p>\n<code-example path=\"dependency-injection/src/app/heroes/hero.service.provider.ts\" region=\"provider\" header=\"src/app/heroes/hero.service.provider.ts (excerpt)\">\nexport let heroServiceProvider =\n { provide: HeroService,\n useFactory: heroServiceFactory,\n deps: [Logger, UserService]\n };\n\n</code-example>\n<ul>\n<li>\n<p>The <code>useFactory</code> field specifies that the provider is a factory function whose implementation is <code>heroServiceFactory</code>.</p>\n</li>\n<li>\n<p>The <code>deps</code> property is an array of <a href=\"guide/dependency-injection-providers#token\">provider tokens</a>.\nThe <code>Logger</code> and <code>UserService</code> classes serve as tokens for their own class providers.\nThe injector resolves these tokens and injects the corresponding services into the matching <code>heroServiceFactory</code> factory function parameters.</p>\n</li>\n</ul>\n<p>Capturing the factory provider in the exported variable, <code>heroServiceProvider</code>, makes the factory provider reusable.</p>\n<p>The following side-by-side example shows how <code>heroServiceProvider</code> replaces <code>HeroService</code> in the <code>providers</code> array.</p>\n<code-tabs>\n\n <code-pane header=\"src/app/heroes/heroes.component (v3)\" path=\"dependency-injection/src/app/heroes/heroes.component.ts\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a> } from '@angular/core';\nimport { heroServiceProvider } from './hero.service.provider';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-heroes',\n providers: [ heroServiceProvider ],\n template: `\n <h2>Heroes</h2>\n <app-hero-list></app-hero-list>\n `\n})\nexport class HeroesComponent { }\n\n\n</code-pane>\n\n <code-pane header=\"src/app/heroes/heroes.component (v2)\" path=\"dependency-injection/src/app/heroes/heroes.component.1.ts\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a> } from '@angular/core';\n\nimport { HeroService } from './hero.service';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-heroes',\n providers: [ HeroService ],\n template: `\n <h2>Heroes</h2>\n <app-hero-list></app-hero-list>\n `\n})\nexport class HeroesComponent { }\n\n\n</code-pane>\n\n</code-tabs>\n\n \n</div>\n\n<!-- links to this doc:\n - api/core/Injector\n - api/core/StaticProvider\n - guide/dependency-injection\n - guide/dependency-injection-in-action\n - guide/hierarchical-dependency-injection\n - guide/providers\n - guide/upgrade\n-->\n<!-- links from this doc:\n - api/core/Component\n - api/core/Inject\n - api/core/Injectable\n - api/core/InjectionToken\n - api/core/NgModule\n - api/core/Provider\n - api/core/forwardRef\n - guide/dependency-injection-in-action#forwardref\n - guide/dependency-injection-providers#aliasing-a-class-interface\n - guide/dependency-injection-providers#aliasing-class-providers\n - guide/dependency-injection-providers#aliasing-multiple-class-interfaces\n - guide/dependency-injection-providers#configuring-class-providers-with-dependencies\n - guide/dependency-injection-providers#defining-providers\n - guide/dependency-injection-providers#dependency-injection-tokens\n - guide/dependency-injection-providers#dependency-providers\n - guide/dependency-injection-providers#injecting-a-configuration-object\n - guide/dependency-injection-providers#injecting-an-object\n - guide/dependency-injection-providers#interfaces-and-dependency-injection\n - guide/dependency-injection-providers#specifying-a-provider-token\n - guide/dependency-injection-providers#specifying-an-alternative-class-provider\n - guide/dependency-injection-providers#token\n - guide/dependency-injection-providers#using-an-injectiontoken-object\n - guide/dependency-injection-providers#using-factory-providers\n - guide/glossary#di-token\n - guide/glossary#injector\n - guide/glossary#provider\n - https://github.com/angular/angular/edit/master/aio/content/guide/dependency-injection-providers.md?message=docs%3A%20describe%20your%20change...\n-->"
|
|
} |