title: Sharing angularjs instance with an iframe (fancybox)
body: <p>I am trying to work out how I can get a controller in an iframe to play nicely with the angularjs instance in the main page body.</p>
  
  <p>The content is in the form of a login form and it is displayed in a iframe via fancybox. It therefore has its own document head including an angularjs library include and a controller, which is attached to the same module as the parent. I previously had it working like this:</p>
  
  <pre><code>/* parent JS */
  var $app = angular.module('Checkout', []);
  
  $app.controller('BasketCtrl', ['$scope', '$rootScope', function($scope, $rootScope) {
      $rootScope.$on('LoginFormCtrl.login', function(e, data) {
          var f = function() {
              // do something
          };
  
          /* Hack 1 - iframe has its own instance and digest cycle so it might be in phase */
          $rootScope.$$phase &amp;&amp; f() || $scope.$apply(f);
      });
  }]);
  
  /* iframe js */
  $app.controller('LoginCtrl', ['$scope', '$http', function($scope, $http) {
      $scope.login = function() {
          $http({
              href : '/customer/ajax/login',
              data : {
                  emailAddress : $scope.emailAddress,
                  password     : $scope.password
              }
          }).success(function(data) {
              /* Hack 2 - can't broadcast on own root scope because it's separate from parent's */
              $('div[ng-controller="BasketCtrl"]').scope().$broadcast('LoginCtrl.login', data);
          });
      };
  }]);
  </code></pre>
  
  <p>I've just written that from memory so there may be errors but that's the crux of it. There are two dirty things in there which I've commented on. I didn't know why these hacks were required until it dawned me that they had no common root scope...</p>
  
  <p>Anyway, I've since attempted to move the login stuff out to a service so I can share its logic with other parts of the site, e.g.:</p>
  
  <pre><code>$app.service('Auth', ['$http', '$rootScope', function($http, $rootScope) {
      return {
          login : function(emailAddress, password) {
              return $http({
                  // blah blah blah
              }).success(function(data) {
                  $rootScope.$broadcast('Auth.login', data);
              });
          }
      };
  }]);
  
  $app.controller('LoginCtrl', ['$scope', 'Auth', function($scope, Auth) {
      $scope.login = function() {
          Auth.login($scope.emailAddress, $scope.password).success(function(data) {
              parent.$.fancybox.close();
          });
      };
  });
  </code></pre>
  
  <p>The issue therefore is that because there are now two angularjs instances, there are two instances of Auth and when the event is broadcast from within the iframe, the parent JS has no knowledge of it.</p>
  
  <p>I don't see any solution to this really... I think the problem isn't angularjs per se but more just the way that iframes work.</p>
  
  <p>It needs to be an iframe because there is also some navigation going on inside of it to other related pages such as forgotten password form etc. I'd like to keep this flexibility.</p>
  
  <p>I dabbled with making it ajax rather than iframe but it's a nightmare to get the dynamic content linked to angularjs's scope. There are also issues with ensuring links contained within the ajax content do not change the window location... plus it inherits the page CSS... it's a can of worms basically.</p>
  
  <p>Any thoughts?</p>