1
votes

I'm working with a parent component that references a child component that plays an audio file in Angular 2. Initially, I'm passing the audio file an input variable of _audioState which contains a string value of "Listen". When the audio button is clicked, this value changes to "Playing" and then "Replay" once the audio file is done playing. These string value changes happen in the audio child component.

When the button with the nextAudio function is clicked in the parent component, I want to reassign _audioState back to "Listen", but the input binding isn't working in the parent once the child component changes this value.

I'm still learning Angular 2 and wasn't sure the best way to get this working. I appreciate any suggestions. My code is below.

Parent Component:

 @Component({
    selector: 'parent-component',
    template: ' <div>
                    <button (click)="nextAudio()"></button>
                    <audio-button [audioPath]="_audioPath"  
                    [audioSrc]="_audioCounter" [audioState]="_audioState">          
                    </audio-button>
                </div>',
    styleUrls: ['./parent-component.less']
})

export class ParentComponent {
 _audioPath: string = "../audio/";
 _audioCounter: number = 1;
 _audioState: string = "Listen";

  nextAudio(): void{
    this._audioCounter = this._audioCounter + 1;
    this._audioState = "Listen";
  }  
}

Child Component:

@Component({
    selector: 'audio-button',
    template: '<button (click)="playSound()"><i class="fa fa-volume-up"></i>    
    {{audioState}}</button>',
    styleUrls: ['./audio-button.component.less']
})
export class AudioButtonComponent {
    @Input() audioPath: string;
    @Input() audioSrc: string;
    @Input() audioState: string;

playSound(): void {
    let sound: any = new Audio(this.audioPath + this.audioSrc + ".mp3");
    sound.play();
    this.audioState = "Playing";
    sound.addEventListener('ended', () => {
        this.audioState = "Replay";
    }, false)

    event.preventDefault();
   }
}
1

1 Answers

1
votes

there are several ways to do it, including of

1. (Recommand) Using ngrx/store

References

Adding Redux with NgRx/Store to Angular (2+) – Part 1 (Oren Farhi)

2. EventEmitter

For example,

@Component({
selector: 'parent-component',
template: `<div>
                Current state : {{_audioState}}
                <hr />
                <audio-button [audioPath]="_audioPath"
                [audioSrc]="_audioCounter" [audioState]="_audioState"
                (emit-status)="updateStatus($event)"
                >
                </audio-button>
            </div>`
})

export class ParentComponent {
  _audioPath: string = "../audio/";
  _audioCounter: number = 1;
  _audioState: string = "Listen";

  nextAudio(): void{ 
    this._audioCounter = this._audioCounter + 1;
    this._audioState = "Listen";
  }

  private updateStatus(status:string){
    this._audioState= status;
  }
}

import { Component, OnInit, Input, Output, EventEmitter } from           '@angular/core';

@Component({
   selector: 'audio-button',
   template: `<button (click)="playSound()"><i class="fa fa-volume-up"></i>
{{audioState}}</button>`,
})

export class AudioButtonComponent {
  @Input() audioPath: string;
  @Input() audioSrc: string;
  @Input() audioState: string;
  @Output('emit-status') emitStatus = new EventEmitter<any>();

  
  playSound(): void {
    //...

    //emit data to parent
    this.emitStatus.emit("playing");
  }
}

3.ViewChild

@Component({
   selector: 'parent-component',
   template: `<div>
            Current state : {{audioBtn.audioState}}
            <hr />
            <audio-button [audioPath]="_audioPath"
            [audioSrc]="_audioCounter" [audioState]="_audioState"
            (emit-status)="updateStatus($event)"
            >
            </audio-button>
        </div>`
})

export class ParentComponent {
    @ViewChild(AudioButtonComponent) audioBtn: AudioButtonComponent;
}

export class AudioButtonComponent {
   //...
  @Input() audioState: string;
  playSound(): void {
     //...
     this.audioState = "playing";
  }
}

Result