angular2 ng-template 在一个单独的文件中

标签 angular typescript ng-template

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/

相关文章:

angular - angular2中如何动态添加克隆节点(相当于cloneNode)

angular - PrimeNG Accordion 中的 ng 模板问题

node.js - 多个类型的函数返回值不存在属性

typescript - 如何使函数尊重 typescript 中的接口(interface)

angular - 以 Angular react 形式动态设置文本区域禁用

Angular Material 2 - "Error retrieving icon: undefined"

typescript - SystemJS 没有用 JS 文件替换 TS 文件?

另一个 ng 模板中的 Angular 4 ng 模板不起作用

angular - Angular 2 提前编译中的未知编译器选项 'angularCompilerOptions'

angular - 为什么使用 golang 从 csv 文件读取 "O' max"string 时存在差异?