angular2 如何使用来自不同文件的 ng-template?当我将 ng-template 放在我使用的相同 HTML 中时,它可以工作,但是当我将 ng-template 移到一个单独的文件中时,它就不会工作。有没有办法将 ng-template 移动到它自己的文件中并在不同的 html 文件中使用它?
info-message.html
<ng-template #messageTemplate>
Hi
</ng-template>
<ng-container *ngTemplateOutlet="messageTemplate;"></ng-container>
上面的工作正常,因为 ng-template 和用法在同一个文件中
message-template.html
<ng-template #messageTemplate>
Hi
</ng-template>
info-message.html
<ng-container *ngTemplateOutlet="messageTemplate;"></ng-container>
这是行不通的。有没有办法使用 "messageTemplate",它位于另一个 html 中的单独文件中(例如:info-message.html)
提前致谢。
最佳答案
此行为可以通过“门户”实现。这是 Angular 应用程序中有用且相当常见的模式。例如,您可能有一个位于顶部应用程序级别附近的全局侧边栏 socket ,然后子组件可以指定本地 <ng-template/>
,作为其整体模板的一部分,将在此位置呈现。
请注意,虽然 <ng-template/>
可以在定义所需导出的文件之外定义,仍然需要放置 <ng-template/>
在 some 组件的模板中。这可以是一个极简主义的组件,它只负责包装 <ng-template/>
,但是它同样可以是一个复杂的组件,其中 <ng-template/>
兴趣只占很小一部分。
此代码说明了一种可能的门户基本实现方式。
@Directive({
selector: '[appPortal]'
})
export class PortalDirective implements AfterViewInit {
@Input() outlet: string;
constructor(private portalService: PortalService, private templateRef: TemplateRef<any>) {}
ngAfterViewInit(): void {
const outlet: PortalOutletDirective = this.portalService.outlets[this.outlet];
outlet.viewContainerRef.clear();
outlet.viewContainerRef.createEmbeddedView(this.templateRef);
}
}
@Directive({
selector: '[appPortalOutlet]'
})
export class PortalOutletDirective implements OnInit {
@Input() appPortalOutlet: string;
constructor(private portalService: PortalService, public viewContainerRef: ViewContainerRef) {}
ngOnInit(): void {
this.portalService.registerOutlet(this);
}
}
@Injectable({
providedIn: 'root'
})
export class PortalService {
outlets = new Map<string, PortalOutletDirective>();
registerOutlet(outlet: PortalOutletDirective) {
this.outlets[outlet.appPortalOutlet] = outlet;
}
}
它使用三个部分工作:
- “门户”指令。这取决于所需的
<ng-template/>
并将应呈现内容的 channel 名称作为输入。 - “门户网站”指令。这存在于 socket 上,例如一个
<ng-container/>
, 并定义导出。 - “门户”服务。这是在根级别提供的,并存储对门户网点的引用,以便门户可以访问它们。
对于非常简单的事情来说,这似乎需要做很多工作,但是一旦管道就位,就很容易(重新)使用。
<div class="container">
<div class="row">
<div class="col-6">
<app-foo></app-foo>
</div>
<div class="col-6">
<ng-container [appPortalOutlet]="'RightPanel'"></ng-container>
</div>
</div>
</div>
// foo.component.html
<h1>Foo</h1>
<ng-template appPortal [outlet]="'RightPanel'">
<h1>RIGHT</h1>
</ng-template>
一般来说,重新发明轮子并不是一个好主意,尽管已经有经过良好测试、记录在案且稳定的实现可用。 Angular CDK提供 such an implementation我建议在实践中使用那个而不是你自己的。
关于angular2 ng-template 在一个单独的文件中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49404822/