I realize your question is over a year old at this point but I've recently had a similar need so I thought I'd post my solution. Originally I had something like you posted but as you pointed out this doesn't feel very "Angular". It's also not easily testable which I supposed is also not very "Angular".
Instead I've refactored my code to implement the iframe as a directive. I then $broadcast() events from my app's controllers and have the directive listen for them. This code can probably be improved quite a bit but it's feels a little more "Angular" and avoids directly touching the DOM.
'use strict';
angular.module('app')
.directive('angularIframe', ['$rootScope', function($rootScope) {
return {
restrict: 'E',
replace: true,
template: '<iframe id="game" src="/iframe/index.html" width="100%" height="100%" frameboarder="0" scrolling="no"></iframe>',
link: function(scope, elem) {
var off = $rootScope.$on('app.postmessage', function(ev, data, targetOrigin) {
var str = JSON.stringify(data);
targetOrigin = targetOrigin || '*';
elem[0].contentWindow.postMessage(str, targetOrigin);
});
// See: http://stackoverflow.com/a/14898795/608884
elem.on('$destroy', function() {
off();
});
}
};
}]);
You can then use this directive by adding <game></game> somewhere in your application.
In a controller you can now broadcast the app.postmessage event along with some data to invoke postMessage() on the iframe:
var myData = { foo: 'bar' };
$rootScope.$broadcast('app.postmessage', myData);