【问题标题】:Angular2 - ContentChild query does not find nested componentsAngular2 - ContentChild 查询找不到嵌套组件
【发布时间】:2016-10-29 20:15:52
【问题描述】:

我正在尝试设置一个 Angular2 组件,该组件自动聚焦通过内容投影插入的输入元素。

我使用的解决方案基于this answer。我还有一个额外的要求,即输入元素可能嵌套在另一个组件中。但是,我发现ContentChild 查询无法检测到深埋在ng-content 标签内的元素。

@Component({
  selector: 'inner-feature',
  template: "<input auto-focus>",
  directives: [AutoFocus]
})
export class InnerFeature { }

@Component({
  selector: 'feature',
  template: `
    <div [class.hide]="!show">
      <ng-content></ng-content>
    </div>
  `
})
export class Feature {
  @ContentChild(AutoFocus)
  private _autoFocus: AutoFocus;

  private _show: boolean = false;

  @Input()
  get show() {
    return this._show;
  }
  set show(show: boolean) {
    this._show = show;
    if (show && this._autoFocus) {
      setTimeout(() => this._autoFocus.focus());
    }
  }
}

@Component({
  selector: 'my-app',
  template: `
    <div>
      <button (click)="toggleFeature()">Toggle</button>
      <feature [show]="showFeature">
        <inner-feature></inner-feature>
      </feature>
    </div>
  `,
  directives: [Feature, InnerFeature]
})
export class App {
  showFeature: boolean = false;

  toggleFeature() {
    this.showFeature = !this.showFeature;
  }
}

_autoFocus 属性永远不会被填充。相比之下,auto-focus 指令没有嵌套在另一个组件中并且工作正常。有没有办法让这个工作?

(我没有粘贴AutoFocus 的代码,因为它对这个示例并不重要。)

请参阅Plunker 以获取演示。

更新上面的代码来修复缺失的指令。

【问题讨论】:

  • 似乎不支持。 ViewQuery(已弃用)支持 descendants: true,但其他类似(未弃用的功能似乎不支持。
  • 这很不幸。这个问题有不同的解决方案吗?本质上,我需要一个通用的模态组件,其主体可以是另一个共享组件(例如用于添加和编辑项目的通用表单),并且我想在显示模态时自动聚焦第一个元素。
  • 我猜github.com/angular/angular/issues/8563 会让这更容易。除此之外我没有任何想法。

标签: typescript angular


【解决方案1】:

使用ContentChildren 并将descendants 设置为true

@ContentChildren(AutoFocus, { descendants: true })

【讨论】:

【解决方案2】:

实际上我想在这个问题上投入更多时间来找到更好的解决方案,但现在我想出了以下可能已经对你有所帮助的方法:

首先,您必须使用@ViewChild 公开InnerFeatures 中的AutoFocus(并且您忘记将AutoFocus 添加到directives 数组中)。这可能如下所示:

@Component({
  selector: 'inner-feature',
  template: "<input auto-focus>",
  directives: [AutoFocus]
})
export class InnerFeature {
  @ViewChild(AutoFocus)
  autoFocus:AutoFocus;
}

然后在您的父组件Feature 中,您可以使用@ContentChildren,它返回绑定组件的QueryList(在您的情况下为InnerFeature)。

在您的show 方法中(或例如在ngAfterContentInit 中或之后),您可以访问此InnerFeatures 列表:

export class Feature implements OnInit {
  @ContentChild(AutoFocus)
  private _autoFocus: AutoFocus;

  @ContentChildren(InnerFeature)
  private _innerFeatures: QueryList<InnerFeature>;

  private _show: boolean = false;

  @Input()
  get show() {
    return this._show;
  }
  set show(show: boolean) {
    this._show = show;
    if (show) {
      setTimeout(() => {
            if (this._autoFocus) {
                this._autoFocus.focus();
            }
            if (this._innerFeatures) {
                this._innerFeatures.map((innerFeature) => {
                    innerFeature.autoFocus.focus();
                });
            }
        });
    }
  }

  ngAfterContentInit() {
    console.log(this._autoFocus);
    console.log(this._innerFeatures);
  }
}

我修改了你的plunker,所以你可以在实际中测试它。

可能不像你想要的那样充满活力,但是,我希望它无论如何都会有所帮助。

如果在英格兰与岛屿的比赛之后没有更好的答案,我会尝试提出更好的方法;)

更新:我更新了我的代码,因为它在访问私有的_results 时抛出了错误。使用map() 代替QueryList

【讨论】:

  • 谢谢。这很有帮助,但就像你说的那样,不像我想要的那样充满活力。我不想Feature 必须知道InnerFeatures,因为可能有几个。我会在比赛结束后等待你的答复。 :)
  • 我考虑了一下。我认为与其弄清楚如何从父组件的所有(未知)和可能深度嵌套的子组件中访问AutoFocus 的所有实例,不如从另一个方向解决问题可能更有意义。例如,您可以使用服务作为指令和父组件之间的桥梁另一种方法可能是使用从Feature 触发的事件。
猜你喜欢
  • 2017-03-09
  • 1970-01-01
  • 2016-03-01
  • 1970-01-01
  • 2017-07-29
  • 2018-06-13
  • 1970-01-01
  • 2018-06-13
相关资源
最近更新 更多