数据更改时重新创建组件

Jle*_*ham 4 rxjs typescript rxjs5 angular

好吧,这个问题似乎有很多答案,但我一直无法理解我应该做什么。

我目前有一个子组件,当有人单击另一个子组件中的播放按钮时正在创建该子组件。这是通过与我的父级共享数据的服务发生的,然后父级传递数据并创建我的子音频播放器组件。我遇到的问题是,如果用户导航到另一个页面并单击以在该页面上播放音频,则旧音频仍然存在并且新音频不会启动。

是否有生命周期钩子或方法可以用来销毁旧的音频组件并创建新的音频 onclick?

信息框 - 单击播放按钮时初始激活发生的位置。

export class InfoBoxComponent implements OnInit {
  ...

  activateAudioPlayer(session) {
    this.newAudioService.newAudio(session)
  }
}
Run Code Online (Sandbox Code Playgroud)

新的音频服务

export class NewAudioService {
  newActiveAudioSource: Subject<string> = new Subject<string>();

  newAudio(session) {
    this.newActiveAudioSource.next(session);
  }

  newActiveAudio$ = this.newActiveAudioSource.asObservable();
}
Run Code Online (Sandbox Code Playgroud)

前端组件 - 信息框和音频播放器的父组件

@Component({ 
   template: `<audio-player *ngIf='newActiveAudio' [newActiveAudio]='newActiveAudio'></audio-player>`,
})

export class FrontendComponent implements OnInit {

  ...

  ngOnInit() {
    this.sub = this.newAudioService.newActiveAudio$.subscribe(
      newActiveAudio => {
        this.newActiveAudio = newActiveAudio;
      });
  }

  ngOnDestroy() {
    // prevent memory leak when component destroyed
    this.sub.unsubscribe();
  }
}
Run Code Online (Sandbox Code Playgroud)

th0*_*h0r 13

这是一个小指令,可以在key值更改时重新创建视图:

import {
  Directive,
  EmbeddedViewRef,
  Input,
  OnChanges,
  SimpleChanges,
  TemplateRef,
  ViewContainerRef
} from '@angular/core';

@Directive({
  selector: '[wRecreateViewKey]'
})
export class RecreateViewDirective implements OnChanges {
  @Input('wRecreateViewKey') key: any;

  viewRef: EmbeddedViewRef<any>;

  constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {}

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.key) {
      if (this.viewRef) {
        this.destroyView();
      }

      this.createView();
    }
  }

  private createView() {
    this.viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
  }

  private destroyView() {
    this.viewRef.destroy();
    this.viewRef = null;
  }
}

Run Code Online (Sandbox Code Playgroud)

使用示例:

import {
  Directive,
  EmbeddedViewRef,
  Input,
  OnChanges,
  SimpleChanges,
  TemplateRef,
  ViewContainerRef
} from '@angular/core';

@Directive({
  selector: '[wRecreateViewKey]'
})
export class RecreateViewDirective implements OnChanges {
  @Input('wRecreateViewKey') key: any;

  viewRef: EmbeddedViewRef<any>;

  constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {}

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.key) {
      if (this.viewRef) {
        this.destroyView();
      }

      this.createView();
    }
  }

  private createView() {
    this.viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
  }

  private destroyView() {
    this.viewRef.destroy();
    this.viewRef = null;
  }
}

Run Code Online (Sandbox Code Playgroud)


mar*_*tin 5

一种可能的方法是设置this.newActiveAudio = false然后让 Angular 更新视图setTimeout(),然后设置新值newActiveAudio

this.sub = this.newAudioService.newActiveAudio$.subscribe(newActiveAudio => {
    this.newActiveAudio = false;
    setTimeout(() => {
        this.newActiveAudio = newActiveAudio;
    });
});
Run Code Online (Sandbox Code Playgroud)


Pan*_*und 5

为此找到了一个小技巧。将您的元素放在一个元素数组中并使用 trackBy 创建 ngFor

 <component *ngFor="let o of [object]; trackBy: trackByObjectProperty">
        </component>
Run Code Online (Sandbox Code Playgroud)