Angular Material: mat-dialog opens multiple dialog boxes. Unsubscribe

angularangular-material

I am creating a small angular app using the NHL API provided here.

My idea was to display a list of all players per team, and to be able to click on a player's name and have a dialog box pop up with his details, with the option to proceed to another page with expanded details and statistics if the user chooses to.

I am using angular material mat-dialog.

My approach is upon clicking a player's name, the parent component will first make a call to the API to retrieve that player's data, and once that is resolved, pass that data to the dialog component.

export class PlayersListComponent implements OnInit { 
team: string;
teamId: number; 
teamPlayers = [];
selectedPlayer;

constructor(private playersService: PlayersService,  private route: 
ActivatedRoute, private router: Router,  public dialog: MatDialog) { }

//additional code

getPlayerDetails(player){
 let playerId = +player.person.id
 this.playersService.getPlayerDetails(playerId)
 this.playersService.selectedPlayerUpdated.subscribe((data)=>{
   this.selectedPlayer = data;

   let dialogRef = this.dialog.open(PlayerPopupComponent, {
    data: this.selectedPlayer
   });
   dialogRef.afterClosed().subscribe((result=>{
     console.log('dialog was closed')
     }))
   })
}
}

So the data is passed and the popup works, however upon closing the dialog box and selecting a new player, this time, 2 duplicate popups are created with the the new player's data (along with 2 console logs). For the third player, 3 popups are created, etc.

I have a feeling I either need to unsubscribe somewhere (not sure where, because the parent component where the subscription is made is never destroyed, only the popup component is destroyed but there is no observable because the API call is made from the parent component).

Or the placement of my dialog function is in the wrong place?

here is the entry component:

export class PlayerPopupComponent implements OnInit, OnDestroy {
public thisPlayer;

constructor(public dialogRef: MatDialogRef<PlayersListComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) { }

ngOnInit() {
this.thisPlayer = this.data
console.log(this.thisPlayer)
}

Any help would be appreciated, thank you.

Best Answer

you are on the right track, that the problem is with the subscriptions, so here is a solution

this.playersService
    .selectedPlayerUpdated
    .pipe(take(1))
    .subscribe((data)=>{
        this.selectedPlayer = data;

        let dialogRef = this.dialog.open(PlayerPopupComponent, {
          data: this.selectedPlayer
        });
        dialogRef
        .afterClosed()
        .pipe(take(1))
        .subscribe((result=>{
          console.log('dialog was closed')
     }))
   })

By using take(1) (you can use also the fist()) operator you will automatically unsubscribe after taking exactly one result from the observable, on which are subscribed.