代码之家  ›  专栏  ›  技术社区  ›  louisvno

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

  •  0
  • louisvno  · 技术社区  · 7 年前

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

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

    为什么ngFor没有检测到audiourl数组中的更改?

    应用程序组件。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>
    

    应用程序组件。ts:

    import { RecordService } from './record.service';
    import { Component, HostListener } from '@angular/core';
    import { Subscription } from 'rxjs/Subscription';
    import { SafeUrl, SafeResourceUrl } from '@angular/platform-browser';
    import { OnInit } from '@angular/core/src/metadata/lifecycle_hooks';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit{
      title = 'app';
    
      audioUrls: SafeResourceUrl[];
    
      constructor(private recordService:RecordService){
      }
    
      ngOnInit(){
        this.recordService.audioUrlsChanged.subscribe(list => this.audioUrls = list);
      }
    
      startRecording(){
        if(this.recordService.audioRecorder){
          this.recordService.audioRecorder.start()
          console.log(this.recordService.audioRecorder.state);
        }
      }
    
      stopRecording(){
        if(this.recordService.audioRecorder){
          this.recordService.audioRecorder.stop()
          console.log(this.recordService.audioRecorder.state);
        }
      }
    }
    

    服务:

    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 refservice只是Window对象的包装)

    1 回复  |  直到 7 年前
        1
  •  3
  •   Boland    7 年前

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

    因此,Angular不会更新视图。你必须在ngZone中运行它。跑

    1. 添加变量 zone 要创建服务的构造函数,请键入 NgZone .
    2. 在stop事件中,将代码包装在 this.zone.run() .

    或者,您可以调用ChangeDetectorRef。detectChanges()。

    参见eg this blog post 要获得更好的解释: