Same-domain iframe communication

AngularJS scope events for same-domain bi-directional iframe communication

It's possible for Angular apps to communicate, where one is running in an iframe of a parent, using standard scope events. This means you can treat an iframe much like a custom directive, responding to $broadcast-ed events, or $emit-ting its own.

This technique relies on the child app being able to access the $scope of the iframe element in the parent app. This is possible by using $window.frameElement to access the iframe element from within the child window, and the angular.element scope function to get its $scope. The child app can then call the parent app's $on and $emit functions.

For simplicity, I've opted to create a small factory in the child app that returns the scope of the iframe in the parent app. This way, it can be used in a very similar way to $rootScope.

appInIframe.factory('$parentScope', function($window) {
  return $window.parent.angular.element($window.frameElement).scope();
});

Then in any controller in the child app that wants to communicate with the parent, you can use these functions as per the following example.

appInIframe.controller('ChildController', function($scope, $parentScope) {
  $scope.messages = [];
  $scope.message = function() {
    $parentScope.$emit('from-iframe','Sent from iframe');
    $parentScope.$apply();
  };
  $parentScope.$on('from-parent', function(e, message) {
    $scope.messages.push(message);
    $scope.$apply();
  });
});

The only thing you should remember is that you need to trigger a digest manually in each app.

The controller in the parent app can then use standard $broadcast and $on to commnicate to the iframe.

appInParentWindow.controller('ParentController', function($scope) {
  $scope.messages = [];
  $scope.$on('from-iframe', function(e, message) {
    $scope.messages.push(message);
  });
  
  $scope.message = function() {
    $scope.$broadcast('from-parent', 'Sent from parent');
  };
});

You can see an example of this technique in a plunker.

Benefits of this technique over some others are given below.

  • No additional global functions added to either the parent or the iframe window. Although yes, it does depend on angular being global in the parent window.
  • The parent controller is ignorant of the fact that events go into an iframe.
  • IDs are not used by parent or child. Because the parent uses the standard $broadcast and $on functions, targeting a specific iframe from the parent controller uses exactly the same techniques you might use to target a custom directive.