Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recreating a component when data changes

Ok so there seems to be a lot of answers to this question but I haven't been able to comprehend what I should do.

I currently have a child component that is being created when someone clicks a play button from another child component. This is happening through a service which shares the data with my parent and then the parent passes the data and creates my child audio-player component. The problem I'm having is if the user navigates to another page and clicks to play the audio on that page the old audio still persists and the new audio doesn't start.

Is there a lifecycle hook or a method I could use to destroy my old audio component and create a new audio onclick?

Info Box - Where the initial activation happens when play button is clicked.

export class InfoBoxComponent implements OnInit {
  ...

  activateAudioPlayer(session) {
    this.newAudioService.newAudio(session)
  }
}

New Audio Service

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

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

  newActiveAudio$ = this.newActiveAudioSource.asObservable();
}

Frontend Component - Parent Component of Info Box and Audio Player

@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();
  }
}
like image 529
Jleibham Avatar asked Dec 07 '22 20:12

Jleibham


1 Answers

Here is a small directive that recreates view when key value changes:

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;
  }
}

Usage example:

<!-- `some-component` will be destroyed and recreated every time `value` changes. -->

<some-component *wRecreateViewKey="value"></some-component>

<!-- Can also be used on regular DOM elements or container -->
<div *wRecreateViewKey="value"></div>
<ng-container *wRecreateViewKey="value"></ng-container>
like image 166
th0r Avatar answered Dec 10 '22 12:12

th0r