替代 angular.element(document).ready
alternative to angular.element(document).ready
我注意到大多数与此主题相关的问题都与 angular 中 jQuery $(document).ready
函数的替代方法有关,但是 angular.element($document).ready
我想要一个 testable/best 替代练习。
我目前正在注入 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;
的指令中设置一个变量,因为我读到如果指令 link 函数被命中,则必须加载 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});
});
'loaded' 手表按预期工作,但自然会在加载时缩放,那是在设置地图之前。我觉得我可以将准备好的文档更改为 $timeout
函数,但这似乎是一种解决方法而不是正确的解决方案,是否有替代 angular.element($document).ready
的最佳实践以相同的方式工作但允许我成功地测试了它的内容?
一般来说 Angular 应用程序已经 bootstrap 在文档 ready
上执行。这是使用 ng-app
自动 bootstrapping 的默认行为,也应在 ready
上执行使用 angular.bootstrap
的手动 bootstrapping。
该问题特定于当前案例(Microsoft 的 Bing 地图 API)。考虑到 ready
is suggested by Microsoft,开发人员 his/her 有更好的选择。
<script src="https://www.bing.com/api/maps/mapcontrol"></script>
是同步加载的,但它会触发一些依赖项来加载,这些依赖项在触发初始文档 ready
时尚未加载。实际上,它需要在另一个ready
中包含ready
才能完成初始化,这正是原始代码和Microsoft示例所显示的,看起来不太好。
为了避免竞争条件应用程序 bootstrap 可以推迟到加载所有先决条件的那一刻,即 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>
回调可以与服务打包在一起,而不是依赖于 <script>
:
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);
});
});
bingMapsLoader
promise 可以被链接起来以保证 API 被初始化,放入路由器解析器等
此外,控制器构造函数在编译指令之前执行。无论是否使用第三方 APIs,将所有 DOM 特定代码移动到 Angular 1.4 及更低版本中的 pre/post link 函数是正确的和控制器 $onInit
或 $postLink
挂钩 Angular 1.5 或更高版本:
app.controller('FooController', function (bingMapsLoader) {
this.$postLink = () => {
bingMapsLoader.then(() => this.mapsInit());
};
this.mapsInit = () => {
Microsoft.Maps.Map(...);
};
...
我注意到大多数与此主题相关的问题都与 angular 中 jQuery $(document).ready
函数的替代方法有关,但是 angular.element($document).ready
我想要一个 testable/best 替代练习。
我目前正在注入 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;
的指令中设置一个变量,因为我读到如果指令 link 函数被命中,则必须加载 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});
});
'loaded' 手表按预期工作,但自然会在加载时缩放,那是在设置地图之前。我觉得我可以将准备好的文档更改为 $timeout
函数,但这似乎是一种解决方法而不是正确的解决方案,是否有替代 angular.element($document).ready
的最佳实践以相同的方式工作但允许我成功地测试了它的内容?
一般来说 Angular 应用程序已经 bootstrap 在文档 ready
上执行。这是使用 ng-app
自动 bootstrapping 的默认行为,也应在 ready
上执行使用 angular.bootstrap
的手动 bootstrapping。
该问题特定于当前案例(Microsoft 的 Bing 地图 API)。考虑到 ready
is suggested by Microsoft,开发人员 his/her 有更好的选择。
<script src="https://www.bing.com/api/maps/mapcontrol"></script>
是同步加载的,但它会触发一些依赖项来加载,这些依赖项在触发初始文档 ready
时尚未加载。实际上,它需要在另一个ready
中包含ready
才能完成初始化,这正是原始代码和Microsoft示例所显示的,看起来不太好。
为了避免竞争条件应用程序 bootstrap 可以推迟到加载所有先决条件的那一刻,即 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>
回调可以与服务打包在一起,而不是依赖于 <script>
:
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);
});
});
bingMapsLoader
promise 可以被链接起来以保证 API 被初始化,放入路由器解析器等
此外,控制器构造函数在编译指令之前执行。无论是否使用第三方 APIs,将所有 DOM 特定代码移动到 Angular 1.4 及更低版本中的 pre/post link 函数是正确的和控制器 $onInit
或 $postLink
挂钩 Angular 1.5 或更高版本:
app.controller('FooController', function (bingMapsLoader) {
this.$postLink = () => {
bingMapsLoader.then(() => this.mapsInit());
};
this.mapsInit = () => {
Microsoft.Maps.Map(...);
};
...