使用 ng-content 时如何消除内部组件

Dan*_*lis 4 angular2-ngcontent angular

我正在尝试分解弹出菜单,以便我可以这样写:

<panel-menu>
  <panel-menu-item>Edit input</panel-menu-item>
  <panel-menu-item>Edit mappings</panel-menu-item>
  <panel-menu-item divider-before>Show agent code</panel-menu-item>
</panel-menu>
Run Code Online (Sandbox Code Playgroud)

我有一个panel-menu带有以下 HTML 的组件:

<div class="btn-group" [class.open]="...">
  <button type="button" class="btn btn-default" (click)="..."><i class="ion-gear-b icon-lg"></i></button>
  <ul class="dropdown-menu dropdown-menu-right">
    <ng-content select="panel-menu-item"></ng-content>
  </ul>
</div>
Run Code Online (Sandbox Code Playgroud)

并panel-menu-item使用以下 HTML:

<li *ngIf="dividerBefore" class="divider"></li>
<li><a><ng-content></ng-content></a></li>
Run Code Online (Sandbox Code Playgroud)

问题是生成的 DOM 在 和 之间有一个panel-menu-item,ul这li破坏了第三方 CSS。

是否有某种方法可以仅投影所选子项的内容,而不是子项本身?

这个答案建议使用属性而li不是组件,但这会泄漏实现。用户panel-menu不需要知道菜单项是作为哪些元素实现的。

yur*_*zui 5

要仅投影内容,您应该将内容包装在嵌入式视图中,例如:

面板菜单项.component.ts

@Component({
  selector: 'panel-menu-item',
  template: `
    <ng-template>
      <li *ngIf="dividerBefore" class="divider"></li>
      <li><a><ng-content></ng-content></a></li>
    </ng-template>
  `
})
export class PanelMenuItemComponent {
  @ViewChild(TemplateRef) content: TemplateRef<any>;
}
Run Code Online (Sandbox Code Playgroud)

在前面的代码中,我将模板包装在标签中,并使用装饰器从中ng-template获取实例。TemplateRef@ViewChild

我们TemplateRef可以轻松管理插入模板的位置:

面板菜单.component.ts

@Component({
  selector: 'panel-menu',
  template: `
    <div class="btn-group" >
      <button type="button" class="btn btn-default">Some button</button>
      <ul class="dropdown-menu dropdown-menu-right">
        <ng-container *ngFor="let item of menuItems">
          <ng-container *ngTemplateOutlet="item.content"></ng-container>
        </ng-container>
      </ul>
    </div>
  `
})
export class PanelMenuComponent {
  @ContentChildren(PanelMenuItemComponent) menuItems: QueryList<PanelMenuItemComponent>;

  constructor(private cdRef: ChangeDetectorRef) {}

  ngAfterViewInit() {
    this.cdRef.detectChanges();
  }
}
Run Code Online (Sandbox Code Playgroud)

我用来@ContentChildren获取面板菜单项,然后使用内置指令NgTemplateOutlet将内容放入ul.

我们必须通过使用运行第二个摘要周期,this.cdRef.detectChanges();因为我们会收到错误

ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后已更改。先前值:“未定义”。当前值:“[对象对象]”。

@ViewChild(TemplateRef) content在更改检测期间更新其值。

堆栈闪电战示例