Angular 2 -注入由HTML选择器创建的组件

Angular 2 - Injecting a component created by a HTML selector

本文关键字:选择器 创建 组件 HTML 注入 Angular      更新时间:2023-09-26

我试图访问一个组件,已创建使用一些HTML中的选择器。我有一个印象(似乎是错误的),提供者会寻找一个现有的实例,并在注入到另一个组件时提供它,但显然我误解了分层提供程序的创建过程。

在下面,我有一个组件,它使用模板HTML中的选择器来创建一个TopLevelComponent的实例。

我试图通过创建一个提供程序并使用DI来通过构造函数推送该实例来访问该TopLevelComponent。

(抱歉,如果这段代码不完美,我只是把一个快速的例子放在一起。)

@component({
    selector: 'my-app',
    template: '<top-level-component></top-level-component>',
    directives: [TopLevelComponent],
    providers: [TopLevelComponent],
})
export class MyApp {
    constructor( private topLevelComponent: TopLevelComponent) {
    }
}
@component({
    selector: 'top-level-component',
    template: '',
})
export class TopLevelComponent {
    constructor() {
        console.log('CONSTRUCTED A TopLevelComponent...');
    }
}

但是,而不是得到一个实例的TopLevelComponent传递给我的组件,我得到两个(如证明的两个日志' construct A TopLevelComponent…

如果我从构造函数中删除'private topLevelComponent: topLevelComponent ',我只得到该组件的一个实例,但我似乎无法得到这个

我有两个问题

  • 如何使用DI将选择器创建的组件的实例传递给其他组件的构造函数

  • 如果我不包括<top-level-component></top-level-component>在应用程序的HTML,我怎么能注入到应用程序的HTML,使它正确呈现?

和第三个

  • 如果以上两种方法都可行,建议采用哪种方法?

我认为@ViewChild将是正确的方法,因为将(!)只有这个组件的一个实例,但由于它被注入到许多不同的组件,我不认为这是可能的。

如果您将组件添加到providers: [...],则该组件将被视为普通类。如果DI在请求TopLevelComponent时找到了这样的提供商,它会创建一个组件类的实例,@Component(...)装饰器被忽略。

如果一个组件被列在directives: [...]中,如果它们因为匹配的选择器而被实例化了,那么DI会把它们作为组件和指令来查找。

  <component-to-inject #source></component-to-inject>
  <component-to-receive [injectedComponent]="source"></component-to-receive>

export class ReceivingComponent { 
  @Input() injectedComponent: InjectingComponent;
  ngOnInit() {
    console.log(this.injectedComponent);
  }      
}

为了获得对模板中存在的组件的引用,你可以使用@ViewChild注释。

@ViewChild(TopLevelComponent)
private myTopLevelComponent:TopLevelComponent

这会给你angular在相应模板中找到的第一个TopLevelComponent实例。

如果你有多个相同类型的组件,但你想找到一个特定的组件,你可以使用本地模板变量。

@ViewChild('templateVariableName')
private myTopLevelComponent:TopLevelComponent

你的HTML模板需要看起来像这样:

<top-level-component #templateVariableName></top-level-component>

最后:如果你想找到所有相同类型的组件,你可以使用@ViewChildren注释。

@ViewChildren(TopLevelComponent)
private topLevelComponents:QueryList<TopLevelComponent>

这将给你一个模板中所有TopLevelComponents的列表。

为什么在您的示例中创建两个实例?

使用providers数组并请求将该类注入到你的构造函数中,会告诉angular创建一个你的组件类的实例。第二个实例是在angular解析你的模板时创建的。

请注意,通过构造函数注入的实例与模板中存在的实例是不同的。你对注入实例所做的任何更改都不会反映在屏幕上。

要获得正确的实例,需要遵循上面提供的步骤。

angular2在providers中传递服务列表。服务是可重用的代码片段。

基本服务示例,可用于任何指令/组件。

imports ...
    @Injectable()
    export class MyEmpService {
        getAllEmployees() {
            // hit database
            // return employee list
        }
        getEmp(id: number) {
            // hit database
            // return employee data 
        }
}

Component是一个带视图的指令。Angular2在指令中传递组件列表。列表中的任何组件都可以在组件中使用。同样,它是可重用的代码,但有视图。简单的例子:EmployeeComponent.ts

imports...
@Component({
    selector: 'my-emp',
    template: `
        <button (click)="getEmpList()">Get All Emp</button>
        <button (click)="getEmp(2)">Get Emp</button>
        <div>
            {{result | json}}
        </div>
    `,
    providers: [MyEmpService]
})
export class EmployeeComponent{
    private result:any = '';
    constructor(private myEmpService: MyEmpService) { }
    getEmpList(){
        this.result = myEmpService.getAllEmployees();
    }
    getEmp(id: number){
        this.result = myEmpService.getEmp(id);
    }
}

AppComponent.ts

imports...
@Component({
    selector: 'my-app',
    template: `
        <h1>Main Component</h1>
        <my-emp></my-emp>
    `,
    directives: [EmployeeComponent]
})
export class AppComponent{ }