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

时间:2016-08-08 17:18:30

标签: javascript html angular typescript

我正在尝试访问在某些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的一个实例传递给我的组件,而是获得两个(由调试日志中存在的'CONSTRUCTED A TopLevelComponent ...'的两个日志证明)。

如果我从构造函数中删除'private topLevelComponent:TopLevelComponent',我只获得该组件的一个实例,但我似乎无法掌握它。

所以我有两个问题

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

  • 如果我在应用HTML中不包含<top-level-component></top-level-component>,我该如何将HTML注入应用以便正确呈现?

还有第三个

  • 如果以上两种方法都可以,这是推荐的方法吗?

我在想@ViewChild是正确的方法,因为(!)只会是这个组件的一个实例,但是因为它注入了许多不同的组件,我认为这是不可能的。

3 个答案:

答案 0 :(得分:2)

如果将组件添加到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);
  }      
}

答案 1 :(得分:1)

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

@ViewChild(TopLevelComponent)
private myTopLevelComponent:TopLevelComponent

这将为您提供角度在相应模板中找到的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解析您的模板时,会创建第二个实例。

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

要获得正确的实例,您需要按照我上面提供的步骤进行操作。

答案 2 :(得分:0)

angular2传递提供程序中的服务列表。服务是可重复使用的代码段。

可在任何指令/组件中使用的基本服务示例。

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{ }