@ViewChild:访问孙子方法

@ViewChild: access grand-child methods

我有三个嵌套组件,分别称为 level0level1level2,定义如下:

@Component({
selector: 'level2',
template: `<div>I am level 2</div>`,
})
export class Level2 {
  getName(){
    return "my name is 'TWO'";
  }
}

@Component({
selector: 'level1',
template: `<div>I am level 1<level2></level2></div>`,
directives: [Level2]
})
export class Level1 {
  getName(){
    return "my name is 'ONE'";
  }
}

@Component({
selector: 'level0',
template: `<div>I am level 0<level1></level1></div>`,
directives: [Level1,Level2]
})
export class App {
@ViewChild(Level1) level1:Level1;
@ViewChild(Level2) level2:Level2;
ngAfterViewInit() {
  if(this.level1){var name1 = this.level1.getName();}
  if(this.level2){var name2 = this.level2.getName();}
  console.log("name1",name1);
  console.log("name2",name2);
  }
}

在控制台中,我希望看到:

name1 my name is 'ONE'
name2 my name is 'TWO'

但我看到的是:

name1 my name is 'ONE'
name2 undefined

我错过了什么?为什么 Level0 组件无法通过 @ViewChild 访问 Level2

有没有办法访问 Level0 中的 Level2 方法?


Here is the plnkr

我认为目前这不可能。

ViewQueryMetadata API doc 表示如下:

Supports the same querying parameters as QueryMetadata, except descendants.

QueryMetadata API doc有这个后代例子:

Configure whether query looks for direct children or all descendants of the querying element, by using the descendants parameter. It is set to false by default.

... code here not shown ...

When querying for items, the first container will see only a and b by default, but with Query(TextDirective, {descendants: true}) it will see c too.

如果在嵌套组件的每一层都使用 ViewChild 就可以实现,就像这样:

// Level 2
@Component({
selector: 'level2',
template: `<div>I am level 2</div>`,
})
export class Level2 {
  getName(){
    return "my name is 'TWO'";
  }
}


// Level 1
@Component({
selector: 'level1',
template: `<div>I am level 1<level2></level2></div>`,
directives: [Level2]
})
export class Level1 {
  @ViewChild(Level2) level2:Level2;
  getName(){
    return "my name is 'ONE'";
  }

  // You need to add additional function that would be called from level 1
  calledFromLevel1() {
    return this.level2.getName();
  }
}


// Level 0
@Component({
selector: 'level0',
template: `<div>I am level 0<level1></level1></div>`,
directives: [Level1,Level2]
})
export class App {
@ViewChild(Level1) level1:Level1;
ngAfterViewInit() {
  if(this.level1) {
    var name1 = this.level1.getName();
    var name2 = this.level1.calledFromLevel1();
  }
  console.log("name1",name1);
  console.log("name2",name2);
  }
}