2014-10-27 50 views
1

我正在使用ui-router并尝试实例化一个窗口小部件,该窗口小部件将参数指定为由id指定的DOM元素。这个DOM元素在<div ng-switch>中,当元素保证存在时,我想调用构造函数。当ng-switch完成渲染时?

<div ng-switch on="state"> 
    <div ng-switch-when="map"> 
    <div id="map"></div> 
    </div> 
</div> 

ui-router lifecycle,我知道我应该挂接到$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! 
    }); 
}]); 

什么工作是在控制器,它是易碎使用50毫秒的setTimeout(),但由DOM元素创建的时间。或者,我可以设置一个时间间隔,检查DOM元素是否存在,并在发现时清除时间间隔。

什么是正确ng-switch何时已经呈现其DOM?这isn't documented

这是Plunkr

+0

你混合隐喻/使用DOM方法和角度方法一起使用,不与角度很好地工作领域。使用指令或模板来操作mapElement而不是dom方法。 – dandavis 2014-10-27 00:48:34

+0

你打算如何处理'mapElement'?不管它是什么,@ dandavis都是正确的,你通常只想在指令中进行DOM操作。 – 2014-10-27 00:56:33

+0

@EstebanFelix:我想实例化一个Google Map。刚刚更新了这个问题。我应该怎么做呢?使用ui路由器状态而不是ng-switch? – 2014-10-27 01:04:36

回答

1

我认为你正陷入许多有经验的前端开发人员在使用Angular时遇到的陷阱。在大多数其他JS库中,我们在创建DOM之后修改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> 

在角类似下面是更地道:

<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> 

至于你的GoogleMap的指令,这是目前为止最简单的方法来完成它。虽然这是非常基本的,可能不会做你需要的一切。

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> 

但正如你所说,这将重新创建谷歌每一个控制器被击中一次地图。周围的一种方法是保存这个元素和地图API和替换它在后续调用:

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); 
      } 

     } 
    } 
}]); 
+0

谢谢你的答案!要阅读[jQuery的 - >角](http://stackoverflow.com/questions/14994391/how-do-i-think-in-angularjs-if-i-have-a-jquery-background)所以再一次。每次路由器登陆该页面时,是否会使用指令导致地图重新创建?这是我想要避免的。 – 2014-10-27 01:43:42

+0

如果我在写这个回复之前说我没有读过,我会是个骗子。如果你已经做了很长时间的jQuery,那你肯定需要重新学习一下。不幸的是,每次激活开关时都会重新创建它。 – 2014-10-27 04:20:23

+0

我运行'new google.maps.Map(..)后,通过将'mapDomElement = document.getElementById('map')''存入'map.domElements''.value',似乎避免了重新创建。 ),然后运行'mapDomElement.parentNode.replaceChild(map.domElements,mapDomElement);'如果设置了该值,而不是调用Google Maps构造函数。 – 2014-10-27 04:32:08

相关问题