Angular 2-包装组件子代

问题描述:

我正在尝试制作一个可重用的tab组件,但对如何在组件中的多个ContentChildren(已更正)上进行迭代以将它们包装在html中感到困惑.

I'm attempting to make a reusable tab component and am confused about how to iterate over multiple ContentChildren (corrected) within the component to wrap them in html.

我的视线中有一个组件

<demo-tabs>
  <a routerLink="/some/link">Tab 1</a>
  <a routerLink="/some/other/link">Tab 2</a>
  <a routerLink="/some/third/link">Tab 3</a>
</demo-tabs>

我想这样渲染:

<ul>
  <li><a routerLink="/some/link">Tab 1</a></li>
  <li><a routerLink="/some/other/link">Tab 2</a></li>
  <li><a routerLink="/some/third/link">Tab 3</a></li>
<ul>

我似乎无法在ng-content中嵌入内容,这是我首先尝试的方法,下面的模板因ExpressionChangedAfterItHasBeenCheckedError

It doesn't seem like I can embed content in ng-content which is what I tried first, and the following template blows up with ExpressionChangedAfterItHasBeenCheckedError

@Component({
  selector: 'demo-tabs',
  template: `<ul class="tabs">
    <li *ngFor="let a of links">
      {{a}}
    </li>
  </ul>`})
export class TabsComponent implements OnInit {
  @ContentChildren('a') links: TemplateRef<any>; // corrected. I originally had this as @ViewChildren

  constructor() { }

  ngOnInit() {
  }

}

首先,这些链接不是Tabs组件的@ViewChildren()-它们是@ContentChildren(),因为@ViewChildren()必须在组件的模板,而@ContentChildren()来自外部声明-就像您所做的一样.

First of all, those links are not @ViewChildren() for Tabs component - they are @ContentChildren(), because @ViewChildren() must be declared in the component's template, while @ContentChildren() are coming from an outside declaration - just like you did.

为了能够以这种方式分离内容,您需要使用非常简单的自定义结构指令(如下所示)标记"所有元素,以便可以将它们作为TabsComponent中单独项目的列表获得.

To be able to separate content in such a way you'll need to "mark" all elements with very simple custom structural directive (as follows) so that you could get them as list of separate items in your TabsComponent.

link.directive.ts

import {Directive, TemplateRef} from '@angular/core';

@Directive({
    selector: '[appLink]'
})
export class AppLinkDirective {
    constructor(public template: TemplateRef<any>) { }
}

这是一个结构指令,可以接收HTML模板作为DI注入令牌.该项目的模板是我们实际上需要呈现到TabsComponent模板中的模板.

This is a structural directive that can receive HTML template as a DI injection token. This item's template is what we actually need to be rendered into TabsComponent's template.

然后,标记我们的物品:

Then, let's mark our items:

app.component.html

<app-demo-tabs>
    <a *appLink routerLink="/some/link">Tab 1</a>
    <a *appLink routerLink="/some/other/link">Tab 2</a>
    <a *appLink routerLink="/some/third/link">Tab 3</a>
</app-demo-tabs>

最后,将它们呈现在组件的模板中:

And, finally, render them in the component's template:

tabs.component.ts

import {Component, ContentChildren, OnInit, QueryList} from '@angular/core';
import {AppLinkDirective} from './link.directive';

@Component({
    selector: 'app-demo-tabs',
    template: `
        <ul class="tabs">
            <li *ngFor="let link of links">
                <ng-template [ngTemplateOutlet]="link?.template"></ng-template>
            </li>
        </ul>`
})
export class TabsComponent implements OnInit {

    @ContentChildren(AppLinkDirective)
    links: QueryList<AppLinkDirective>;

    constructor() {
    }

    ngOnInit() {
    }

}

当然,您需要将此指令导入某个模块,以便可以在模板中使用.

And of course you'll need to import this directive in some module so that it could be used in the template.