Angular ng-template 中的 6 个嵌套 ViewChild 为空
Angular 6 nested ViewChild inside ng-template is null
我们在应用程序中使用模态 (ng-bootstrap's one)。该模式看起来像:
<ng-template #modal let-modal>
<app-audio #audio></app-audio>
</ng-template>
这是逻辑:
@ViewChild('modal')
modal: ElementRef;
@ViewChild('audio')
audio: AudioComponent;
模态打开方式:
this.modalService.open(this.modal, { size: 'lg' });
到这里一切都很好。模式打开并显示音频组件。但是现在,我们想要访问组件内部的逻辑,并且在执行以下操作时:
this.audio.somePublicComponentFunction()
碰巧this.audio为空。我已经尝试使用 angular 的更改检测器来获取子项,但无法找到正确使用实际组件 link this.audio 的方法。有任何想法吗?非常感谢。
You can see the issue here: stackblitz.com/edit/angular-ofmpju
你可以像这样读取没有引用变量的子组件
@ViewChild(AudioComponent)
audio: AudioComponent;
这将为您提供子组件的实例 - 您可以在其中访问方法
this.audio.someComponentFunction()
你的html
<ng-template #modal let-modal>
<app-audio></app-audio>
</ng-template>
我认为这将解决您的问题 - 编码愉快
更新:
希望我找到了解决此问题的方法 - 如果您只想触发一个功能,则可以使用此方法
我刚刚用 getter
和 setter
添加了一个 属性 并在我们 set
值
时触发了函数
@Input()
get triggerFunction(): boolean {
return this.runFuntion;
}
set triggerFunction(value: boolean) {
this.runFuntion = value;
this.someFunction();
}
所以这会导致每次模型出现时触发该函数 - 上面提到的 属性 属于嵌套在 <ng-template>
中的子组件,所以最终模型模板将读取为如下所述:
<ng-template #modal let-modal>
<app-audio [triggerFunction]="true"></app-audio>
</ng-template>
希望这能暂时解决问题 - 谢谢
您可以从模板本身调用方法 audio.someFunction()
。
<ng-template #modal let-modal>
<div style="background-color: red;">
<h1>Modal header</h1>
<app-audio #audio></app-audio>
<!-- on click, call audio comp method someFunction() using its reference -->
<button (click)="audio.someFunction()">Operate with audio from inside modal</button>
</div>
</ng-template>
此处不需要@ViewChild
属性。这应该可以为您解决问题。
分叉 demo
对我来说,所有这些解决方案都不起作用,我仍然想在第三方 ng-template 中访问我自己的组件。这是我的 'solution'。我不认为这是最佳实践,而是获得我想要的东西的绝望解决方案 ;-) 它当然只适用于您自己的组件。
// mycomponent.ts => component that needs to be accessed
import { Component, Output, EventEmitter, AfterViewInit } from '@angular/core';
@Component({
selector: 'my-component',
templateUrl: './mycomponent.html'
})
export class MyComponent implements AfterViewInit {
@Output() initialized: EventEmitter<MyComponent> = new EventEmitter<MyComponent>();
ngAfterViewInit(): void {
this.initialized.emit(this);
}
reload(): void {
// Do something
}
}
// somecomponent.html => component with <ng-template> holding MyComponent
<ng-template>
<div class="btn-group ml-2">
<my-component (initialized)="onMyComponentInitialized($event)"></my-component>
</div>
</ng-template>
// somecomponent.ts => component with <ng-template> holding MyComponent
import { Component, OnDestroy } from '@angular/core';
import { MyComponent } from '../../my-component';
@Component({
selector: 'some-component',
templateUrl: './some-component.html'
})
export class SomeComponent implements OnDestroy {
private _myComponent: MyComponent = null;
onMyComponentInitialized(component: MyComponent) {
this._myComponent = component;
}
someOtherMethod() {
if (this._myComponent) {
// Call some method on the component
this._myComponent.reload();
}
}
ngOnDestroy() {
this._myComponent = null;
}
}
我们在应用程序中使用模态 (ng-bootstrap's one)。该模式看起来像:
<ng-template #modal let-modal>
<app-audio #audio></app-audio>
</ng-template>
这是逻辑:
@ViewChild('modal')
modal: ElementRef;
@ViewChild('audio')
audio: AudioComponent;
模态打开方式:
this.modalService.open(this.modal, { size: 'lg' });
到这里一切都很好。模式打开并显示音频组件。但是现在,我们想要访问组件内部的逻辑,并且在执行以下操作时:
this.audio.somePublicComponentFunction()
碰巧this.audio为空。我已经尝试使用 angular 的更改检测器来获取子项,但无法找到正确使用实际组件 link this.audio 的方法。有任何想法吗?非常感谢。
You can see the issue here: stackblitz.com/edit/angular-ofmpju
你可以像这样读取没有引用变量的子组件
@ViewChild(AudioComponent)
audio: AudioComponent;
这将为您提供子组件的实例 - 您可以在其中访问方法
this.audio.someComponentFunction()
你的html
<ng-template #modal let-modal>
<app-audio></app-audio>
</ng-template>
我认为这将解决您的问题 - 编码愉快
更新:
希望我找到了解决此问题的方法 - 如果您只想触发一个功能,则可以使用此方法
我刚刚用 getter
和 setter
添加了一个 属性 并在我们 set
值
@Input()
get triggerFunction(): boolean {
return this.runFuntion;
}
set triggerFunction(value: boolean) {
this.runFuntion = value;
this.someFunction();
}
所以这会导致每次模型出现时触发该函数 - 上面提到的 属性 属于嵌套在 <ng-template>
中的子组件,所以最终模型模板将读取为如下所述:
<ng-template #modal let-modal>
<app-audio [triggerFunction]="true"></app-audio>
</ng-template>
希望这能暂时解决问题 - 谢谢
您可以从模板本身调用方法 audio.someFunction()
。
<ng-template #modal let-modal>
<div style="background-color: red;">
<h1>Modal header</h1>
<app-audio #audio></app-audio>
<!-- on click, call audio comp method someFunction() using its reference -->
<button (click)="audio.someFunction()">Operate with audio from inside modal</button>
</div>
</ng-template>
此处不需要@ViewChild
属性。这应该可以为您解决问题。
分叉 demo
对我来说,所有这些解决方案都不起作用,我仍然想在第三方 ng-template 中访问我自己的组件。这是我的 'solution'。我不认为这是最佳实践,而是获得我想要的东西的绝望解决方案 ;-) 它当然只适用于您自己的组件。
// mycomponent.ts => component that needs to be accessed
import { Component, Output, EventEmitter, AfterViewInit } from '@angular/core';
@Component({
selector: 'my-component',
templateUrl: './mycomponent.html'
})
export class MyComponent implements AfterViewInit {
@Output() initialized: EventEmitter<MyComponent> = new EventEmitter<MyComponent>();
ngAfterViewInit(): void {
this.initialized.emit(this);
}
reload(): void {
// Do something
}
}
// somecomponent.html => component with <ng-template> holding MyComponent
<ng-template>
<div class="btn-group ml-2">
<my-component (initialized)="onMyComponentInitialized($event)"></my-component>
</div>
</ng-template>
// somecomponent.ts => component with <ng-template> holding MyComponent
import { Component, OnDestroy } from '@angular/core';
import { MyComponent } from '../../my-component';
@Component({
selector: 'some-component',
templateUrl: './some-component.html'
})
export class SomeComponent implements OnDestroy {
private _myComponent: MyComponent = null;
onMyComponentInitialized(component: MyComponent) {
this._myComponent = component;
}
someOtherMethod() {
if (this._myComponent) {
// Call some method on the component
this._myComponent.reload();
}
}
ngOnDestroy() {
this._myComponent = null;
}
}