我正在尝试使用@ViewChild
切换*ngIf
元素,然后调用本机事件。
这是我的html元素,用#audioPlayer
装饰,因此我可以通过@ViewChild
提取元素。
<audio
#audioPlayer
*ngIf="conversationIsRunning"
[src]='activeConversation?.clips[activeConversation.activeClipId].audio.blob'
(ended)="audioComplete($event)"
autoplay controls preload="auto" >
</audio>
在我的打字稿中,我有以下内容:
@ViewChild('audioPlayer') audioPlayer;
private conversationIsRunning: boolean;
ngOnInit() {
this.conversationIsRunning = false;
}
ngOnChanges() {
console.log("ngOnChanges");
this.conversationIsRunning = true;
console.log(this.audioPlayer); // undefined
this.audioPlayer.nativeElement.play(); // error
}
如果我从*ngIf
元素中删除audio
,则错误消失。但是我真的希望这个功能在我不需要的时候销毁元素。
我在this回答中看到你可以在@ViewChild
上使用setter,所以我实现了它,但没有成功...
private privAudioPlayer: ViewContainerRef;
@ViewChild('audioPlayer') set audioPlayer(audioPlayer: ViewContainerRef) {
this.privAudioPlayer = audioPlayer;
console.log('audioPlayer set called >> ', audioPlayer, this.privAudioPlayer);
};
...但是这总是输出audioPlayer set called >> undefined undefined
我还尝试将this.conversationIsRunning = true;
从其当前位置拆分并放入各种不同的生命周期钩子,然后将ngOnChanges
更改为其他生命周期钩子也无济于事。
我必须等到下一帧还是什么?为什么set audioPlayer
mutator会收到undefined
?
答案 0 :(得分:0)
在第一个代码示例中,您应该使用ngAfterViewInit()
而不是ngOnChanges()
。
答案 1 :(得分:0)
问题在于,作为动态元素,初始化组件时该元素不存在,因此使用未定义的ElementRef创建视图子级。
有一些解决方案。
如果您运行的是Angular 8,则可以简单地告诉它元素不是静态的,并且当它存在时,视图子级将收到ElementRef:
@ViewChild('audioPlayer', { static: false }) audioPlayer: ElementRef;
在Angular 8之前,最好的方法是将条件元素放在子组件中,并将所有必需的数据作为输入参数传递:
<app-audio *ngIf="conversationIsRunning"> </app-audio>
子组件具有如下模板:
<audio #audioPlayer [src]='activeConversation?.clips[activeConversation.activeClipId].audio.blob'
(ended)="audioComplete($event)"
autoplay controls preload="auto" >
</audio>
您的事件处理程序将位于子代码的后面,并且您可以公开一个方法来响应父组件中的ngChanges进行播放。如果您需要与父级进行通讯,也可以发布事件。该元素始终存在于子组件中,因此ElementRef将始终有效。
最后,您也可以只切换样式显示属性。该组件始终存在于DOM中,并且视图子级将始终具有有效的ElementRef。显然,它总是使用资源并导致负载开销,无论您是否显示它:
<audio
#audioPlayer
[style.display]="conversationIsRunningDisplay()" [src]='activeConversation?.clips[activeConversation.activeClipId].audio.blob'
(ended)="audioComplete($event)"
autoplay controls preload="auto" >
</audio>
代码如下:
@ViewChild('audioPlayer') audioPlayer;
private conversationIsRunning: boolean;
ngOnInit() {
this.conversationIsRunning = false;
}
ngOnChanges() {
console.log("ngOnChanges");
this.conversationIsRunning = true;
console.log(this.audioPlayer); // undefined
this.audioPlayer.nativeElement.play(); // error
}
public conversationIsRunningDisplay() {
if (this.conversationIsRunning) {
return 'block';
}
return 'none';
}