我有一个具有各种类型搜索的应用程序 - 但是这些搜索之间的许多功能是相同的,另外除了几个字符串(面板标题等)之外,视图几乎相同。
我有一个基本的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()发回结果?这听起来太复杂了。
答案 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教程,他们可能会比我更好地解释它。