2014-10-27 51 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

相關問題