0

I have a component that has a scorebar on the left side. I also have a game service that handles all game logic. If a new player joins, I want to hide the scorebar, change the players array within the game.service and show the scorebar again.

This is what I currently have:

game.component.ts:

this.scorebarSub = this.gameService.hideScorebar.subscribe(hide => {
  const scorebar = $('#score-bar');
  if (hide && !this.scoreIsHidden) {
    scorebar.animate({"margin-left": '-=400'});
    this.scoreIsHidden = true;
  } else if (!hide && this.scoreIsHidden) {
    scorebar.animate({"margin-left": '+=400'});
    this.scoreIsHidden = false;
  }
})

game.service.ts:

playerJoined(player: Player) {
    this.hideScorebar.next(true);
    this.currentRoom.players.push(player);
    this.hideScorebar.next(false);
}

The problem is now that I cant wait for the animation to finish so the scorebar gets updated while the hide animation is played.

How can I do this in a better way?

derloopkat
  • 6,232
  • 16
  • 38
  • 45
sirzento
  • 537
  • 1
  • 5
  • 23

2 Answers2

1

You need to utilise the complete function parameter of animate which is called when the animation completes. Here is a simplified, untested example which will hopefully point you in the right direction:

Component:

this.scorebarSub = this.gameService.updateScorebar.subscribe((player) => {
  const scorebar = $('#score-bar');

  scorebar.animate({"margin-left": '-=400'}, 400, 'swing', 
      () => {      
          // this method executes when the animation is complete
          this.gameService.addPlayer(player);
          scorebar.animate({"margin-left": '+=400'});
          }
    ));
});

Service:

playerJoined(player: Player) {
    this.updateScorebar.next(player);
}

addPlayer(player: Player) {
     this.currentRoom.players.push(player);
}

It is also worth mentioning that mixing jQuery with Angular is somewhat unconventional.

wlf
  • 3,086
  • 1
  • 19
  • 29
  • Isn't this somewhat strange that I take the player object from service -> component -> service? But I guess this could work – sirzento Jul 04 '20 at 22:36
  • Possibly, but I was focusing on the usage of the complete callback without diverging too much from your original code. – wlf Jul 04 '20 at 22:38
-1

the simplest way would be to wrap this.hideScorebar.next(false); in a setTimeout to wait for your animation to process. but it is not the best way. consider the following:

playerJoined(player: Player) {
    this.playerJoined.next();
    this.currentRoom.players.push(player);
}
this.gameService.playerJoined.subscribe(() => {
    if(this.openScoreTimeout) { // a new player joined while animation was in progress
       clearTimeout(this.openScoreTimeout)
    } else {
       scorebar.animate({"margin-left": '-=400'});
       this.scoreIsHidden = true;
    }
    this.openScoreTimeout = setTimeout(() => {
       scorebar.animate({"margin-left": '+=400'});
       this.scoreIsHidden = false;
       this.openScoreTimeout = 0;
    }, animationTime)
}
D Pro
  • 1,756
  • 1
  • 8
  • 15
  • I dont think this works. `this.currentRoom.players.push(player)` gets called right after the event has fired so the player gets added to the array immediately and then the animation starts. Or am I wrong? – sirzento Jul 04 '20 at 10:29
  • I don't know how the rest of your app works, I don't even know what's going on in your template. maybe my solution will gave you an idea how to solve your problem. – D Pro Jul 04 '20 at 10:32