Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS postmessage to iframe

I am looking for a way to obtain an iframe contentWindow object and post a message to it after some action of the user. My current solution does not feel ok with angular at all (especially accessing the DOM from the controller).

I have created a plunker demonstrating the issue: http://plnkr.co/edit/aXh4jydWGWfK3QQD4edd

Is the a more angular way to execute the postMessage?

controller:

app.controller('Main', function($scope) {
  $scope.click = function() {
    var iframe = document.getElementById("inner").contentWindow;

    iframe.postMessage("Hello iframe", '*');
  }
});

html:

  <body ng-controller="Main">
    <button ng-click="click()">send message</button>

    <iframe id="inner" src="inner.html"/>
  </body>
like image 242
Max Fichtelmann Avatar asked Sep 30 '22 10:09

Max Fichtelmann


1 Answers

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);
like image 171
NoobsArePeople2 Avatar answered Oct 13 '22 11:10

NoobsArePeople2