如何在组件B中渲染组件A的一部分
How to render a part of Component A in Component B
我有一个组件 A
和 B
<div class="A">
<div class="A1"></div>
<div class="A2"></div>
</div>
<div class="B">
<!--want to display <div class="A1"></div> here-->
</div>
组件 B
不包含组件 A
或绕过
<componentA></componentA>
<componentB></componentB>
我尝试将 <div class="A1"></div>
包装到 ng-template
中,然后在 componentB
中查询,但它始终是 undefined
:
@ViewChild('templ') templ: TemplateRef<any>;
然后我意识到@ViewChild
是查询子组件,那你怎么查询和渲染<ng-template>
它不是子组件?
渲染组件 A
的模板作为组件 B
的内容
<ComponentB>
<ComponentA></ComponentA>
</ComponentB>
componentB
渲染的内部模板 'content'(在本例中为 ComponentA
的模板)
ComponentB.component.html
<ng-content> </ng-content>
要访问 ComponentB
中呈现的 ComponentA
,请使用 ContentChild
@ContentChild(ComponentA) footer: componentA;
您可以在父组件中创建公共 ng-template
并将其 templateRef
传递给组件 Input
绑定中的子组件。稍后内部组件将填充该模板的模板绑定。
这意味着在两个组件中添加 @Input a1: TemplateRef<any>;
并在组件 A 和 B 的父组件(基本上它们具有相同的父组件)的父组件中放在 ng-template
下方。
<ng-template #a1>
<div class="A1">
{{item.Description}}
</div>
</ng-tmeplate>
组件 A 模板
<div class="A">
<ng-container
*ngTemplateOutlet="a1;context:{item: valueFromComponentA}">
</ng-container>
<div class="A2"></div>
</div>
组件 B 模板
<div class="B">
<ng-container
*ngTemplateOutlet="a1;context:{item: valueFromComponentB}">
</ng-container>
</div>
看看 Alex Rickabaugh 的 awesome sideNav sample,它演示的正是您所需要的。
基于此,您需要在 ComponentA
中定义一个 ng-container
。然后你需要用自定义指令标记你的 ComponentB
部分,并且有一个连接 ComponentA
和 ComponentB
:
的服务
<div class="A1"><div>
<div class="A2" *leftNav >
<h3>Content</h3>
</div>
指令:
@Directive({
selector: '[leftNav]',
})
export class LeftNavDirective implements OnInit {
constructor(private leftNav: LeftNav, private ref: TemplateRef<any>) {}
ngOnInit(): void {
this.leftNav.setContents(this.ref);
}
}
服务:
@Injectable()
export class LeftNav {
private _state = new BehaviorSubject<TemplateRef<any>|null>(null);
readonly contents = this._state.asObservable();
setContents(ref: TemplateRef<any>): void {
this._state.next(ref);
}
clearContents(): void {
this._state.next(null);
}
}
最后,在您的 ComponentB
中,您必须在 ngAfterViewInit
上订阅您的 <div class="A1"> ... <div>
内容:
ngAfterViewInit(): void {
this
.leftNav
.contents
.subscribe(ref => {
if (this._current !== null) {
this._current.destroy();
this._current = null;
}
if (ref === null) {
return;
}
this._current = this.vcr.createEmbeddedView(ref);
});
}
我有一个组件 A
和 B
<div class="A">
<div class="A1"></div>
<div class="A2"></div>
</div>
<div class="B">
<!--want to display <div class="A1"></div> here-->
</div>
组件 B
不包含组件 A
或绕过
<componentA></componentA>
<componentB></componentB>
我尝试将 <div class="A1"></div>
包装到 ng-template
中,然后在 componentB
中查询,但它始终是 undefined
:
@ViewChild('templ') templ: TemplateRef<any>;
然后我意识到@ViewChild
是查询子组件,那你怎么查询和渲染<ng-template>
它不是子组件?
渲染组件 A
的模板作为组件 B
<ComponentB>
<ComponentA></ComponentA>
</ComponentB>
componentB
渲染的内部模板 'content'(在本例中为 ComponentA
的模板)
ComponentB.component.html
<ng-content> </ng-content>
要访问 ComponentB
中呈现的 ComponentA
,请使用 ContentChild
@ContentChild(ComponentA) footer: componentA;
您可以在父组件中创建公共 ng-template
并将其 templateRef
传递给组件 Input
绑定中的子组件。稍后内部组件将填充该模板的模板绑定。
这意味着在两个组件中添加 @Input a1: TemplateRef<any>;
并在组件 A 和 B 的父组件(基本上它们具有相同的父组件)的父组件中放在 ng-template
下方。
<ng-template #a1>
<div class="A1">
{{item.Description}}
</div>
</ng-tmeplate>
组件 A 模板
<div class="A">
<ng-container
*ngTemplateOutlet="a1;context:{item: valueFromComponentA}">
</ng-container>
<div class="A2"></div>
</div>
组件 B 模板
<div class="B">
<ng-container
*ngTemplateOutlet="a1;context:{item: valueFromComponentB}">
</ng-container>
</div>
看看 Alex Rickabaugh 的 awesome sideNav sample,它演示的正是您所需要的。
基于此,您需要在 ComponentA
中定义一个 ng-container
。然后你需要用自定义指令标记你的 ComponentB
部分,并且有一个连接 ComponentA
和 ComponentB
:
<div class="A1"><div>
<div class="A2" *leftNav >
<h3>Content</h3>
</div>
指令:
@Directive({
selector: '[leftNav]',
})
export class LeftNavDirective implements OnInit {
constructor(private leftNav: LeftNav, private ref: TemplateRef<any>) {}
ngOnInit(): void {
this.leftNav.setContents(this.ref);
}
}
服务:
@Injectable()
export class LeftNav {
private _state = new BehaviorSubject<TemplateRef<any>|null>(null);
readonly contents = this._state.asObservable();
setContents(ref: TemplateRef<any>): void {
this._state.next(ref);
}
clearContents(): void {
this._state.next(null);
}
}
最后,在您的 ComponentB
中,您必须在 ngAfterViewInit
上订阅您的 <div class="A1"> ... <div>
内容:
ngAfterViewInit(): void {
this
.leftNav
.contents
.subscribe(ref => {
if (this._current !== null) {
this._current.destroy();
this._current = null;
}
if (ref === null) {
return;
}
this._current = this.vcr.createEmbeddedView(ref);
});
}