我想做一个可重用的组件,设置多个子组件并一次渲染一个组件,我在父组件上有一组使用 @ContenChildren 获得的 View ,如下所示:
@ContentChildren(ChildComponent) children: QueryList<ChildComponent>;
//getCurrentChild function
getCurrentChild(){
//index is a position of child
return this.children.toArray()[this.index];
}
并渲染父模板:
<ng-container *ngTemplateOutlet="getCurrentChild().content"></ng-container>
内容通过@ViewChild在子组件中渲染:
@ViewChild('currentChild') child;
模板如下所示:
<ng-template #currentChild>
<ng-content>
</ng-content>
</ng-template>
当我想实现这个结构时,我会这样做:
<parent>
<child>
<specific-one></specific-one>
</child>
<child>
<specific-two></specific-two>
</child>
</parent>
现在我在父组件中有一个方法,该方法在单击按钮时触发,并且需要调用特定组件中的方法(具体一或具体二取决于 currentChild):
export class SpecificOneComponent implements OnInit{
action(){
//this action will be called when parent is clicked
}
}
我尝试通过子引用
调用方法,但操作没有退出。还传递上下文,两者都没有。看来我在父模板中设置内容的方式不正确。
如有任何帮助,我们将不胜感激。
最佳答案
每个子组件都有自己的内容,因此这意味着仅获取对 ng-template
的引用就足够了,其中会有 ng-content
.
此外,由于您希望在父级上发生特定事件时调用特定组件的方法,因此我们将使用一项服务,以便能够通知具体组件。
特定.service.ts
private _shouldCallAction$ = new Subject();
shouldCallAction$ = this._shouldCallAction$.asObservable();
constructor() { }
triggerAction (uniqueCompId) {
this._shouldCallAction$.next(uniqueCompId);
}
特定-{one|two|...n}.component.ts
这适用于依赖于父组件中发生的某些事件的每个组件。
private shouldCallActionSubscription: Subscription;
uniqueId: number | string;
constructor(private specificService: SpecificService) {
this.uniqueId = randomId();
}
ngOnInit() {
this.shouldCallActionSubscription = this.specificService.shouldCallAction$
.pipe(
filter(id => id === this.uniqueId)
)
.subscribe(() => {
console.log('calling action for specific-one')
});
}
ngOnDestroy () {
this.shouldCallActionSubscription.unsubscribe();
}
child.component.html
<ng-container *ngIf="instanceIdx === crtIdx">
<h3>trigger action of current specific component</h3>
<button (click)="triggerAction()">trigger</button>
</ng-container>
<ng-template #currentChild>
<ng-content></ng-content>
</ng-template>
child.component.ts
在这里,您还需要获取对specificComponent
的引用,以获得其唯一ID。
// Before class
let instances = 0;
@ViewChild('currentChild', { static: true }) tpl: TemplateRef<any>;
@ContentChild('specific', { static: true }) specificComp;
get uniqueSpecificCompId () {
return this.specificComp.uniqueId;
}
constructor (private specificService: SpecificService) {
this.instanceIdx = instances++;
}
triggerAction () {
this.specificService.triggerAction(this.uniqueSpecificCompId);
}
父组件.ts
@ViewChildren(ChildOneComponent) children: QueryList<ChildOneComponent>;
@ViewChild('container', { static: true, read: ViewContainerRef }) container: ViewContainerRef;
crtIdx = 0;
ngAfterViewInit () {
this.setNewView();
}
setNewView () {
this.container.clear();
this.container.createEmbeddedView(this.children.toArray()[this.crtIdx].tpl);
}
updateIndex (idx) {
this.crtIdx = idx;
this.setNewView();
}
parent.component.html
<app-child [crtIdx]="crtIdx">
<!-- ... -->
<app-specific-two #specific></app-specific-two>
</app-child>
<app-child [crtIdx]="crtIdx">
<!-- ... -->
<app-specific-one #specific></app-specific-one>
</app-child>
<ng-container #container></ng-container>
<h3>Select a child</h3>
<button
*ngFor="let _ of [].constructor(n); let idx = index;"
(click)="updateIndex(idx)"
>
Select {{ idx + 1 }}
</button>
祝你好运!
关于javascript - 通过 View 中的 @ViewChild 调用组件上的方法到 QueryList,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57515877/