The Task:
I am integrating an existing HTML5 project (a Phaser-based scientific software) into Angular, for the purposes of better structuring of the ever-expanding UI.
The software lies in its own component and is working. All functionality of the software is exposed from a controller class. I have an instance of the controller class inside the state of the Phaser project.
Imagining a new component (say, top-menu) I would like to be able to say:
<div (click)="this.controller.makeAction()"></div>
, where "this.controller" is an instance, saved in the top-menu component.
Related research:
I have read in many places, that the recommended way to communicate between unrelated components is through a service and using an rxjs BehaviorSubject. Ok... here comes the problem:
The Problem:
When I create the service, I have to set the instance of the BehaviorSubject. The problem is that I do not know when the game will be ready, in order to acces the state, and thus provide the controller to the service. So.. the BehaviorSubject stays null and I get an error.
I would really like to avoid placing Angular code inside the Phaser project, as they should be kept as decoupled as possible (currently there is no coupling what-so-ever).
Questions:
Is my approach correct? The controller will be given to any UI element, and thus to any component. How to fix this problem?
Related Code:
1. The service
// Omitting imports and decorators
export class UserActionControllerService {
private _userActionController = new BehaviorSubject<UserActionController>(null);
userActionController = this._userActionController.asObservable();
constructor() { }
setUAC(userActionController: UserActionController){
this._userActionController.next(userActionController);
}
}
2. Using the service in top-menu
//Omitting imports and decorator
export class TopMenuComponent implements OnInit {
userActionController: UserActionController;
constructor(private uac: UserActionControllerService) { }
ngOnInit() {
this.uac.userActionController.subscribe((value) => {
this.userActionController = value;
});
}
and the html...
<p>{{this.userActionController | async | json}}</p>
3. Setting the value of the controller in the service
//Ommitting imports and decorator
export class GteCoreComponent implements OnInit {
game: Phaser.Game;
constructor(private userActionControllerService: UserActionControllerService) {}
ngOnInit() {
this.game = new GTE(width, height);
this.userActionControllerService.setUAC(this.game.state.states.MainScene.userActionController);
}
}
The last line yields an error, because the game has not been created yet. I tried with setTimeout(), still to no avail.
Thanks for your help in advance!
EDIT:
I managed to get it working with setTimeout, which seems like a hack. Any other suggestions?
EDIT2:
As per request, here is the GTE class:
export class GTE extends Phaser.Game {
game: Phaser.Game;
constructor(width?: number, height?: number) {
super(width, height, Phaser.CANVAS, 'phaser-div', null, false, true);
this.game = this;
this.game.state.add('Boot', Boot, false);
this.game.state.add('MainScene', MainScene, false);
this.game.state.start('Boot');
}
}