【问题标题】:alternative to angular.element(document).ready替代 angular.element(document).ready
【发布时间】:2017-11-24 05:59:45
【问题描述】:

我注意到与此主题相关的大多数问题都与 jQuery $(document).ready Angular 函数的替代方案有关,即 angular.element($document).ready 但我想要一个可测试/最佳实践的替代方案。

我目前正在注入 Bing 地图,它需要在我的控制器中的代码执行之前加载。

目前我将控制器代码包装在准备好的文档中:

angular.element($document).ready(function() {
    self.map = new Microsoft.Maps.Map(document.getElementById('map'), {
        credentials: $scope.credentials,
        enableClickableLogo: false,
        enableSearchLogo: false,
        showDashboard: false,
        disableBirdseye: true,
        allowInfoboxOverflow: true,
        liteMode: true,
        minZoom: 2
    });

    $scope.$watch('zoom', function (zoom) {
        self.map.setView({animate: true, zoom: zoom});
    });

    if ($scope.onMapReady) {
        $scope.onMapReady({ map: self.map });
    }

});

哪个有效,但我无法对其进行测试,所以我认为这是不正确的用法。 我尝试在指令中设置一个变量 $scope.loaded = true;,因为我读到如果指令链接函数被命中,则必须加载 DOM。然后我尝试将准备好的文档替换为:

$scope.$watch('loaded', function () {
    self.map = new Microsoft.Maps.Map(document.getElementById('map'), {
       credentials: $scope.credentials,
       enableClickableLogo: false,
       enableSearchLogo: false,
       showDashboard: false,
       disableBirdseye: true,
       allowInfoboxOverflow: true,
       liteMode: true,
       minZoom: 2
    });

    if ($scope.onMapReady) {
        $scope.onMapReady({ map: self.map });
    }
});

$scope.$watch('zoom', function (zoom) {
    self.map.setView({animate: true, zoom: zoom});
});

“已加载”手表按预期工作,但自然会在加载时点击缩放,这就是在设置地图之前。我觉得我可以将准备好的文档更改为 $timeout 函数,但这似乎是一种解决方法,而不是正确的解决方案,是否有最佳实践替代 angular.element($document).ready 以相同的方式工作但允许我测试它内容成功?

【问题讨论】:

  • 这段代码的上下文是什么?通常 Angular 应用程序应该在文档准备好时被引导,所以这个包装器至少在控制器内部是无用的。
  • @estus bing 地图的调用方式如下:<script charset="UTF-8" type='text/javascript' src='https://www.bing.com/api/maps/mapcontrol'></script> 一旦加载,我们就可以访问上述 sn-p 中的Microsoft,这显然需要足够长的时间才能仅存在于文档中的控制器中准备好了
  • 请提供一种将问题复制为 fiddle/plunk 的方法,如果可能的话,不会暴露您的 API 密钥或其他东西。一般来说,答案是“你应该只用 angular.bootstrap 做一次准备”,所以这都是关于与特定脚本交互的。如果此 API 上有可以连接以确保其准备就绪的事件,请考虑使用它们。
  • @estus 我认为这几乎可以复制问题,但不完全是,但它显示了一张准备好文档的地图,而另一个则失败了。 plnkr.co/edit/j3aJ7OR2UD7eNyfagVOu?p=preview 我们的主应用程序按照您所说的 doc 就绪引导程序执行,但是我们只引导程序体,并且脚本调用存在于头脑中,这可能是个问题吗?
  • Plunker 今天不能正常工作,但我有机会检查一下。不,问题更复杂。初始 API 脚本会加载更多它们,并且在应用程序初始化时它们不会被加载/完成,即使这些脚本是在没有 async 属性的情况下加载的。我有类似的竞争条件here 并最终延迟应用程序初始化窗口load 事件。

标签: javascript angularjs timeout watch document-ready


【解决方案1】:

通常 Angular 应用程序已经在文档 ready 上启动。这是ng-app 自动引导的默认行为,angular.bootstrap 手动引导也应在ready 上执行。

这个问题是针对当前案例(Microsoft 的 Bing Maps API)的。考虑到ready is suggested by Microsoft,开发人员只能靠自己拥有更好的选择。

<script src="https://www.bing.com/api/maps/mapcontrol"></script>

是同步加载的,但它会触发一些依赖项来加载,这些依赖项在触发初始文档ready 时尚未加载。实际上,它需要ready在另一个ready中才能完成初始化,这正是原始代码和微软示例所显示的,看起来不太好。

为了避免竞争条件,应用程序引导可以推迟到加载所有先决条件的那一刻,即window load event instead of document ready。它可能会提供相当大的延迟,但它可以保证加载应用程序所依赖的脚本,而不管它们的传输是如何执行的:

angular.element(window).on('load', () => {
  angular.bootstrap(document.body, ['app']
});

API 提供的用于控制初始化过程的替代方案是global callback function

<script src="https://www.bing.com/api/maps/mapcontrol?callback=globalCallbackName"></script>

回调可以与服务打包,而不是依赖&lt;script&gt;

angular.module('bingMaps', [])
.factory('bingMapsLoader', ($q, $window, $document, $timeout) => {
  var script = document.createElement('script');
  script.src = 'https://www.bing.com/api/maps/mapcontrol?callback=bingMapsCallback';
  script.async = true;

  $document.find('body').append(script);

  return $q((resolve, reject) => {
    $window.bingMapsCallback = resolve;
    $timeout(reject, 30000);
  });
});

bingMapsLoaderpromise 可以被链接以保证 API 已初始化、放入路由器解析器等。

此外,控制器构造函数在编译指令之前执行。无论是否使用第三方 API,将所有特定于 DOM 的代码移动到 Angular 1.4 及更低版本中的 pre/post 链接函数以及 Angular 1.5 或更高版本中的控制器 $onInit$postLink 挂钩是正确的:

app.controller('FooController', function (bingMapsLoader) {
  this.$postLink = () => {
    bingMapsLoader.then(() => this.mapsInit());
  };

  this.mapsInit = () => {
    Microsoft.Maps.Map(...);
  };
  ...

【讨论】:

  • 我最后采取了一种稍微不同的方法,但主要原则是基于您的回答,将回调包装在服务中并使用 $window.callback。完全可测试且工作正常,感谢您的努力!
猜你喜欢
  • 2017-10-02
  • 2012-12-20
  • 1970-01-01
  • 2014-04-20
  • 1970-01-01
  • 2011-03-26
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
相关资源
最近更新 更多