首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >@ViewChild未定义

@ViewChild未定义
EN

Stack Overflow用户
提问于 2017-02-14 13:02:53
回答 2查看 2K关注 0票数 0

我尝试使用*ngIf切换@ViewChild元素,然后调用本机事件。

这是我的html元素,用#audioPlayer装饰,这样我就可以通过@ViewChild提取元素。

代码语言:javascript
复制
<audio 
    #audioPlayer     
    *ngIf="conversationIsRunning"    
    [src]='activeConversation?.clips[activeConversation.activeClipId].audio.blob'
    (ended)="audioComplete($event)" 
    autoplay controls preload="auto" >
</audio>

在我的打字稿中,我有以下内容:

代码语言:javascript
复制
@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
}

如果我从audio元素中删除*ngIf,这个错误就会消失。然而,我真的希望这个功能在元素在我不需要它的时候被销毁。

我在this answer中看到可以在@ViewChild上使用setter,所以我实现了它,但是没有成功……

代码语言:javascript
复制
private privAudioPlayer: ViewContainerRef;
@ViewChild('audioPlayer') set audioPlayer(audioPlayer: ViewContainerRef) {
    this.privAudioPlayer = audioPlayer;
    console.log('audioPlayer set called >> ', audioPlayer, this.privAudioPlayer);
};

...however这将始终输出audioPlayer set called >> undefined undefined

我还尝试将this.conversationIsRunning = true;从其当前位置拆分,并将其放入各种不同的ng生命周期钩子中,然后也将ngOnChanges更改为其他生命周期钩子,但都无济于事。

我是不是要等到下一帧或者别的什么?为什么set audioPlayer赋值函数接收undefined

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-02-14 17:25:48

在第一个代码示例中,您应该使用ngAfterViewInit()而不是ngOnChanges()

票数 1
EN

Stack Overflow用户

发布于 2019-11-14 20:09:28

问题是,作为一个动态元素,该元素在组件初始化时并不存在,因此视图子元素是用一个未定义的ElementRef创建的。

这里有几个解决方案。

如果你运行Angular 8,你可以简单地告诉它这个元素不是静态的,当它存在时,视图子元素将收到ElementRef:

代码语言:javascript
复制
@ViewChild('audioPlayer', { static: false }) audioPlayer: ElementRef;

在Angular 8之前,最好的方法是将条件元素放在一个子组件中,并将任何需要的数据作为输入参数传入:

代码语言:javascript
复制
<app-audio *ngIf="conversationIsRunning"> </app-audio>

该子组件具有如下模板:

代码语言:javascript
复制
<audio #audioPlayer [src]='activeConversation?.clips[activeConversation.activeClipId].audio.blob'
(ended)="audioComplete($event)" 
autoplay controls preload="auto" >
</audio>

您的事件处理程序将位于子组件的代码中,并且您可以公开一个方法,该方法将被调用以响应父组件中的ngChanges。如果您需要与父级通信,也可以发布事件。元素始终存在于子组件中,因此ElementRef将始终有效。

最后,您也可以只切换样式显示属性。组件始终存在于DOM中,并且视图子对象将始终具有有效的ElementRef。显然,它总是使用资源并导致负载开销,无论您是否显示它:

代码语言:javascript
复制
<audio 
#audioPlayer     
[style.display]="conversationIsRunningDisplay()"   [src]='activeConversation?.clips[activeConversation.activeClipId].audio.blob'
(ended)="audioComplete($event)" 
autoplay controls preload="auto" >
</audio>

你背后的代码是这样的:

代码语言:javascript
复制
@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';
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42218239

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档