使用 ng-content 时如何消除内部组件
How to eliminate inner component when using ng-content
我正在尝试排除弹出菜单,所以我可以这样写:
<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>
我有一个 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>
和panel-menu-item
与此HTML:
<li *ngIf="dividerBefore" class="divider"></li>
<li><a><ng-content></ng-content></a></li>
问题是结果 DOM 在 ul
和 li
之间有一个 panel-menu-item
,这打破了 third-party CSS.
有什么方法可以只投影所选 children 的 内容 ,而不投影 children 本身?
This answer 建议在 li
上使用属性而不是组件,但这会泄漏实现。 panel-menu
的用户不需要知道菜单项的实现元素。
要仅投影内容,您应该将内容包装在嵌入式视图中,例如:
面板菜单-item.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>;
}
在前面的代码中,我将模板包装在 ng-template
标记中,并使用 @ViewChild
装饰器从中获取 TemplateRef
实例。
有了 TemplateRef
我们可以轻松管理插入模板的位置:
面板-menu.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();
}
}
我正在使用 @ContentChildren
获取我们的面板菜单项,然后使用内置指令 NgTemplateOutlet 将内容放入 ul
。
我们必须使用 this.cdRef.detectChanges();
运行 第二个摘要循环,因为我们会得到错误
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed
after it was checked. Previous value: 'undefined'. Current value:
'[object Object]'.
一旦 @ViewChild(TemplateRef) content
在更改检测期间更新其值。
我正在尝试排除弹出菜单,所以我可以这样写:
<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>
我有一个 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>
和panel-menu-item
与此HTML:
<li *ngIf="dividerBefore" class="divider"></li>
<li><a><ng-content></ng-content></a></li>
问题是结果 DOM 在 ul
和 li
之间有一个 panel-menu-item
,这打破了 third-party CSS.
有什么方法可以只投影所选 children 的 内容 ,而不投影 children 本身?
This answer 建议在 li
上使用属性而不是组件,但这会泄漏实现。 panel-menu
的用户不需要知道菜单项的实现元素。
要仅投影内容,您应该将内容包装在嵌入式视图中,例如:
面板菜单-item.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>;
}
在前面的代码中,我将模板包装在 ng-template
标记中,并使用 @ViewChild
装饰器从中获取 TemplateRef
实例。
有了 TemplateRef
我们可以轻松管理插入模板的位置:
面板-menu.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();
}
}
我正在使用 @ContentChildren
获取我们的面板菜单项,然后使用内置指令 NgTemplateOutlet 将内容放入 ul
。
我们必须使用 this.cdRef.detectChanges();
运行 第二个摘要循环,因为我们会得到错误
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: '[object Object]'.
一旦 @ViewChild(TemplateRef) content
在更改检测期间更新其值。