簡體   English   中英

@ViewChild 未定義

[英]@ViewChild is undefined

我正在嘗試使用*ngIf切換@ViewChild元素,然后在此之后調用本機事件。

這是我的 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
}

如果我從audio元素中刪除*ngIf ,錯誤就會消失。 但是,我真的希望此功能可以在不需要時銷毀元素。

我在這個答案中看到你可以在@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; 從其當前位置並放入各種不同的 ng 生命周期鈎子,然后也將ngOnChanges更改為其他生命周期鈎子也無濟於事。

我必須等到下一幀還是什么? 為什么那個set audioPlayer mutator 收到undefined

在第一個代碼示例中,您應該使用ngAfterViewInit()而不是ngOnChanges()

問題是作為一個動態元素,在組件初始化時該元素不存在,因此使用未定義的 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';
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM