我试图通过按下父级按钮来执行子组件的功能,但由于某种原因它未定义。
父:
.. com1.html
<ng-template #content let-c="close" let-d="dismiss">
<div class="modal-header">
<h4 class="modal-title">Title</h4>
</div>
<div class="modal-body" style="display: flex; justify-content: center;">
<app-com2 [var1]="value" #traceRef></app-com2>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="savePNG()"><i class="fa fa-download"></i>PNG</button>
<button type="button" class="btn btn-outline-dark" (click)="c()">Close</button>
</div>
</ng-template>
<button class="btn btn-sm btn-secondary" (click)="open(content)">Button</button>
...com1.ts
export class com1 implements OnInit {
@ViewChild('traceRef') traceRef;
value = "something";
constructor(private modalService: NgbModal) {}
savePNG() {
this.traceRef.savePNG();
}
open(content: any) {
this.modalService.open(content, { windowClass: 'temp-modal' });
}
}
任何人都可以指出我正确的方向因为其他线程没有帮助:( 即使使用ngAfterViewInit,它仍然未定义。
答案 0 :(得分:2)
它与ng-template
的常见情况不同的原因是NgbModal
服务创建模板并且不将其附加到父视图,而是附加到根ApplicationRef
}
const viewRef = content.createEmbeddedView(context);
this._applicationRef.attachView(viewRef);
这意味着您的组件的查询总是无效。
在一般情况下(参见@ConnorsFan提供的example),我们使用vcRef.createEmbeddedView
负责检查父视图中的查询:
vcRef.createEmbeddedView
||
\/
function attachEmbeddedView(
...
Services.dirtyParentQueries(view); <========== set dirty for queries
我在这里看到的简单解决方案就是直接在模板中传递或调用引用:
(click)="traceRef.savePNG()"
答案 1 :(得分:0)
我认为您需要以下内容。将ChildComponent替换为您的子类名
@ViewChild('traceRef')
traceRef:ChildComponent
答案 2 :(得分:0)
我注意到您的父模板是一个模态,您可以使用模板变量在此处打开:((click)="open(content)"
通过模态服务。所以这意味着它会动态地添加到DOM中。
因此,这可能是一个时间问题,因为父项是动态加载的。
我会尝试这个,在CHILD的ngAfterViewInit中,使用EventEmitter触发一个事件。抓取父项中的事件,然后将标志设置为true。然后在理论中,您可以在父母中执行此操作:
savePNG() {
if (this.childLoaded) this.traceRef.savePNG();
}
您确定孩子已加载,因此savePNG可用。但是,请参阅我的注释 - traceRef仍然是未定义的。
因此,您需要在EventEmitter中传递对子函数的引用,并使用它而不是#traceRef。
例如 - 在孩子身上:
export class app-com2 implements blah blah {
@Output() childLoaded: EventEmitter<any> = new EventEmitter<any>();
savePNG() {
// code to save the image
}
ngAfterViewInit() {
this.childLoaded.emit(this.savePNG);
}
}
父:
.. com1.html
<ng-template #content let-c="close" let-d="dismiss">
<div class="modal-header">
<h4 class="modal-title">Title</h4>
</div>
<div class="modal-body" style="display: flex; justify-content: center;">
<app-com2 [var1]="value" (childLoaded)="handleChildLoaded($event)"></app-com2>
</div>
.. com1.ts
handleChildLoaded(save: any) {
const result = save;
console.log(result);
}
Docs关于孩子到父母的通讯。
请注意
更多地考虑这个问题 - 这是一个生命周期/计时问题,因此您的代码将无法运行。这可能就是原因:
您的父组件加载,触发所有生命周期挂钩(例如ngOnInit和ngAfterViewInit等)。 #content得到处理,并在ngAfterViewInit和以后的钩子中可用。
现在单击按钮加载#content(可用)。但它有<app-com2>
组件,用#traceRef模板变量引用。但是模板变量只在ngAfterViewInit钩子触发之前处理 - 而且已经为父节点触发了,因此#traceRef来得太晚,Angular无法将它连接起来。因此它总是未定义的。
请参阅下面关于(2)的评论 - 不太正确,但我怀疑是因为您加载模式的方式,#traceRef将始终未定义。