Tl;dr:我如何提供一个可见组件作为指令的依赖项?自然,组件必须在指令之前进行初始化,但它必须与应用程序稍后在selector
组件上运行时显示的实例相同。
细节:
我的 app.component.html 的结构如下:
app.component.html
<app-navigation></app-navigation>
<router-outlet></router-outlet>
顶部有一个导航栏,始终可见。<router-outlet>
始终显示当前活动的组件。
我现在想允许在 中呈现的组件<router-outlet>
修改导航栏的内容,例如显示适合当前活动组件的附加按钮。这应该与指令一起使用,如下所示:
some.component.html
<div *appTopBar>
<button>Additional Button</button>
</div>
附加按钮现在应该出现在顶部的导航栏中。
该appTopBar
指令如下所示:
顶栏.directive.ts
import {AfterViewInit, Directive, OnDestroy, TemplateRef} from '@angular/core';
import {AppComponent} from '../navigation/navigation.component';
@Directive({
selector: '[appTopBar]'
})
export class TopBarDirective implements AfterViewInit, OnDestroy {
constructor(private tmpl: TemplateRef<any>,
private nav: NavigationComponent) {
}
ngAfterViewInit(): void {
this.nav.setTopBarContent(this.tmpl);
}
ngOnDestroy(): void {
this.nav.setTopBarContent(null);
}
}
该指令依赖于 NavigationComponent 并且可以通过公开提供的方法将内容传递给导航栏setTopBarContent()
:
导航.component.ts
import {Component, EmbeddedViewRef, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
@Component({
selector: 'app-navigation',
templateUrl: './navigation.component.html',
styleUrls: ['./navigation.component.scss']
})
export class NavigationComponent {
@ViewChild('topBarContainer',{static: false})
topBar: ViewContainerRef;
topBarContent: EmbeddedViewRef<any>;
constructor() {}
/**
* Set the template to be shown in the top bar
* @param tmpl template, null clears the content
*/
public setTopBarContent(tmpl: TemplateRef<any>) {
if (this.topBarContent) {
this.topBarContent.destroy();
}
if (tmpl) {
this.topBarContent = this.topBar.createEmbeddedView(tmpl);
}
}
}
我遇到的第一个问题是,在NavigationComponent
初始化 TopBarDirective 时,依赖项还不可用。我收到以下错误:
错误错误:未捕获(承诺):NullInjectorError:
StaticInjectorError(AppModule)[TopBarDirective -> NavigationComponent]: StaticInjectorError(Platform: core)[TopBarDirective -> NavigationComponent]:
NullInjectorError:没有导航组件的提供者!
所以显然组件在指令之后被初始化并且还不可用。
我尝试将其添加NavigationComponent
到providers
数组中,AppComponent
并且依赖注入现在起作用了:
@NgModule({
declarations: [
NavigationComponent,
SomeComponent,
TopBarDirective
],
imports: [
BrowserModule,
CommonModule
],
providers: [NavigationComponent]
})
export class AppModule { }
但是,现在似乎有两个 NavigationComponent 实例。我通过在其中生成一个随机数并记录它constructor
来检查这一点。NavigationComponent
该指令肯定有一个与<app-navigation>
选择器上显示的实例不同的实例。
现在我知道这种模式以某种方式起作用。前段时间我发现它是由一些 Angular 开发人员介绍的,但不幸的是我不再有源代码了。但是,工作版本显示 中的内容AppComponent
,因此该指令仅具有对 的依赖AppComponent
项,这似乎首先被初始化。因此,不会发生整个依赖性问题。
如何确保NavigationComponent
提供给 的 TopBarDirective
实例与选择器中显示的实例相同<app-navigation>
?