我一直在经历"英雄"官方Angular 2页面上的教程,当我开始路由时,有些事情没有意义。它是关于提供者的。
有问题的部分表示如下。我的主要组件如下所示:
/* app.components */
import {Component} from 'angular2/core';
import {HeroesComponent} from './heroes.component';
import {HeroService} from './hero.service';
@Component({
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<my-heroes></my-heroes>
`
directives: [HeroesComponent],
providers: [HeroService]
})
export class AppComponent {
title = 'Tour of Heroes';
constructor(private _heroService: HeroService) {}
}
并且英雄组件看起来像这样:
/* heroes.component */
import {Component} from 'angular2/core';
import {Hero} from './hero';
import {HeroDetailComponent} from './hero-detail.component';
import {HeroService} from './hero.service';
import {OnInit} from 'angular2/core';
@Component({
selector: 'my-heroes',
directives: [HeroDetailComponent],
template: `
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="#hero of heroes" [class.selected] = "hero === selectedHero" (click)="onSelect(hero)">
<span class="badge"> {{hero.id}} </span> {{hero.name}}
</li>
</ul>
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
`
})
export class HeroesComponent implements OnInit {
heroes: Hero[];
selectedHero: Hero;
ngOnInit() {
this.getHeroes();
}
constructor(private _heroService: HeroService) { }
getHeroes() {
this._heroService.getHeroes().then(heroes => this.heroes = heroes);
}
onSelect(hero: Hero) {
this.selectedHero = hero;
}
}
好的,我的问题是:为了实现这一点,我需要在两个文件中导入import {HeroService} from './hero.service';
。但是,providers: [HeroService]
只是@Component
app.components
的一部分。我不需要在heroes.component
中编写这段代码。 heroes.component
如何知道选择哪个提供商?它是继承自app.components
吗?如果是这样,为什么我必须在两个文件中都写这个:import {HeroService} from './hero.service';
?为什么不在app.components
?这两个类也具有相同的constructor
。我不知道这里发生了什么,所以提前感谢任何解释。
答案 0 :(得分:0)
注射器是分层的。在bootstrap()
中初始化根提供程序,然后为每个组件创建另一个子注入器,从而生成一个模仿DOM中组件的结构。
当Angular实例化一个类(服务,组件,管道......)时,它会请求一个DI实例,DI也会尝试解析构造函数参数。这是递归完成的,直到不需要进一步的依赖来解析,然后返回实例。
从最近的注射器请求实例。如果注射器没有类型的提供者(或其他键,如字符串或OpaqueToken
),请求将被转发到父注射器,直到找到提供者或达到根注射器。
有关详细信息,请参阅https://angular.io/docs/ts/latest/api/core/Directive-decorator.html
答案 1 :(得分:0)
这与Angular2的“分层注入器”功能相关联。这些注射器链接到组件并遵循相同的树。
子组件的注入器是父组件的子注入器。如果未在当前注入器中找到提供者,则会将其查找到父提供者...
有关详细信息,请参阅此问题:
答案 2 :(得分:0)
是的,它是继承的,注入器是分层的。查看此博客post和官方documentation。
答案 3 :(得分:0)
在研究了 Angular-2 的一些文档后,我分享了我对dependency-injection and providers
的了解,这些知识可以帮助某些人。
依赖注入是分层的 依赖注入是一种重要的应用程序设计模式。 Angular有自己的依赖注入框架,如果没有它,我们真的无法构建一个Angular应用程序。
依赖关系是注入器范围内的单例。在我们的示例中,HeroService
及其AppComponent
个孩子共享了一个HeroComponent
个实例。
在您的示例中,AppComponent
是“英雄”功能区域的根组件。它管理该区域的所有子组件。您的HeroService
可能会公开一个返回英雄数据的getHeroes
方法,但其消费者都不需要知道这一点。
服务只不过是Angular 2中的一个类。它仍然存在 只有一个类,直到我们用Angular注册它 喷射器。
这就是配置进样器的原因。我们不必创建Angular注入器。 Angular在引导过程中为我们创建了一个应用程序范围的注入器。我们必须通过注册创建应用程序所需服务的提供程序来配置注入器。我们可以在引导期间注册提供程序。像:
bootstrap(AppComponent,
[HeroService]); // DISCOURAGED (but works)
注射器现在知道我们的HeroService
。我们HeroService
的一个实例将可用于整个应用程序的注入。
首选方法是在应用程序组件中注册应用程序提供程序。因为HeroService
用于英雄功能区域 - 而不是其他地方 - 注册它的理想位置是在顶层HeroesComponent
。
在组件中注册提供商
providers:[HeroService], // in your app.component that registers the HeroService
仔细查看providers
元数据的@Component
部分。
HeroService
的一个实例现在可用于注入AppComponent
及其所有子组件。
AppComponent
本身并不需要HeroService。但 它的孩子HeroComponent
。
专注于构造函数
向构造函数添加参数。
constructor(private _heroService: HeroService) {
this._heroService.getHeroes().then(heroes => this.heroes = heroes); // or you can use in OnInit
}
N.B:可能无需在constructor
appComponent
我们正在使用TypeScript编写,并使用参数名称 类型注释
:HeroService
。该课程也装饰有@Component
装饰者。当TypeScript编译器评估此类时,它会看到
@Component
装饰器并将类元数据添加到生成的内容中 JavaScript代码。在那个元数据中隐藏着那些信息 将heroService
参数与HeroService
类相关联。Angular注入器如何知道注入一个实例
时HeroService
创建新HeroComponent
。
依赖注入的更多细节可以看this link
和层次依赖注入可以看到this link