触发第三方初始化的角度

时间:2014-02-16 08:45:13

标签: javascript angularjs

我是角色新手,没有简单的角度应用程序的问题,但现在我想与第三方组件集成。我可以想到几个kluges来实现我想要做的事情,但我更喜欢使用一个干净的解决方案来满足一般要求:如何从“外部”角度调用角度代码?

我希望我的角度应用程序初始化一个启动视图,然后等待第三方软件初始化,然后让角度显示主视图。第三方软件通过各种异步调用进行初始化,可能需要一两秒钟,或者在极端情况下需要更长时间。它提供了一个回调函数,在它准备就绪时会被调用。

所以现在要模拟我的效果:

.controller('MySplash', ['$scope', '$location', '$q', 
                             function($scope, $location, $q) {   

      $scope.waitForInit = $q.defer();

      $scope.waitForInit.promise.then(function() {
          $location.path('/tab/MyMainView');
      });

      $scope.waitForInit.resolve();  // fake the post-init triggering
    }])

因此,这显示了启动画面,当延迟满足时显示主屏幕,在这种情况下,它当然会立即发生。

我也有第三方软件提供的功能

 CalledWhenThirdPartyReady() {
      // put some code here
 }

在概念上,我想做的就是将解析调用移到此回调中

 CalledWhenThirdPartyReady() {
       $scope.waitForInit.resolve();
 }

从根本上说,我的谜题是如何获得一些有效的独立代码可以访问DI。在概念中,我想要做的就是调用角度服务,或访问角度变量。我尝试过这种事情

 CalledWhenThirdPartyReady() {

      angular.module('myApp')

   .run(["$rootScope", "$location",
              function ($rootScope, $location) {
                // just to show access to DI-ed variables
                console.log("Run in module", $rootScope, ",", $location);

            }] );
 }

认为将调用run方法并且我可以访问注入的变量,但是运行永远不会被触发我猜是因为我注册run()太晚了。

2 个答案:

答案 0 :(得分:1)

尝试使用$apply

  

$ apply()用于从外部执行角度表达式   角度框架。 (例如,来自浏览器DOM事件,   setTimeout,XHR或第三方库)。因为我们正在呼唤   我们需要执行适当范围生命周期的角度框架   异常处理,执行手表。

例如:

CalledWhenThirdPartyReady() {
    $scope.$apply($scope.waitForInit.resolve());  
}

这要求CalledWhenThirdPartyReady可以访问$scope,例如,如果它在controller内定义。如果您需要在Angular应用程序之外定义CalledWhenThirdPartyReady,则需要以其他方式处理它。

从外部调用controller中的函数的示例:

JS:

var app = angular.module('myApp', []);

app.controller('MySplash', ['$scope', '$location', '$q',
  function($scope, $location, $q) {

    $scope.waitForInit = $q.defer();

    $scope.waitForInit.promise.then(function() {
      console.log('Resolved.');
    });

    $scope.resolve = function () {
       $scope.waitForInit.resolve();
    }
  }
]);

HTML:

<body ng-controller="MySplash">
</body>

<script type="text/javascript">
  window.onload = function() {

    console.log('Loading.');
    window.setTimeout(function () {
      var controllerScope = angular.element(document.querySelector('body')).scope();
      controllerScope.resolve();
    }, 1000);
  }
</script>

答案 1 :(得分:1)

上面由tasseKATT给出的链接给出了外部交互的一般原则,特别是通过DOM查找角度入口点。

最后,我采用了向模块添加属性的方法,有效地使用模块作为暂存器在我的应用程序的各个部分之间进行通信。 (我猜比使用全局稍好一点。)

在我的控制器模块中:

angular.module('starter.controllers', [])


.controller('PetSplashCtrl', ['$scope', '$location', '$q', 
                         function($scope, $location, $q) {   

  var initDeferred = $q.defer();
  angular.module('starter.controllers').initDeferred = initDeferred;

  initDeferred.promise.then(function() {
      $location.path('/tab/pets');
  });

}]);

并在第三方回调中添加了

angular.module('starter.controllers').initDeferred.resolve();

angular和thirdPartyCode之间存在竞争条件,因此我需要检查角度是否准备就绪并且在调用resolve()之前设置了Promise:

function thirdPartyCallback(){

var initWaiter = function(){

    if ( typeof angular !== 'undefined' 
              && angular.module('starter.controllers') 
              && angular.module('starter.controllers').initDeferred
       ){
        angular.module('starter.controllers').initDeferred.resolve();
        console.log("init done");

    } else {
        console.log("init wait");
        setTimeout(initWaiter, 1000);
    }               
};

initWaiter();

}

我不确定通过DOM查找服务是否会比这更好。