I am working on a game which uses angular.js for the ui and a game engine class.
Because of conflicts between the game engine class and the angular-material library, I have to load the the game engine in order after angular.
Once the game engine is initialized, it does dispatch a custom dom event "clientReady", with 2 objects attached that I need to access within my angular controllers.
So on app.run I initialize this 2 objects to the root scope like this:
app.run(function($rootScope) {
$rootScope.engine = {};
$rootScope.editor = {};
document.addEventListener('clientReady', function(e) {
$rootScope.$apply(function() {
$rootScope.engine = e.detail.engine;
$rootScope.editor = e.detail.editor;
});
});
});
Now within my controllers I am trying to set scopes like:
$scope.player = $rootScope.engine.player;
This does not work of course, because the "clientReady" event happens late after angular initialize and the rootscope does not exist when it starts running the controller.
Is there a way to handle this? I'm wondering if I could somehow launch the controllers after the dom event.
You cannot "launch" the controller. You can goto the view and it'll run he controller and bind the scope of the controller with its corresponding view.
So if you want this event to be listened at all times, you should do this in the BodyController. But if you only want to listen to this event on certain views, the you should probably just do this on app.run
app.controller('BodyController', function($rootScope) {
$document.addEventListener('clientReady', function(e) {
// Decide based on view when you want to change initialize the game or not
if($location.path == '/login') {
// don't let the user init as he/she is not logged in
} else {
//init
// Store e in a service or $rootScope. I'd pick a service to do this as I wouldn't want to clutter my $rootScope
GameService.save(e);
// Handle transition to the new path
$location.path('/something');
}
});
})
Or else if you only want to listen to this on one or more views. 1. Listen to clientReady event on one/more of your views (assuming this event is initialized only once)
So, lets say your home/default view is '/'. Then in HomeController, you do this:
app.controller('MainCtrl', function($scope, $document) {
$document.addEventListener('clientReady', function(e) {
// Store e in a service or $rootScope. I'd pick a service to do this as I wouldn't want to clutter my $rootScope
GameService.save(e);
// Goto to View/Controller that needs e
$location.path('/something');
});
}
isInitialized()
returns true ONLY when the clientReady
event has been fired. If isInitialized()return false, then the $location will be changed and execution of GameCtrl will stop (because of
return` statement)app.controller('GameCtrl', function($scope, GameService, $location) {
if(!GameService.isInitialized()) {
$location.path('/home'); // or to any other route you deem fit
// Instead of redirecting, you can handle this gracefully on this view too. But I think that'll take much more effort.
return; //Important so that the controller is not processed any further
}
// This is where the magic happens!
$scope.engine = GameService.getEngine();
$scope.editor = GameService.getEditor();
}
GameService
is where game engine and other client given object is stored.angular.module('myApp').service('GameService', function() {
// AngularJS will instantiate a singleton by calling "new" on this function
this.getEngine = function() {
// Logic
}
this.getEditor = function () {
// Logic
}
this.isInitialized = function () {
// Logic
}
};