子组件和DI上下文

时间:2017-12-05 00:52:44

标签: angular

我有一个具有各种类型搜索的应用程序 - 但是这些搜索之间的许多功能是相同的,另外除了几个字符串(面板标题等)之外,视图几乎相同。

我有一个基本的SearchComponent和一个Specialized搜索组件。 Specialized搜索组件在标记中实例化基本SearchComponent并设置适当的输入。

每个专业搜索组件使用不同的搜索策略,即服务实例和方法以及结果的映射。

目前,我在实例化基本组件时绑定了对父项的函数引用,以便可以调用父函数。然而,看起来DI上下文是不同的,所以它抱怨我找不到我在父母中注入的服务。

我该如何解决这个问题?

示例:

在search-base.ts中:

  @Input() execSearchFn: (query) => Observable<any>;
  @Input() mapTableDataFn: (i: any) => any;

executeSearch(e) {  // Triggered by some event
  this.execSearchFn(e.query);  // delegate to parent for specialized search
}

在xyz-search.html中:

   <app-search-base #appSearchBase
    searchTitle="XYZ Search"
    [execSearchFn]="execSearch"
    [mapTableDataFn]="mapTableData">
  </app-search-base>

在xyz-search.ts中:

constructor(private xyzService: XYZService) {}

execSearch(query: string) {
 return this.xyzService.search(query);  // does not work! xyzService is undefined!
}

这样可以正常工作,调用父项中的函数,但找不到任何注入的属性。

错误是“无法读取未定义的属性搜索”。果然xyzService在构造函数中注入并定义,但因为调用上下文来自基本组件,所以它在execSearch函数中是未定义的。

我的目标功能类似于在基类中定义抽象方法,以及定义该抽象方法的确切行为的子类。但是Angular不允许抽象组件,因此必须使用上述解决方法。事实上我可以创建一个常规的抽象基类,但我不能重新使用标记。我需要重用基本功能和基本标记。

我猜这样做的最好方法是发出一个执行事件(而不是使用函数引用),然后通过Input()发回结果?这听起来太复杂了。

1 个答案:

答案 0 :(得分:1)

这很难理解。只是为了说明我做对了:你正试图让一个子组件(这里是搜索库)执行一个动作,并希望在父组件(这里是你的xyz-search)中对它做出反应。 / p>

这通常是output绑定函数的一个很好的例子。您当前正在提供一个函数作为输入变量,为您的子组件提供代码,而不是将调用作为其输出发出。这是一种肮脏的方式,它有限制。你找到了一个,因为只是给代码会失去上下文。

所以这就是我要做的。我将您的功能从输入更改为输出,这可以通过几个简单的步骤完成。这是父组件。

<app-search-base #appSearchBase
    searchTitle="XYZ Search"
    (onExecSearch)="execSearch($event)"
    [mapTableDataFn]="mapTableData">
 </app-search-base>

我们只需要使用括号,并在此处使用$ event参数调用父execSearch函数(这是至关重要的,所以不要忘记)。括号将绑定类型从input更改为output。我将子函数重命名为onExecSearch,以便在发生某些事情时更清楚地调用它。

现在在子组件中,我们必须通过输出事件发射器使用给定的输出函数。如果你想这样称呼它,这是一个常见的角度模式。

@Output() onExecSearch: new EventEmitter<string>();

executeSearch(e) {   
  this.onExecSearch.emit(e.query); 
}

我们可以通过在onExecSearch发射器上发出正确类型的值来调用父项的提供输出函数。您的父execSearch函数绑定到发射器,因此在onExecSearch调用其emit函数时调用它,但这样它将使用正确的上下文执行

  

子组件公开了一个EventEmitter属性   当事情发生时发出事件。父母绑定到该事件   财产并对这些事件作出反应。

您的XYZ-search.ts甚至无法更改,它应该被正确调用。

有关详细信息,请查看this教程,他们可能会比我更好地解释它。