我正在使用ui路由器,并试图实例化一个小部件,该小部件将id指定的DOM元素作为参数。这个DOM元素在<div ng-switch>
中,我想在元素保证存在时调用小部件构造函数。
<div ng-switch on="state">
<div ng-switch-when="map">
<div id="map"></div>
</div>
</div>
从ui路由器的生命周期来看,我明白我应该挂接$viewContentLoaded
。然而,这不起作用——ng-switch
中的DOM元素当时还没有创建:
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('/', {url: '/', templateUrl: 'index.html'})
.state('map', {url: 'map', templateUrl: 'map.html', controller: 'MapCtrl'})
}]);
app.controller('MapCtrl', ['$rootScope', '$scope', '$state', function MapCtrl($rootScope, $scope, $state) {
$scope.state = $state.current.name; // expose the state to the template so we can ng-switch. Apparently there's no better way: https://github.com/angular-ui/ui-router/issues/1482
$scope.$on('$viewContentLoaded', function mapContentLoaded(event, viewConfig) {
var mapElement = document.getElementById('map');
console.log('Attempting to create map into', mapElement);
var map = new google.maps.Map(mapElement); // <-- but mapElement will be null!
});
}]);
实际工作是在控制器中使用50ms的setTimeout()
,这很脆弱,但到那时DOM元素已经创建。或者,我可以设置一个间隔,检查map
DOM元素的存在,并在找到它时清除该间隔。
判断ng-switch
何时呈现其DOM的正确方法是什么?这没有记录在案。
这是Plunkr。
我认为您陷入了许多有经验的前端开发人员在使用Angular时所陷入的陷阱。在大多数其他JS库中,我们在创建DOM后对其进行修改,然后向其添加功能。然而,在Angular中,功能是在HTML中定义的。功能性和交互性是通过使用指令创建的。
在jQuery中这样的东西很好:
<div id="foobar">
Click here to do stuff
</div>
<script type="text/javascript">
$(function () {
$('#foobar').on('click', function () {
someService.doStuff();
});
});
</script>
而Angular中的更为惯用:
<div id="foobar" ng-controller="Main" ng-click="doStuff()">
Click here to do stuff
</div>
<script type="text/javascript">
app.controller('Main', ['$scope', 'somerService', function ($scope, someService) {
$scope.doStuff = function () {
someService.doStuff();
}
}]);
</script>
至于你的谷歌地图指令,这是迄今为止最简单的方法来实现它。尽管这是非常基本的,可能不会做到你需要的一切。
app.directive('googleMap', [function() {
return {
link: function(element) {
new google.maps.Map(element);
}
}
}
]);
您的map.html
:
<div ng-switch on="state">
<div ng-switch-when="map">
<div google-map id="map"></div>
</div>
</div>
然而,正如您所提到的,每当控制器被击中时,这将重新创建谷歌地图。解决方法之一是保存元素和Mapapi,并在随后的调用中替换它:
app.directive('googleMap', [function () {
var googleMapElement,
googleMapAPI;
return {
link: function (element) {
if (!googleMapElement || !googleMapAPI) {
googleMapAPI = new google.maps.Map(element);
googleMapElement = element;
}
else {
element.replaceWith(googleMapElement);
}
}
}
}]);