Angular 使用ngFor更改阵列后未更新DOM

Angular 使用ngFor更改阵列后未更新DOM,angular,rxjs,ngfor,Angular,Rxjs,Ngfor,想要的行为:当按下停止按钮时,会生成一个音频链接,添加到ngFor添加到列表中的数组中,并更新DOM 实际行为:单击停止按钮后,音频剪辑不会直接添加到列表中。只有在调用新事件(如再次单击停止按钮)时,ngFor才会将其添加到DOM中(并且工作正常) 为什么NGF不检测AudioURL数组中的更改 app-component.html: <button (click)="startRecording()">Start Recording</button> <butto

想要的行为:当按下停止按钮时,会生成一个音频链接,添加到ngFor添加到列表中的数组中,并更新DOM

实际行为:单击停止按钮后,音频剪辑不会直接添加到列表中。只有在调用新事件(如再次单击停止按钮)时,ngFor才会将其添加到DOM中(并且工作正常)

为什么NGF不检测AudioURL数组中的更改

app-component.html:

<button (click)="startRecording()">Start Recording</button>
<button (click)="stopRecording()">Stop Recording</button>
<ul>
  <li *ngFor="let audioUrl of audioUrls">
    <audio controls [src]="audioUrl"></audio> 
  </li>
</ul>
服务:

import { WindowRefService } from './window-ref.service';
import { Injectable, HostListener } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { SafeUrl } from '@angular/platform-browser';
declare var MediaRecorder: any;

@Injectable()
export class RecordService {

  audioRecorder:any;
  chunks:any[] = [];
  audioUrls:SafeResourceUrl[] = [];
  audioUrlsChanged= new Subject<SafeResourceUrl[]>();

  constructor(private windowRef:WindowRefService, private domSanitizer: DomSanitizer) { 
    this.audioRecorder = this.windowRef.nativeWindow.navigator.mediaDevices.getUserMedia (
      // constraints - only audio needed for this app
      {
         audio: true
      }).then(
        stream => {
          this.audioRecorder = new MediaRecorder(stream);

          this.audioRecorder.ondataavailable = (e) => {
            this.chunks.push(e.data);
          }

          this.audioRecorder.onstop = (e) => {
            let blob = new Blob(this.chunks, { 'type' : 'audio/ogg; codecs=opus' });
            this.chunks = []; //reset buffer
            let url:SafeResourceUrl = this.domSanitizer.bypassSecurityTrustResourceUrl(this.windowRef.nativeWindow.URL.createObjectURL(blob));
            this.audioUrls.push(url);
            this.audioUrlsChanged.next(this.audioUrls.slice());        
          }
      });     
  }
从“/window-ref.service”导入{WindowRefService};
从“@angular/core”导入{Injectable,HostListener};
从“rxjs/Observable”导入{Observable};
从'rxjs/Subject'导入{Subject};
从“@angular/platform browser”导入{domsanizer,SafeResourceUrl};
从“@angular/platform browser”导入{SafeUrl};
声明var MediaRecorder:任何;
@可注射()
导出类记录服务{
录音机:任何;
块:任意[]=[];
audioURL:SafeResourceUrl[]=[];
audioUrlsChanged=新主题();
构造函数(私有windowRef:WindowRefService,私有domSanitizer:domSanitizer){
this.audioRecorder=this.windowRef.nativeWindow.navigator.mediaDevices.getUserMedia(
//限制-此应用程序只需要音频
{
音频:正确
}).那么(
流=>{
this.audioRecorder=新媒体记录器(流);
this.audioRecorder.ondataavailable=(e)=>{
this.chunks.push(即数据);
}
this.audioRecorder.onstop=(e)=>{
让blob=newblob(this.chunks,{'type':'audio/ogg;codecs=opus'});
this.chunks=[];//重置缓冲区
让url:SafeSourceUrl=this.domsanizer.bypassSecurityTrustResourceUrl(this.windowRef.nativeWindow.url.createObjectURL(blob));
this.audioUrls.push(url);
this.audioUrlsChanged.next(this.audioUrls.slice());
}
});     
}

(Window refservice只是窗口对象的包装)

audioRecorder onstop方法发生在Angular上下文之外,因为它是Angular外部库生成的事件

因此,Angular不会更新视图。您必须在ngZone.run中运行它

  • 将变量
    zone
    添加到服务的构造函数中,键入
    NgZone
  • 在stop事件中,将代码包装在
    this.zone.run()中
  • 或者,您可以调用ChangeDetectorRef.detectChanges()


    请参见eg以获得更好的解释:

    音频录制器顶部方法发生在Angular上下文之外,因为它是Angular外部库生成的事件

    因此,Angular不会更新视图。您必须在ngZone.run中运行它

  • 将变量
    zone
    添加到服务的构造函数中,键入
    NgZone
  • 在stop事件中,将代码包装在
    this.zone.run()中
  • 或者,您可以调用ChangeDetectorRef.detectChanges()

    有关更好的解释,请参见eg:

    import { WindowRefService } from './window-ref.service';
    import { Injectable, HostListener } from '@angular/core';
    import { Observable } from 'rxjs/Observable';
    import { Subject } from 'rxjs/Subject';
    import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
    import { SafeUrl } from '@angular/platform-browser';
    declare var MediaRecorder: any;
    
    @Injectable()
    export class RecordService {
    
      audioRecorder:any;
      chunks:any[] = [];
      audioUrls:SafeResourceUrl[] = [];
      audioUrlsChanged= new Subject<SafeResourceUrl[]>();
    
      constructor(private windowRef:WindowRefService, private domSanitizer: DomSanitizer) { 
        this.audioRecorder = this.windowRef.nativeWindow.navigator.mediaDevices.getUserMedia (
          // constraints - only audio needed for this app
          {
             audio: true
          }).then(
            stream => {
              this.audioRecorder = new MediaRecorder(stream);
    
              this.audioRecorder.ondataavailable = (e) => {
                this.chunks.push(e.data);
              }
    
              this.audioRecorder.onstop = (e) => {
                let blob = new Blob(this.chunks, { 'type' : 'audio/ogg; codecs=opus' });
                this.chunks = []; //reset buffer
                let url:SafeResourceUrl = this.domSanitizer.bypassSecurityTrustResourceUrl(this.windowRef.nativeWindow.URL.createObjectURL(blob));
                this.audioUrls.push(url);
                this.audioUrlsChanged.next(this.audioUrls.slice());        
              }
          });     
      }